Share via


C# Console App - Can't retrieve SOAP 1.2 response from Web Service

Question

Wednesday, August 22, 2018 7:53 PM

I am unable to hit a SOAP 1.2 web service with C# code, inside a console app. It does not work for me. My web service URL works in SOAPUI but I can't get a response in my C# code. I get a "500 Internal error." The status reads "ProtocolError." I am running this from my Visual Studio 2017 editor. What am I doing wrong?

using System;
using System.IO;
using System.Net;
using System.Xml;

namespace testBillMatrixConsole
{
    class Program
    {
        static void Main(string[] args)
        {
                string _url = @"https://service1.com/MSAPaymentService/MSAPaymentService.asmx";
                var _action = @"http://schemas.service1.com/v20060103/msapaymentservice/AuthorizePayment";
            try
            {
                XmlDocument soapEnvelopeXml = CreateSoapEnvelope();
                HttpWebRequest webRequest = CreateWebRequest(_url, _action);
                InsertSoapEnvelopeIntoWebRequest(soapEnvelopeXml, webRequest);

                // begin async call to web request.
                IAsyncResult asyncResult = webRequest.BeginGetResponse(null, null);

                // suspend this thread until call is complete. You might want to
                // do something usefull here like update your UI.
                asyncResult.AsyncWaitHandle.WaitOne();

                // get the response from the completed web request.
                string soapResult;
                using (WebResponse webResponse = webRequest.EndGetResponse(asyncResult))
                {
                    using (StreamReader rd = new StreamReader(webResponse.GetResponseStream()))
                    {
                        soapResult = rd.ReadToEnd();
                    }
                    Console.Write(soapResult);
                }



            }
            catch (WebException ex)
                {

                throw;//ex.Message.ToString();

            }

        }

        private static XmlDocument CreateSoapEnvelope()
        {
            XmlDocument soapEnvelopeDocument = new XmlDocument();
            soapEnvelopeDocument.LoadXml(@"<soap:Envelope xmlns:soap=""http://www.w3.org/2003/05/soap-envelope"" xmlns:msap=""http://schemas.service1.com/v20060103/msapaymentservice""><soap:Body><msap:AuthorizePayment><!--Optional:--><msap:clientPaymentId>?</msap:clientPaymentId><msap:amount>?</msap:amount><msap:method>?</msap:method><!--Optional:--><msap:parameters><!--Zero or more repetitions:--><msap:PaymentParameter><!--Optional:--><msap:Name>?</msap:Name><!--Optional:--><msap:Value>?</msap:Value></msap:PaymentParameter></msap:parameters></msap:AuthorizePayment></soap:Body></soap:Envelope>");
            return soapEnvelopeDocument;
        }

        private static HttpWebRequest CreateWebRequest(string url, string action)
        {
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
            webRequest.Headers.Add("SOAPAction", action);
            webRequest.ContentType = "application/soap+xml;charset=\"utf-8\"";
            webRequest.Accept = "text/xml";
            webRequest.Method = "POST";
            return webRequest;
        }

        private static void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml, HttpWebRequest webRequest)
        {
            using (Stream stream = webRequest.GetRequestStream())
            {
                soapEnvelopeXml.Save(stream);
            }
        }
    }
}

All replies (12)

Wednesday, August 22, 2018 8:37 PM

This Web service you wrote? If so, then the HTTP 500 error means that an unhandled .Net exception was thrown. You don't have any exception handling in the Web service so the Web server swallowed the exception and through the HTTP 500 error.

The protocol error could just be superficial just like the HTTP 500 is superficial in this situation. 

You need to implement some global exception handling logic in the service and log the exception so you can see it.

Another tool you can use is PostMon that may allow you to see the exception that caused the HTTP 500. 

Web services can be addressed at the below link.

 https://forums.asp.net/28.aspx/1?WCF+ASMX+and+other+Web+Services


Wednesday, August 22, 2018 9:21 PM

Thanks for your fast reply. I did not write the service that I am trying to call. It is actually a 3rd party vendor. Obviously, the URL in my post is not real, but the rest of the code is. I was hoping someone could tell me what is wrong with my code, because I can hit the web service URL with a SOAPUI call and get a response. I carefully created the same soap envelope that I saw in the SOAPUI call, but I still get nothing back.  Any ideas?


Thursday, August 23, 2018 12:00 AM

I did not write the service that I am trying to call. It is actually a 3rd party vendor.

The 3rd party vendor is who you should be making contact with on how to consume the service. 


Thursday, August 23, 2018 2:12 AM

SOAP request content type should be "application/soap+xml". Fix that and try again.


Thursday, August 23, 2018 1:25 PM

SOAP request content type should be "application/soap+xml". Fix that and try again.

I changed that and got the same result.


Thursday, August 23, 2018 1:59 PM

Personally I would recommend that you add a service reference in your code to do this. Calling a SOAP service is generally quite a bit harder than just writing some XML to the network. For example if this is a WCF service (which it doesn't appear to be because of the asmx) then you have to generate the WS-A information otherwise the call will fail. SOAP 1.x also supports MustUnderstand which you must generate if used by the service. The body and data must be properly namespace prefixed. The list goes on and on.

The service reference that VS can auto-generate will allow you to use a regular .NET class to call the service and it'll handle the serialization/deserialization behind the scenes. Is this an option for you?

Michael Taylor http://www.michaeltaylorp3.net


Thursday, August 23, 2018 3:44 PM

Personally I would recommend that you add a service reference in your code to do this. Calling a SOAP service is generally quite a bit harder than just writing some XML to the network. For example if this is a WCF service (which it doesn't appear to be because of the asmx) then you have to generate the WS-A information otherwise the call will fail. SOAP 1.x also supports MustUnderstand which you must generate if used by the service. The body and data must be properly namespace prefixed. The list goes on and on.

The service reference that VS can auto-generate will allow you to use a regular .NET class to call the service and it'll handle the serialization/deserialization behind the scenes. Is this an option for you?

Michael Taylor http://www.michaeltaylorp3.net

All options are open to me. Since I am new to this, would you be able to point me to a site that has a tutorial I could follow on how to do what you are suggesting?


Thursday, August 23, 2018 3:54 PM

Here's the basic link to the documentation. Note that it is referring to WCF which will have a WSDL endpoint. If the service you are calling has a WSDL endpoint then you can do that. 

If not then go to the Advanced option and you'll see an option to add a Web Reference. You'll have to use that option instead.

Michael Taylor http://www.michaeltaylorp3.net


Friday, August 24, 2018 12:27 PM

Here's the basic link to the documentation. Note that it is referring to WCF which will have a WSDL endpoint. If the service you are calling has a WSDL endpoint then you can do that. 

If not then go to the Advanced option and you'll see an option to add a Web Reference. You'll have to use that option instead.

Michael Taylor http://www.michaeltaylorp3.net

I tried your suggestion and added the wsdl as a service client. I tried it and got the same error, “Invalid Request”:

Server stack trace:

   at System.ServiceModel.Channels.ServiceChannel.HandleReply(ProxyOperationRuntime operation, ProxyRpc& rpc)

   at System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)

   at System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)

   at System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)

Exception rethrown at [0]:

   at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)

   at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)

   at testBillMatrixConsole.testServiceReference2.MSAPaymentServiceSoap.AuthorizePayment(AuthorizePaymentRequest request)

   at testBillMatrixConsole.testServiceReference2.MSAPaymentServiceSoapClient.testBillMatrixConsole.testServiceReference2.MSAPaymentServiceSoap.AuthorizePayment(AuthorizePaymentRequest request) in C:\Users\caldwelj\source\repos\testBillMatrixConsole\Connected Services\testServiceReference2\Reference.cs:line 1110

   at testBillMatrixConsole.testServiceReference2.MSAPaymentServiceSoapClient.AuthorizePayment(String clientPaymentId, Decimal amount, PaymentMethod method, PaymentParameter[] parameters) in C:\Users\caldwelj\source\repos\testBillMatrixConsole\Connected Services\testServiceReference2\Reference.cs:line 1120

   at testBillMatrixConsole.Program.Main(String[] args) in C:\Users\caldwelj\source\repos\testBillMatrixConsole\Program.cs:line 70

The code at the line number sin the error:

[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]

        testBillMatrixConsole.ServiceReference1.AuthorizePaymentResponse testBillMatrixConsole.ServiceReference1.MSAPaymentServiceSoap.AuthorizePayment(testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequest request) {

            return base.Channel.AuthorizePayment(request);

        }

       

        public testBillMatrixConsole.ServiceReference1.AuthorizationResponse AuthorizePayment(string clientPaymentId, decimal amount, testBillMatrixConsole.ServiceReference1.PaymentMethod method, testBillMatrixConsole.ServiceReference1.PaymentParameter[] parameters) {

            testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequest inValue = new testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequest();

            inValue.Body = new testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequestBody();

            inValue.Body.clientPaymentId = clientPaymentId;

            inValue.Body.amount = amount;

            inValue.Body.method = method;

            inValue.Body.parameters = parameters;

            testBillMatrixConsole.ServiceReference1.AuthorizePaymentResponse retVal = ((testBillMatrixConsole.ServiceReference1.MSAPaymentServiceSoap)(this)).AuthorizePayment(inValue);

            return retVal.Body.AuthorizePaymentResult;

        }

     

I tried the definition that ended at line 1110 in the references.cs.

[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]

        testBillMatrixConsole.ServiceReference1.AuthorizePaymentResponse testBillMatrixConsole.ServiceReference1.MSAPaymentServiceSoap.AuthorizePayment(testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequest request) {

            return base.Channel.AuthorizePayment(request);

        }

The code that uses it:

                MSAPaymentServiceSoap _sp = new MSAPaymentServiceSoapClient();

                PaymentParameter[] _pp = new PaymentParameter[10];

                _pp[0] = new PaymentParameter();

                _pp[0].Name = "PayAccount";

                _pp[0].Value = "5292341000000327";

                _pp[1] = new PaymentParameter();

                _pp[1].Name = "UserInterfaceType";

                _pp[1].Value = "CWA";

                _pp[2] = new PaymentParameter();

                _pp[2].Name = "PayAccountExpiration";

                _pp[2].Value = "092018";

                _pp[3] = new PaymentParameter();

                _pp[3].Name = "UserAccount";

                _pp[3].Value = "ACCJ1476J";

                _pp[4] = new PaymentParameter();

                _pp[4].Name = "UserZipCode";

                _pp[4].Value = "12345";

                _pp[5] = new PaymentParameter();

                _pp[5].Name = "ClientData1";

                _pp[5].Value = "06";

                _pp[6] = new PaymentParameter();

                _pp[6].Name = "ClientData2";

                _pp[6].Value = "abcd";

                _pp[7] = new PaymentParameter();

                _pp[7].Name = "ClientData3";

                _pp[7].Value = "ACCJ1476J";

                _pp[8] = new PaymentParameter();

                _pp[8].Name = "ClientData4";

                _pp[8].Value = "abcdst";

                _pp[9] = new PaymentParameter();

                _pp[9].Name = "ClientData5";

                _pp[9].Value = "abc123";

                AuthorizePaymentRequest _ar = new AuthorizePaymentRequest();

                _ar.Body = new AuthorizePaymentRequestBody();

                _ar.Body.amount = 32.11m;

                _ar.Body.clientPaymentId = @"1232314e4f9f7fc7:76f0e3fd:1551140314b:-b75";

                _ar.Body.parameters = _pp;

                _sp.AuthorizePayment(_ar); //throws error “Invalid Request”

I also tried definition at line 1120 in the References.cs. I got the same error message:

        public testBillMatrixConsole.ServiceReference1.AuthorizationResponse AuthorizePayment(string clientPaymentId, decimal amount, testBillMatrixConsole.ServiceReference1.PaymentMethod method, testBillMatrixConsole.ServiceReference1.PaymentParameter[] parameters) {

            testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequest inValue = new testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequest();

            inValue.Body = new testBillMatrixConsole.ServiceReference1.AuthorizePaymentRequestBody();

            inValue.Body.clientPaymentId = clientPaymentId;

            inValue.Body.amount = amount;

            inValue.Body.method = method;

            inValue.Body.parameters = parameters;

            testBillMatrixConsole.ServiceReference1.AuthorizePaymentResponse retVal = ((testBillMatrixConsole.ServiceReference1.MSAPaymentServiceSoap)(this)).AuthorizePayment(inValue);

            return retVal.Body.AuthorizePaymentResult;

        }

The code I created for this one:

                MSAPaymentServiceSoapClient _spc = new MSAPaymentServiceSoapClient();

               

                PaymentParameter[] _pp = new PaymentParameter[10];

                _pp[0] = new PaymentParameter();

                _pp[0].Name = "PayAccount";

                _pp[0].Value = "5292341000000327";

                _pp[1] = new PaymentParameter();

                _pp[1].Name = "UserInterfaceType";

                _pp[1].Value = "CWA";

                _pp[2] = new PaymentParameter();

                _pp[2].Name = "PayAccountExpiration";

                _pp[2].Value = "092018";

                _pp[3] = new PaymentParameter();

                _pp[3].Name = "UserAccount";

                _pp[3].Value = "ACCJ1476J";

                _pp[4] = new PaymentParameter();

                _pp[4].Name = "UserZipCode";

                _pp[4].Value = "12345";

                _pp[5] = new PaymentParameter();

                _pp[5].Name = "ClientData1";

                _pp[5].Value = "06";

                _pp[6] = new PaymentParameter();

                _pp[6].Name = "ClientData2";

                _pp[6].Value = "abcd";

                _pp[7] = new PaymentParameter();

                _pp[7].Name = "ClientData3";

                _pp[7].Value = "ACCJ1476J";

                _pp[8] = new PaymentParameter();

                _pp[8].Name = "ClientData4";

                _pp[8].Value = "abcdst";

                _pp[9] = new PaymentParameter();

                _pp[9].Name = "ClientData5";

                _pp[9].Value = "abc123";

                _spc.AuthorizePayment(@"1232314e4f9f7fc7:76f0e3fd:1551140314b:-b75", 32.11m, PaymentMethod.MasterCard, _pp); //throws error

Here is my App.Config:

<?xml version="1.0" encoding="utf-8" ?>

<configuration>

    <configSections>

    </configSections>

    <startup>

        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />

    </startup>

    <system.serviceModel>

        <bindings>

            <basicHttpBinding>

                <binding name="MSAPaymentServiceSoap">

                    <security mode="Transport" />

                </binding>

                <binding name="MSAPaymentServiceSoap1" />

                <binding name="MSAPaymentServiceSoap2">

                    <security mode="Transport" />

                </binding>

                <binding name="MSAPaymentServiceSoap3" />

            </basicHttpBinding>

        </bindings>

        <client>

            <endpoint address="https://servicemsagroup.billmatrix.com/MSAPaymentService/MSAPaymentService.asmx"

                binding="basicHttpBinding" bindingConfiguration="MSAPaymentServiceSoap"

                contract="ServiceReference1.MSAPaymentServiceSoap" name="MSAPaymentServiceSoap" />

            <endpoint address="https://servicemsagroup.billmatrix.com/MSAPaymentService/MSAPaymentService.asmx"

                binding="basicHttpBinding" bindingConfiguration="MSAPaymentServiceSoap2"

                contract="testServiceReference2.MSAPaymentServiceSoap" name="MSAPaymentServiceSoap1" />

        </client>

    </system.serviceModel>

</configuration>


Friday, August 24, 2018 1:00 PM

How many days have you been at  this with no success? And yet I'll bet you have not contacted the 3rd party vendor.  hmm....


Friday, August 24, 2018 1:55 PM

How many days have you been at  this with no success? And yet I'll bet you have not contacted the 3rd party vendor.  hmm....

For your information, I did contact the vendor and they told me that providing me with the WSDL was all they were obligated to do and that was all the help they would give me. 

I will look elsewhere for help.


Friday, August 24, 2018 2:00 PM

Given the original protocol error I'm thinking it is related to SOAP 1.2 or perhaps SSL. What version of .NET are you using? Are you sure the WSDL is actually returning SOAP 1.2?

BasicHttpBinding is going to default to SOAP 1.1 (or at least it did). In order to use SOAP 1.2 (at least on older frameworks) a custom binding is needed. So try defining this custom binding and then using it instead of basicHttpBinding.

<customBinding>
  <binding name="customHttpBinding">
    <textMessageEncoding messageVersion="Soap12" />
    <httpTransport/>
  </binding>
</customBinding>

Using Fiddler to watch the call will also allow you to compare what you're sending against what SoapUI sends. Since SoapUI is working that means it is most likely a serialization issue in WCF.

Michael Taylor http://www.michaeltaylorp3.net