function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
JesipJesip 

Using Session ID with the .NET Provider for sForce

I have been using the sForce Provider for .NET for several integrations with great success.  Kudos to the developers who did a fantastic job.

I am having a problem with one particular integration in which I want to pass the session id passed from SFDC and reuse it to create a connection within my asp page.  When I do this using the sForce api, it is as simple as setting the sessionheadervalue of the sForceService equal to the SessionID.  Can anyone tell me how I can do the same thing with the provider?

(The reason I need to do this rather than hard-coding a user and password is that the ASPX page is going to create objects within SFDC that I would like the user to own)

Thanks.

DevAngelDevAngel

Hi Jesip,

Well, you need to modify the sforceConnection class so that it will accept a connection string like "session id=baBxhvfYhis7Qx1;server url=https://na1-api.salesforce.com/services/Soap/u/5.0".

To do this you modify the property setter for ConnectionString to include:

If m_htbConnParms.ContainsKey("session id") Then

m_svcSforce.SessionHeaderValue = New Sforce.SessionHeader

m_svcSforce.SessionHeaderValue.sessionId = m_htbConnParms("session id").ToString

SessionID = m_htbConnParms("session id").ToString

m_authAuthType = AUTHENTICATION_TYPE.SESSIONID

End If

If m_htbConnParms.ContainsKey("server url") Then

m_svcSforce.Url = m_htbConnParms("server url").ToString

URL = m_htbConnParms("server url").ToString

m_authAuthType = AUTHENTICATION_TYPE.SESSIONID

End If

Create an Enum called AUTHENTICATION_TYPE with 2 values SESSIONID and USERNAME.

Then, in the Open method, modify the login part like below:

With m_svcSforce

m_enmConnState = ConnectionState.Connecting

If m_authAuthType = AUTHENTICATION_TYPE.USERNAME Then

Dim objLR As Sforce.LoginResult = .login(m_strUsername, m_strPassword)

m_enmConnState = ConnectionState.Open

.SessionHeaderValue = New Sforce.SessionHeader

.SessionHeaderValue.sessionId = objLR.sessionId

.Url = objLR.serverUrl

m_strUserId = objLR.userId

Else

m_enmConnState = ConnectionState.Open

m_strUserId = m_svcSforce.getUserInfo().userId

End If

If m_intQueryBatchSize > 0 Then

.QueryOptionsValue = New Sforce.QueryOptions

.QueryOptionsValue.batchSize = m_intQueryBatchSize

.QueryOptionsValue.batchSizeSpecified = True

End If

End With

This should allow you to specify a connection string that uses the session id and server url rather than the username and password.

Cheers

JesipJesip
Thanks a lot for the reply!  This modification will make me the provider that much more valuable!
JesipJesip
For anyone else attempting to benefit from this post, it is also worth mentioning that you need to pass the Partner API URL from SFDC (NOT the Enterprise) as the sForceProvider uses the Partner WSDL.  Making this mistake will generate an XML document error when you try and use your connection.
David-David-

This is another approach that doesn't require modifying the SforceConnection class.  This assumes you have two panels (panelLogin and panelRequestForm). The SessionId and URL properties are stored in ViewState via Literal controls.


private SforceConnection conn;


private void Page_Load(object sender, System.EventArgs e)
{
 if(!IsPostBack)
 {
  panelLogin.Visible = true;
 }
 else
 {
  // Handle login if login form visible; else, handle form submit
  if(panelLogin.Visible)
  {
   string connString = "User ID=" + txtUsername.Text.Trim() + ";Password=" + txtPassword.Text.Trim();
   conn = new SforceConnection(connString);
   conn.URL = litSFDCEndpoint.Text;


   try
   {
    conn.Open();


    litSessionId.Text = conn.SessionID;
    litSFDCEndpoint.Text = conn.URL;


    panelLogin.Visible = false;
    panelRequestForm.Visible = true;
   }
   catch(Exception err)
   {
    lblMessage.Text = "Error: " + err.Message + "<br><br>";
   }
  }
  else
  {
   conn = new SforceConnection();
   conn.SessionID = litSessionId.Text;
   conn.URL = litSFDCEndpoint.Text;


   try
   {
    // Process form (insert, update, etc)
   }
   catch(Exception err)
   {
    lblMessage.Text = "Error: " + err.Message + "<br><br>";
   }
  }
 }
}

David-David-
I looked back at my reply from 5 months ago, and I see the point of the original post was to auth via session only (not username/pwd).  Oops.  :-)
 
I'm trying out Dave's idea now...see how it goes.
David-David-

I took Dave's suggestion and modified ConnectionString() and Open() with a few minor alterations.  Also added the enum and a couple of member vars.  VB.NET 1.1 code posted below. 

Code:

    Private m_authType As AuthenticationType
    Private m_strSessionId As String
    Private m_strUrl As String

    Private Enum AuthenticationType
        SessionId
        Username
    End Enum

    Public Property ConnectionString() As String Implements System.Data.IDbConnection.ConnectionString
        Get
            Return m_strConnection
        End Get
        Set(ByVal Value As String)
            'parse
            m_strConnection = Value
            m_htbConnParms = ParseConnectionString(Value)

            ' I'm resetting the sessionid parameter because I found the '=' symbol at the end of the SessionId got parsed out in ParseConnectionString().
            ' One could modify that accordingly to prevent this; I was lazy and hardcoded it here for test purposes.
            m_htbConnParms("sessionid") = "qrKAqvXXOOvnVBptJ0UdrmQVLCitqQdkifCrjoL_2cDbTxOkOEHQ.bSobBGwX66rDxpsMAr0i9BTm_rlx9Z86WpYnKO9AsNCSeX5jsUoLXQ="

            ' Username and Password-Style Authentication (note keys are lower case)
            If m_htbConnParms.ContainsKey("user id") And m_htbConnParms.ContainsKey("password") Then
                m_strUsername = m_htbConnParms("user id").ToString
                m_strPassword = m_htbConnParms("password").ToString
                m_authType = AuthenticationType.Username
            End If

            ' SessionId and Server URL Authentication (note keys are lower case)
            If m_htbConnParms.ContainsKey("sessionid") And m_htbConnParms.ContainsKey("serverurl") Then
                m_strSessionId = m_htbConnParms("sessionid").ToString
                m_strUrl = m_htbConnParms("serverurl").ToString
                m_authType = AuthenticationType.SessionId
            End If

            If m_htbConnParms.ContainsKey("querybatchsize") Then
                m_intQueryBatchSize = Convert.ToInt32(m_htbConnParms("querybatchsize"))
            End If

            If m_htbConnParms.ContainsKey("retrievechunksize") Then
                m_intRetrieveChunkSize = Convert.ToInt32(m_htbConnParms("retrievechunksize"))
            End If

            If m_htbConnParms.ContainsKey("sendcompressedrequest") Then
                m_svcSforce.SendCompressedRequest = Boolean.Parse(m_htbConnParms("sendcompressedrequest").ToString)
            End If

            If m_htbConnParms.ContainsKey("acceptcompressedresponse") Then
                m_svcSforce.AcceptCompressedResponse = Boolean.Parse(m_htbConnParms("acceptcompressedresponse").ToString)
            End If

            If m_htbConnParms.ContainsKey("commandtimeout") Then
                Me.CommandTimeout = Convert.ToInt32(m_htbConnParms("commandtimeout"))
            End If
        End Set
    End Property

    Public Sub Open() Implements System.Data.IDbConnection.Open
        Try
            With m_svcSforce
                If m_enmConnState = ConnectionState.Closed Then
                    With m_svcSforce
                        m_enmConnState = ConnectionState.Connecting

                        ' Instantiate SessionHeader
                        .SessionHeaderValue = New Sforce.SessionHeader

                        ' Authenticate via Username/Pwd or SessionId/Url
                        If m_authType = AuthenticationType.Username Then
                            Dim objLR As Sforce.LoginResult = .login(m_strUsername, m_strPassword)

                            .SessionHeaderValue.sessionId = objLR.sessionId
                            .Url = objLR.serverUrl

                            m_strUserId = objLR.userId
                        ElseIf m_authType = AuthenticationType.SessionId Then
                            .SessionHeaderValue.sessionId = m_strSessionId
                            .Url = m_strUrl

                            m_strUserId = m_svcSforce.getUserInfo().userId
                        End If

                        ' Query Options
                        If m_intQueryBatchSize > 0 Then
                            .QueryOptionsValue = New Sforce.QueryOptions
                            .QueryOptionsValue.batchSize = m_intQueryBatchSize
                            .QueryOptionsValue.batchSizeSpecified = True
                        End If

                        ' Set ConnectionState to Open
                        m_enmConnState = ConnectionState.Open
                    End With
                Else
                    Throw New InvalidOperationException("Connection already open.  State: " & m_enmConnState.ToString)
                End If
            End With
        Catch ex As Exception
            m_enmConnState = ConnectionState.Closed
            Throw ex
        End Try
    End Sub


 
Along the way, however, I found that one could easily enable the existing SforceConnection object (i.e., no modifications necessary to ADO.NET provider) to assume a new SessionHeader.  This is done by first logging in "traditionally" with a username and password (ideally, an API designated account), then resetting the SforceConnection's SessionHeader value to one that uses the SessionId passed in via weblink.  Note that I didn't need to change the Url property, but that could be accomplished by passing the API Url via weblink, as well. 

This approach is posted below in a C# 2.0 sample method below called UpdateAccount().

Code:

using Salesforce.SforceClient;
using Salesforce.SforceClient.Sforce;

    private void UpdateAccount(string accountId, string newValue)
    {
        // Open SFDC Connection using an API Account
        SforceConnection conn = new SforceConnection("User ID=api@yourorg.com;Password=xxxxxxx");
        conn.Open();

        // Set the SessionHeader to the session of the user that clicked the weblink
        conn.SforceService.SessionHeaderValue = new SessionHeader();
        conn.SforceService.SessionHeaderValue.sessionId = Request.QueryString["SFDCSessionId"];

        // This update will occur in the authentication context of the user that clicked the weblink
        SforceCommand cmd = new SforceCommand("UPDATE Account SET SomeField__c = @SomeField__c WHERE Id = @Id", conn);
        cmd.Parameters["@Id"].Value = accountId;
        cmd.Parameters["@SomeField__c"].Value = newValue;

        int result = cmd.ExecuteNonQuery();
    }


 

DevAngelDevAngel

Glad to see you get it working!

 

:smileywink: