goenning / SharpSapRfc

Making SAP RFC calls even easier with .NET
MIT License
84 stars 27 forks source link

Define DestinationConfiguration in Appconfig without username and password #35

Closed jensweller closed 8 years ago

jensweller commented 8 years ago

Hi. Is it possible to add the DestinationConfiguration in App.config without username and passwort. Set the username and password in code.

goenning commented 8 years ago

Does this issue help you https://github.com/goenning/SharpSapRfc/issues/33?

jensweller commented 8 years ago

Hi. I already found this issue. But I think that solves my proplem not quite. In this example everything is in code. Its perfect to define all connections in appconfig. But without username and password.

goenning commented 8 years ago

If you're doing that to hide the credentials, I actually recommend you to encrypt your configuration file. How to safely store configuration settings in web.config.

For any other reason, you can actually mix both. In the following example, it'll take default parameters from *.config and the rest from code.

<SAP.Middleware.Connector>
  <ClientSettings>
    <DestinationConfiguration>
      <destinations>
        <add NAME="MY_CONFIG_PARAMS" CLIENT="001" LANG="EN" ASHOST="sap-vm" SYSNR="00" />
      </destinations>
    </DestinationConfiguration>
  </ClientSettings>
</SAP.Middleware.Connector>
public class Program
{
    public class CustomDestinationConfig : IDestinationConfiguration
    {
        private RfcConfigParameters parameters;
        public CustomDestinationConfig(RfcConfigParameters defaultParameters)
        {
            this.parameters = defaultParameters;
        }

        public bool ChangeEventsSupported()
        {
            return false;
        }

        public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;

        public RfcConfigParameters GetParameters(string destinationName)
        {
            if (destinationName == "MY_CODE_PARAMS")
            {
                this.parameters[RfcConfigParameters.User] = "user";
                this.parameters[RfcConfigParameters.Password] = "p$ss";
                return parameters;
            }
            else
                throw new ArgumentOutOfRangeException(destinationName);
        }
    }

    public static void Main(string[] args)
    {
        RfcDestination destination = RfcDestinationManager.GetDestination("MY_CONFIG_PARAMS");
        RfcDestinationManager.RegisterDestinationConfiguration(new CustomDestinationConfig(destination.Parameters));
        using (SapRfcConnection conn = new PlainSapRfcConnection("MY_CODE_PARAMS"))
        {
            var result = conn.ExecuteFunction("Z_SSRT_SUM",
                new RfcParameter("i_num1", 2),
                new RfcParameter("i_num2", 4)
            );

            var total = result.GetOutput<int>("e_result");
        }
    }
}
jensweller commented 8 years ago

The problem ist I have more than one connection in the app.config. And I want to set different username and password for the connections. The username should not be saved.

If I call RfcDestinationManager.RegisterDestinationConfiguration(new CustomDestinationConfig(destination.Parameters));

I override all destinations in appconfig.

It should be possible to just add new parameters to the existing destinations in appconfig.

goenning commented 8 years ago

There is no standard way to do that with SharpSapRfc, but you still can workaround it by using the code above, even if you have multiple destinations.

You'll need to call RfcDestinationManager.GetDestination for each of your destinations and store it in an array. Instead of passing a single destination to CustomDestinationConfigs constructor, you'll have to pass the array and store it in a private field. CustomDestinationConfig .GetParameters should now add additional parameters for each destination that was previously read from app.config.

jensweller commented 8 years ago

Yes this is a option. But it is not possible to iterate all existing destinations in code. So I have to know all connections in code. I need to add connections to appconfig without compile my application again.

At runtime the user has just to insert the username and password for this connection.

goenning commented 8 years ago

That's correct, we can't iterate through all destinations, but as it's a XML file, we can read it with XmlDocument and XPath.

var doc = new XmlDocument();
doc.Load("path/to/your/config");

Dictionary<string, RfcConfigParameters> destinations = new Dictionary<string, RfcConfigParameters>();
var nodes = doc.SelectNodes("//configuration/SAP.Middleware.Connector/ClientSettings/DestinationConfiguration/destinations/add");
foreach(XmlNode node in nodes)
{
    string name = node.Attributes["NAME"].Value;
    RfcConfigParameters parameters = RfcDestinationManager.GetDestination(name).Parameters;
    destinations.Add(name, parameters);
}

RfcDestinationManager.RegisterDestinationConfiguration(new CustomDestinationConfig(destinations));

If anyone want to add this feature into SharpSapRfc, I'd be happy to get a PR.

Cheers.

jensweller commented 8 years ago

Hm. I think thats not the best solution to read the xml document again.

jensweller commented 8 years ago

I think I found a better solution. Instead of define SAP.Middleware.Connector Destinations I define my own destinations in Appconfig. In code I read this destinations store it in my own list and register them in SAP.Middleware.Connector. So I have fully access to this parameters and can also change them at runtime.