Consuming WCF Soap Service running on Mono from An

2019-07-01 19:36发布

问题:

I am working on a Android/C# project. What I need to be able to do is have a WCF soap service which can either run on Windows or Linux (Mono).

It's working fine on Windows and I can access the WCF Service on Mono from the WCF Test Client provided in Visual Studio and it works fine but when accessing android using KSOAP2 I get the error HTTP Request Failed, HTTP status: 415

Below is how the soap service is started

string methodInfo = classDetails + MethodInfo.GetCurrentMethod().Name;
            try
            {
                if (Environment.GetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT") != "yes")
                {
                    Environment.SetEnvironmentVariable("MONO_STRICT_MS_COMPLIANT", "yes");
                }
                if (String.IsNullOrEmpty(soapServerUrl))
                {
                    string message = "Not starting Soap Server: URL or Port number is not set in config file";
                    library.logging(methodInfo, message);
                    library.setAlarm(message, CommonTasks.AlarmStatus.Medium, methodInfo);
                    return;
                }
                Console.WriteLine("Soap Server URL: {0}", soapServerUrl);
                baseAddress = new Uri(soapServerUrl);
                host = new ServiceHost(soapHandlerType, baseAddress);
                BasicHttpBinding basicHttpBinding = new BasicHttpBinding();

                //basicHttpBinding.Namespace = "http://tempuri.org/";



                var meta = new ServiceMetadataBehavior()
                {
                    HttpGetEnabled = true,
                    HttpGetUrl = new Uri("", UriKind.Relative),
                    //HttpGetBinding = basicHttpBinding,
                };
                //meta.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;

                host.Description.Behaviors.Add(meta);

                host.AddServiceEndpoint(soapManagerInterface, basicHttpBinding, soapServerUrl);
                host.AddServiceEndpoint(typeof(IMetadataExchange), MetadataExchangeBindings.CreateMexHttpBinding(), "mex");

                var debugBehaviour = new ServiceDebugBehavior()
                {
                    HttpHelpPageEnabled = true,
                    HttpHelpPageUrl = new Uri("", UriKind.Relative),
                    IncludeExceptionDetailInFaults = true,
                    //HttpHelpPageBinding = basicHttpBinding,
                };

                host.Description.Behaviors.Remove(typeof(ServiceDebugBehavior));
                host.Description.Behaviors.Add(debugBehaviour);
                host.Opened += new EventHandler(host_Opened);
                host.Faulted += new EventHandler(host_Faulted);
                host.Closed += new EventHandler(host_Closed);
                host.UnknownMessageReceived += new EventHandler<UnknownMessageReceivedEventArgs>(host_UnknownMessageReceived);
                host.Open();
            }

The soapServerURL is http://192.168.1.74:8000/CritiMon.

Below is how I am trying to call the soap service from android using KSOAP2.

final String soapAction = "http://tempuri.org/ISoapInterface/testSoapFunction";
        final String namespace = "http://tempuri.org/";
        final String methodName = "testSoapFunction";
        final String url = "http://192.168.1.74:8000/CritiMon?wsdl";
        String resultData = "";

        new Thread(new Runnable() {

            @Override
            public void run() {
                SoapSerializationEnvelope envelope = null;
                try
                {
                //String resultData = "";

                    SoapObject request = new SoapObject(namespace, methodName);
                    //request.addProperty("firstName", "Chris");
                    //request.addProperty("lastName", "Board");
                    envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
                    envelope.dotNet = true;
                    envelope.setOutputSoapObject(request);

                    HttpTransportSE http = new HttpTransportSE(url);

                    http.call(soapAction, envelope);
                    SoapPrimitive result = (SoapPrimitive)envelope.getResponse();

                    String resultData = result.toString();
                    Log.d("Soap Result", resultData);

                }
                catch (Exception ex)
                {
                    Log.e("Soap Error 2", ex.getMessage());
}

I have no idea what I can do to make this work on Mono with Android.

回答1:

Firstly, you want to catch the actual SOAP request on the wire. You can do this using Fiddler or SoapUI - they both act as proxies through which local requests are passed, allowing you to inspect the actual XML request for anomalies. You might discover something obvious by doing this, or you can at least update your question with more information.

Following that, and without any further information, I can only offer a memorable experience with talking to WCF services from non-.NET applications:

WCF specifies the XML request that it expects, but it actually requires object properties to be in a specific order. This can be a declared order in the datacontract, or it can be an implicit alphabetical order. Either way, if you don't provide object properties in the specified order you will be stung and things won't work.