none
.NET C# console application calling SAP webService RRS feed

  • Question

  • Intention:
    My intent is to call a SAP webService with a C#.Net client (console application).
    I would like to use basic authentication with username and password.

    I'm able to call and use the provided SAP webServices with soapUI, so I guess there is no problem with the webService itself.

    After reviewing a ton of other posts I'm a bit confused about the right URI URL from SAP to use. 
    So I went to SOAMANAGER, selected my service definition, selected the tab "Overview", klicked onto the link "Show / hide selected Binding's or Services's WSDL URL" and copied the URL which showed up right next to the link. This looks like the following:

    http://<IP:PORT>/sap/bc/srt/wsdl/srvc_51F72577B69615C0E10080000A0F87DB/wsdl11/allinone/ws_policy/document?sap-client=<CLIENTNUMBER>

    What I did so far (within VS2012):

    1. created a new console application
    2. right click onto the project / Add Service Reference...
    3. I added the URL as found above (entered my SAP user credentials)
    4. I kept the Name: "ServiceReference1" and hit OK
    var binding = new BasicHttpBinding();
    binding.MaxReceivedMessageSize = int.MaxValue;
    binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
    binding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
    var address = new EndpointAddress("http://<IP:PORT>/sap/bc/srt/wsdl/srvc_51F72577B69615C0E10080000A0F87DB/wsdl11/allinone/ws_policy/document?sap-client=<CLIENT>");
    
    //create client
    ServiceReference1._WUV_TESTFMClient client = new ServiceReference1._WUV_TESTFMClient(binding, address);
    
    //define credentials
    client.ClientCredentials.UserName.UserName = "<USER>";
    client.ClientCredentials.UserName.Password = "<PW>";
    
    //open client
    client.Open();
    
    //define importing parameter
    ServiceReference1._WUV_TESTFM01Tst parameter = new ServiceReference1._WUV_TESTFM01Tst();
    parameter.IWmeng = 34;
    
    //create response
    ServiceReference1._WUV_TESTFM01TstResponse response = client._WUV_TESTFM01Tst(parameter);
    
    //consume webservice
    Console.WriteLine(response.EWmeng);
    
    //close client
    client.Close();

    However when I start debugging the program it fails on line:

    //create response
    ServiceReference1._WUV_TESTFM01TstResponse response = client._WUV_TESTFM01Tst(parameter);
    System.ServiceModel.CommunicationException was unhandled
      HResult=-2146233087
      Message=Unbekannte Nachrichtenversion.
      Source=mscorlib
      StackTrace:
        Server stack trace: 
           bei System.ServiceModel.Channels.ReceivedMessage.ReadStartEnvelope(XmlDictionaryReader reader)
           bei System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData messageData, RecycledMessageState recycledMessageState, Boolean[] understoodHeaders, Boolean understoodHeadersModified)
           bei System.ServiceModel.Channels.BufferedMessage..ctor(IBufferedMessageData messageData, RecycledMessageState recycledMessageState)
           bei System.ServiceModel.Channels.TextMessageEncoderFactory.TextMessageEncoder.ReadMessage(ArraySegment`1 buffer, BufferManager bufferManager, String contentType)
           bei System.ServiceModel.Channels.HttpInput.DecodeBufferedMessage(ArraySegment`1 buffer, Stream inputStream)
           bei System.ServiceModel.Channels.HttpInput.ReadBufferedMessage(Stream inputStream)
           bei System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(HttpRequestMessage httpRequestMessage, Exception& requestException)
           bei System.ServiceModel.Channels.HttpInput.ParseIncomingMessage(Exception& requestException)
           bei System.ServiceModel.Channels.HttpChannelFactory`1.HttpRequestChannel.HttpChannelRequest.WaitForReply(TimeSpan timeout)
           bei System.ServiceModel.Channels.RequestChannel.Request(Message message, TimeSpan timeout)
           bei System.ServiceModel.Dispatcher.RequestChannelBinder.Request(Message message, TimeSpan timeout)
           bei System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
           bei System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
           bei System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
           bei System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)
        Exception rethrown at [0]: 
           bei System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
           bei System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
           bei Consume05.ServiceReference1._WUE_CPSG._wue_cpsg01Tst(_wue_cpsg01TstRequest request)
           bei Consume05.ServiceReference1._WUE_CPSGClient.Consume05.ServiceReference1._WUE_CPSG._wue_cpsg01Tst(_wue_cpsg01TstRequest request) in d:\srcTrials\ConsumeSAPWebServiceViaServiceReference\Consume01\Consume05\Service References\ServiceReference1\Reference.cs:Zeile 158.
           bei Consume05.ServiceReference1._WUE_CPSGClient._wue_cpsg01Tst(_wue_cpsg01Tst _wue_cpsg01Tst1) in d:\srcTrials\ConsumeSAPWebServiceViaServiceReference\Consume01\Consume05\Service References\ServiceReference1\Reference.cs:Zeile 164.
           bei Consume05.Program.Main(String[] args) in d:\srcTrials\ConsumeSAPWebServiceViaServiceReference\Consume01\Consume05\Program.cs:Zeile 36.
           bei System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
           bei System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
           bei Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
           bei System.Threading.ThreadHelper.ThreadStart_Context(Object state)
           bei System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
           bei System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
           bei System.Threading.ThreadHelper.ThreadStart()
      InnerException: 
    

    I really have no idea what else I could do and appreciate any help.

    Thanks in advance!
    best,
    Markus

    Thursday, August 8, 2013 1:41 PM

Answers

  • Hi Markus,

    So the SAP webservice is using plain HTTP transport and demand a HTTP basic authentication credentials, correct?

    If so, I think the binding configuration and client credentials supplying code you provided looks ok (see below article for reference).

    #Wcf TransportCredentialOnly mode: Basic clear text credentials over unsecured transport
    http://developers.de/blogs/damir_dobric/archive/2006/07/31/890.aspx

    For the exception encountered, I'd suggest you try using some HTTP debugging tools like fiddler to inspect the HTTP request and response messages so as to get the raw error info from the server-side.

    In addition, since you've got the service call successful by using soapUI, you can can try capturing the request/response pairs of soapUI based client and compare them with the WCF client generated ones to see what's the main difference on the underlying HTTP SOAP layer.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, August 9, 2013 1:52 AM
    Moderator
  • Thanks for your reply。

    According to the raw HTTP error info you provided, it seems the SAP service require an intermediate proxy authentication (before the request reach the target webservice server). You can confirmed with the service side about if it does demand a proxy authentication for the client-side. Or is the server-side authentication only demanded by the intermediate proxy server rather than the actual webservice server?

    For WCF service client (or WebRequest based client), we can use WebRequest.DefaultWebProxy property to assign a custom WebProxy instance with authentication credentials specified. Here is a blog entry I've ever written on this:

    #[WCF]How to supply dedicated credentials for webproxy authentication in WCF client
    http://blogs.msdn.com/b/stcheng/archive/2008/12/03/wcf-how-to-supply-dedicated-credentials-for-webproxy-authentication.aspx


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 13, 2013 3:45 PM
    Moderator

All replies

  • Hi Markus,

    So the SAP webservice is using plain HTTP transport and demand a HTTP basic authentication credentials, correct?

    If so, I think the binding configuration and client credentials supplying code you provided looks ok (see below article for reference).

    #Wcf TransportCredentialOnly mode: Basic clear text credentials over unsecured transport
    http://developers.de/blogs/damir_dobric/archive/2006/07/31/890.aspx

    For the exception encountered, I'd suggest you try using some HTTP debugging tools like fiddler to inspect the HTTP request and response messages so as to get the raw error info from the server-side.

    In addition, since you've got the service call successful by using soapUI, you can can try capturing the request/response pairs of soapUI based client and compare them with the WCF client generated ones to see what's the main difference on the underlying HTTP SOAP layer.


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, August 9, 2013 1:52 AM
    Moderator
  • Hi Steven,

    thank you for your hint. 

    This is correct I'm using plain HTTP with "Transport Channel Authentication" / "User ID/Password"

    Finally, when I switched to the web view in Fiddler I could see a SAP web page which returns me a HTTP 401 - Unauthorized error.

    In the Auth-tab is the following message:

    No Proxy-Authenticate Header is present.
    
    WWW-Authenticate Header is present: Basic realm="SAP NetWeaver Application Server [<SAPSystemName>/<client>]"
    

    In the Raw-tab is the following message:

    HTTP/1.0 401 Unauthorized Date: Tue, 13 Aug 2013 14:29:48 GMT Set-Cookie: sap-usercontext=sap-client=<client>; path=/ Content-Type: text/html; charset=utf-8 Content-Length: 2254 sap-system: <SAPSystemName> WWW-Authenticate: Basic realm="SAP NetWeaver Application Server [<SAPSystemNo>/<client>]" Server: SAP NetWeaver Application Server / ABAP 731 X-Cache: MISS from <proxy>.com X-Cache-Lookup: MISS from <proxy>.com:<port> Via: 1.0 <proxy>.com (squid/3.1.10) Proxy-Connection: keep-alive

    <html><head><title>Logon Error Message</...

    I did check the user credentials and they work from within Chrome, IE and SAP itself. I wonder if I have to pass the user credentials in a different way?
    Tuesday, August 13, 2013 2:54 PM
  • Thanks for your reply。

    According to the raw HTTP error info you provided, it seems the SAP service require an intermediate proxy authentication (before the request reach the target webservice server). You can confirmed with the service side about if it does demand a proxy authentication for the client-side. Or is the server-side authentication only demanded by the intermediate proxy server rather than the actual webservice server?

    For WCF service client (or WebRequest based client), we can use WebRequest.DefaultWebProxy property to assign a custom WebProxy instance with authentication credentials specified. Here is a blog entry I've ever written on this:

    #[WCF]How to supply dedicated credentials for webproxy authentication in WCF client
    http://blogs.msdn.com/b/stcheng/archive/2008/12/03/wcf-how-to-supply-dedicated-credentials-for-webproxy-authentication.aspx


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Tuesday, August 13, 2013 3:45 PM
    Moderator
  • Hi Steven,

    Thank you very much for your help. It all works now!

    Thanks again,
    Markus

    Where to find the correct binding address:

    In my example above I was also using the wrong binding address. If you have access to the SAP the following steps will guide you to the location where to find the binding address.

    1. Within SAP execute transaction SOAMANAGER
    2. Go to "Web Service Configuration"
    3. Look up for your service definition
    4. Select "Configurations"
    5. Go to transport settings
    6. finally place the "Calculated Address URL" behind "http://<SAPServerAddress/sap"
    • Proposed as answer by Sergio Parra Tuesday, March 15, 2016 11:42 AM
    Thursday, August 15, 2013 7:16 AM
  • Cool! Thanks for sharing this.

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, August 15, 2013 7:21 AM
    Moderator
  • Hello, I have been beating my head against the wall trying to figure this out.  I would really appreciate another set of eyes.

    1. Created brand new C# console app framework 4
    2. Add web reference to my new SAP service

    The app.config is:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <configSections>
            <sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" >
                <section name="SAPTest.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
            </sectionGroup>
        </configSections>
        <applicationSettings>
            <SAPTest.Properties.Settings>
                <setting name="SAPTest_mysapserver_zss_myactions"
                    serializeAs="String">
                    <value>http://mysapserver/bc/srt/rfc/sap/myactions/010/zss_myactions/myactions</value>
                </setting>
            </SAPTest.Properties.Settings>
        </applicationSettings>
    </configuration>


    1. The net result is that when I look at this in Fiddler, I get a 401 error.  I clearly security that the basic authorization header is not being passed. 

    The code I call is:

    System.Net.NetworkCredential cred = new System.Net.NetworkCredential();
    
     SAPTest.mySapServer.mysap_Actions _proxy1 = new SAPTest.mySapServer.mysap_Actions();
    
     SAPTest.mySapServer.mysap_Actions1 inputData = new SAPTest.mySapServer.mysap_Actions1();
    
    SAPTest.mySapServer.mysap_ActionsResponse outPutData = new SAPTest.mySapServer.mysap_ActionsResponse();
    
     cred.UserName = "user";
     cred.Password = "pw";
    
     _proxy1.PreAuthenticate = true;
     _proxy1.Credentials = cred;
     outPutData = proxy1.Callmysap_Actions(inputData);
    1. The net result is that when I call this in the C# console app I see in Fiddler that I get a 401 error and that there is no basic security header.
    2. I have reviewed the above threads and I do not have access to to modify the header in the proxy class.  
    3. Is there something that I can add to app.config to force basic auth?  Right now nothing is being sent over.
    4. Any other suggestions would be appreciated.

    Cheers!

    Tuesday, June 14, 2016 5:35 PM