cancel
Showing results for 
Search instead for 
Did you mean: 

How to change SAP RegisterDestinationConfiguration assigned parameter values on runtime

Former Member
0 Kudos

<b>Requirement:</b><br>

The requirement is to make a transaction through a BAPI

using the username and password

of the user everytime, who calls a BAPI function,

so that the transactions are logged by the user, not by the

test/development username. This user activity/transaction

will differ from other user.

<b>Details:</b><br>

a) We're using .NET connector (to call BAPIs) in a webservice call.

<br>

    i)  sapnco.dll (ver: 3.0.0.42)<br>

    ii) sapnco_utils.dll (ver: 3.0.0.42)<br>

b) The username & password will be sent as arguments in a web-method.

<b>Approach:</b><br>

Our approach was to make new registration (RegisterDestinationConfiguration)

everytime we call the BAPI function.

But this approach is not recommended by senior members

(like Markus Tolksdorf & Hynek Petrak) on the SCN forum.

They say to register once.

We followed an example mentioned in the link below, but it doesn't work

(the comment with the 'AddOrEditDestination' example):

http://scn.sap.com/thread/3674375

We'll need to un-Register the previous 'registration'

(using the exact username and password as was used during its registration),

to then register a new one. To do this we will need to keep a record

(in a separate table) of the users

who have called the BAPI.

But we will need to check for concurrency of the resource.

i.e. Handle issue when two users register at the same time.

<b>Q: Is there a simpler way and/or better than the one mentioned above?</B>

- - - - - - - - - - - - - - - - - -

Here's the code, we use:

- - - - - - - - - - - - - - - - - -

    [WebMethod]

        public bool authenticateUser(string un, string pw)

        {

            bool result = false;

            InMemoryDestinationConfiguration objDestConfig = new InMemoryDestinationConfiguration();

                try

                {

                    #region "Register/Unregister Destination Configuration"

                    if (!(RfcDestinationManager.IsDestinationConfigurationRegistered()))

                        RfcDestinationManager.RegisterDestinationConfiguration(objDestConfig);

                    objDestConfig.AddOrEditDestination("mySAP", 15, un, pw, "EN", "50", "100.170.14.59", "03", "DEVELOPER");

                    #endregion

                    RfcDestination dest = RfcDestinationManager.GetDestination("mySAPdestination");

                    dest.Ping();

                    objDestConfig.RemoveDestination("mySAP");

                    result = true;

                }

                catch (Exception ex)

                {

     // log Error using user made function

                    logError(ex.ToString(), "authenticateUser()");

                }

            return result;

        }

    /* - - - - - - - - - - - - - - */

    /* AddOrEditDestination Code: */

    /* - - - - - - - - - - - - - */

    public class InMemoryDestinationConfiguration : IDestinationConfiguration

    {

        Dictionary<string, RfcConfigParameters> availableDestinations;

        RfcDestinationManager.ConfigurationChangeHandler changeHandler;

        public InMemoryDestinationConfiguration()

        {

            availableDestinations = new Dictionary<string, RfcConfigParameters>();

        }

        public RfcConfigParameters GetParameters(string destinationName)

        {

            RfcConfigParameters foundDestination;

            availableDestinations.TryGetValue(destinationName, out foundDestination);

            return foundDestination;

        }

        //our configuration supports events

        public bool ChangeEventsSupported()

        {

            return true;

        }

        public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged

        {

            add

            {

                changeHandler = value;

            }

            remove

            {

                //do nothing

            }

        }

        //removes the destination that is known under the given name

        public void RemoveDestination(string name)

        {

            if (name != null && availableDestinations.Remove(name))

            {

                //Console.WriteLine("Successfully removed destination " + name);

                //Console.WriteLine("Fire deletion event for destination " + name);

                changeHandler(name, new RfcConfigurationEventArgs(RfcConfigParameters.EventType.DELETED));

            }

        }

        //allows adding or modifying a destination for a specific application server

        public void AddOrEditDestination(string name, int poolSize,

            string user, string password, string language, string client,

            string applicationServer, string systemNumber, string systemID)

        {

            //in productive code the given parameters should be checked for validity, e.g. that name is not null

            //as this is not relevant for the example, we omit it here

            RfcConfigParameters parameters = new RfcConfigParameters();

            parameters[RfcConfigParameters.Name] = name;

            //parameters[RfcConfigParameters.MaxPoolSize] = Convert.ToString(poolSize);

            //parameters[RfcConfigParameters.IdleTimeout] = Convert.ToString(1); // we keep connections for 10 minutes

            parameters[RfcConfigParameters.User] = user;

            parameters[RfcConfigParameters.Password] = password;

            parameters[RfcConfigParameters.Client] = client;

            parameters[RfcConfigParameters.Language] = language;

            parameters[RfcConfigParameters.AppServerHost] = applicationServer;

            parameters[RfcConfigParameters.SystemNumber] = systemNumber;

            parameters[RfcConfigParameters.SystemID] = systemNumber;

            RfcConfigParameters existingConfiguration;

            //if a destination of that name existed before, we need to fire a change event

            if (availableDestinations.TryGetValue(name, out existingConfiguration))

            {

                availableDestinations[name] = parameters;

                RfcConfigurationEventArgs eventArgs = new RfcConfigurationEventArgs(RfcConfigParameters.EventType.CHANGED, parameters);

                //MessageBox.Show("Fire change event " + eventArgs.ToString() + " for destination " + name);

                changeHandler(name, eventArgs);

            }

            else

            {

                availableDestinations[name] = parameters;

            }

            //MessageBox.Show("Added application server destination " + name);

        }

    }

Accepted Solutions (1)

Accepted Solutions (1)

MarkusTolksdorf
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Fahad,

that what you like to achieve can easily be done using a RfcCustomDestination that you create from the configured destination pointing to the target system. On the RfcCustomDestination you can adjust user/password on the fly without having to unregister/register the IDestinationConfiguration all the time. As you write it yourself, this pattern is bad and should not be done - in particular it will not work at all in multi-threaded environments.

Best regards,

Markus

hynek_petrak
Active Participant
0 Kudos

Hi Markus,

can you compare performance wise the approach of using GetDestination(RfcConfigParameters) and RfcCustomDestination ?

MarkusTolksdorf
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Hynek,

without having made perfromance comparisons between the two approaches, from gut feeling I would say that the difference is pretty small and is in favor of GetDestination(RfcConfigParameters) - but not really noticeable. Furthermore CustomDestinations can be used always, GetDestination(RfcConfigParameters) only if no IDestinationConfiguration is registered with NCo's RfcDestinationManager.

Best regards,

Markus

hynek_petrak
Active Participant
0 Kudos

Hi Marcus,

thanks for the hint. How is it with sharing of meta data repository between parent destination and child CustomDestination(s)?

Are they shared when CustomDestination differs from parent just by user credentials?

Or is it required to use a separate common account for the metadata in order to share metadata?

In Fahad's use case, I can imagine, the meta data cache can gain on performance.

BR, Hynek

MarkusTolksdorf
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Hynek,

CustomDestinations share the repository of their parent, i.e. metadata lookups in the backend are not necessary again, when using CustomeDestinations originating from one and the same Destination.

Best regards,

Markus

Former Member
0 Kudos

Thanks Markus,
Your suggestion worked.

Also thank you Hynek Petrak. I have gone through different question on this website, and both you guys help a lot with different questions.
I hope you guys keep continuing to help others.
I wish you all the best for your future.


I am including the sample code I used in my implementation.

  1:  public bool pingWithSAPUserLogon(string un, string pw)
  2:          {
  3:      bool result = false;
  4:          try                
  5:          {
  6:              if (!(RfcDestinationManager.IsDestinationConfigurationRegistered()))                    
  7:              {
  8:              RfcDestinationManager.RegisterDestinationConfiguration(new SAPConfig());
  9:              }
  10:          RfcDestination destFinal = null;
  11:          RfcDestination destTest = RfcDestinationManager.GetDestination("mySAPdestination");
  12:                  
  13:          RfcCustomDestination destCust = destTest.CreateCustomDestination();
  14:          destCust.User = un; 
  15:          destCust.Password = pw;
  16:                  
  17:          destFinal = destCust;
  18:   
  19:          destFinal.Ping();
  20:          result = true;
  21:          }
  22:          catch (Exception ex)
  23:          {
  24:          // Log Exception                
  25:          }
  26:      
  27:      return result;
  28:  }
  29:   
  30:   
  31:   
  32:  public class SAPConfig : IDestinationConfiguration
  33:      {
  34:          private string SAP_username = "";
  35:          private string SAP_password = "";
  36:          public SAPConfig()
  37:          {
  38:   
  39:          }
  40:          public bool ChangeEventsSupported()
  41:          {
  42:              return false;
  43:          }
  44:   
  45:          public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;
  46:   
  47:          public RfcConfigParameters GetParameters(string destinationName)
  48:          {
  49:              RfcConfigParameters parms = new RfcConfigParameters();
  50:   
  51:              if (destinationName.Equals("mySAPdestination"))
  52:              {
  53:                  parms.Add(RfcConfigParameters.AppServerHost, "10.10.10.10");
  54:                  parms.Add(RfcConfigParameters.SystemNumber, "01");
  55:                  parms.Add(RfcConfigParameters.SystemID, "ABC");
  56:                  parms.Add(RfcConfigParameters.Client, "150");
  57:                  parms.Add(RfcConfigParameters.Language, "EN");
  58:                  parms.Add(RfcConfigParameters.PoolSize, "10");
  59:              }
  60:              return parms;
  61:          }
  62:      }
hynek_petrak
Active Participant
0 Kudos

Hi Fahad,

I'd suggest one more thing. Remove:

if (!(RfcDestinationManager.IsDestinationConfigurationRegistered()))                   

{

  RfcDestinationManager.RegisterDestinationConfiguration(new SAPConfig());

}

and put this to the Global.asax on application startup event:

RfcDestinationManager.RegisterDestinationConfiguration(new SAPConfig());


You register once at startup of the application and for the rest of the life time you assume it is registered.

Former Member
0 Kudos
I'm pasting the code again, because SCN.SAP's code formatting is crap.
Also SCN.SAP's rule to lock a reply (i.e. stop someone from editing once a reply to that original reply is made) is horrible.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
public bool pingWithSAPUserLogon(string un, string pw)
        {
     bool result = false;
          try                
          {
               if (!(RfcDestinationManager.IsDestinationConfigurationRegistered()))                    
               {
               RfcDestinationManager.RegisterDestinationConfiguration(new SAPConfig());
               }
          RfcDestination destFinal = null;
          RfcDestination destTest = RfcDestinationManager.GetDestination("mySAPdestination");
                
          RfcCustomDestination destCust = destTest.CreateCustomDestination();
          destCust.User = un; 
          destCust.Password = pw;
                
          destFinal = destCust;

          destFinal.Ping();
          result = true;
          }
          catch (Exception ex)
          {
          // Log Exception                          }
     
     return result;
}



public class SAPConfig : IDestinationConfiguration
    {
        private string SAP_username = "";
        private string SAP_password = "";
        public SAPConfig()
        {

        }
        public bool ChangeEventsSupported()
        {
            return false;
        }

        public event RfcDestinationManager.ConfigurationChangeHandler ConfigurationChanged;

        public RfcConfigParameters GetParameters(string destinationName)
        {
            RfcConfigParameters parms = new RfcConfigParameters();

            if (destinationName.Equals("mySAPdestination"))
            {
                parms.Add(RfcConfigParameters.AppServerHost, "10.10.10.10");
                parms.Add(RfcConfigParameters.SystemNumber, "01");
                parms.Add(RfcConfigParameters.SystemID, "ABC");
                parms.Add(RfcConfigParameters.Client, "150");
                parms.Add(RfcConfigParameters.Language, "EN");
                parms.Add(RfcConfigParameters.PoolSize, "10");
            }
            return parms;
        }
    }
Former Member
0 Kudos

Thanks Hynek. I'll do that.

Answers (1)

Answers (1)

hynek_petrak
Active Participant
0 Kudos

From the manual:

RfcDestinationManager.GetDestination(RfcConfigParameters)

This API provides the possibility for applications to directly pass their logon parameters at runtime. The parameters have to provide logon information for the SAP system to which to connect. The RfcDestinationManager uses that information to retrieve or create a destination

Demonstrated for instance here:

Former Member
0 Kudos

Thank you for replying to my question.

I implemented the 'on-the-fly' example you suggested.
It worked once or twice, then it started giving this error:


"SAP.Middleware.Connector.RfcInvalidStateException: Hard-coded logon parameters not allowed when using a DestinationConfiguration

  at SAP.Middleware.Connector.RfcDestinationManager.GetDestination(RfcConfigParameters parameters)"

Here's the code I implemented:

I'm reading all log-on data (except username and password) from a (web.config) file.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
public bool pingWithSAPUserLogon(string un, string pw)
        {
            bool result = false;
                try                {
                    RfcConfigParameters configParams =
                        new RfcConfigParameters(
                            clsGetParameters.GetParameters(
                            Credentials.SAP_DESTINATION_NAME,Credentials.SAP_POOL_SIZE,
                            un,pw,Credentials.SAP_LANGUAGE,Credentials.SAP_CLIENT,
                            Credentials.SAP_APP_SERVER_HOST,Credentials.SAP_SYSTEM_NUMBER,
                            Credentials.SAP_SYSTEM_ID));


                    RfcDestination dest = RfcDestinationManager.GetDestination(configParams);
                    dest.Ping();
                    result = true;
                }
                catch (Exception ex)
                {
                    // Log Exception                }
            return result;
        }




public static class Credentials        {
            //static string _SAP_APP_SERVER_HOST;            //static string _SAP_SYSTEM_NUMBER;            //static string _SAP_SYSTEM_ID;            //static string _SAP_CLIENT;            //static string _SAP_LANGUAGE;            //static string _SAP_POOL_SIZE;            //static string _SAP_DESTINATION_NAME            
            public static string SAP_DESTINATION_NAME
            {
                get { return ReadSetting("SAP_DESTINATION_NAME"); }
                //set { _SAP_DESTINATION_NAME = value; }            }


            public static string SAP_APP_SERVER_HOST
            {
                get { return ReadSetting("SAP_APP_SERVER_HOST"); }
                //set { _SAP_APP_SERVER_HOST = value; }            }


            public static string SAP_SYSTEM_NUMBER
            {
                get { return ReadSetting("SAP_SYSTEM_NUMBER"); }
                //set { _SAP_SYSTEM_NUMBER = value; }            }


            public static string SAP_SYSTEM_ID
            {
                get { return ReadSetting("SAP_SYSTEM_ID"); }
                //set { _SAP_SYSTEM_ID = value; }            }


            public static string SAP_CLIENT
            {
                get { return ReadSetting("SAP_CLIENT"); }
                //set { _SAP_CLIENT = value; }            }


            public static string SAP_LANGUAGE
            {
                get { return ReadSetting("SAP_LANGUAGE"); }
                //set { _SAP_LANGUAGE = value; }            }


            public static int SAP_POOL_SIZE
            {
                get                {
                    int result = 0;
                    try                    {
                        result = Int32.Parse(ReadSetting("SAP_POOL_SIZE"));
                    }
                    catch (Exception ex) 
                    {
                         // Log Exception                     }
                    return result;
                }
                //set { _SAP_POOL_SIZE = value; }            }


public static string ReadSetting(string key)
            {
                string result = "";
                try                {
                    var appSettings = ConfigurationManager.AppSettings;
                    result = appSettings[key];

                }
                catch (Exception)
                {
                         // Log Exception                }
                return result;
            }
MarkusTolksdorf
Product and Topic Expert
Product and Topic Expert
0 Kudos

Hi Fahad,

GetDestination(RfcConfigParameters) cannot be used when registering a IDestinationConfiguration with RfcDestinationManager. When using the latter, all destinations need to originate from the IDestinationConfigruation storage. GetDestination(RfcConfigParameters) should only be used in small applications and only if using app.config or an own IDestinationConfigruation doesn't seem to make sense in a certain use case. But in most cases this will work and ensures that the destination storage could be exchnaged easily for an application if needed.

Best regards,

Markus