4
votes

I am trying to call a WCF service method from an .NET Core Web API using the new Visual Studio WCF Connected service.

But when I am testing this, I get the following error:-

The content type multipart/related; type="application/xop+xml"; start="http://tempuri.org/0"; boundary="uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a+id=1197"; start-info="text/xml" of the response message does not match the content type of the binding (text/xml; charset=utf-8). If using a custom encoder, be sure that the IsContentTypeSupported method is implemented properly. The first 1024 bytes of the response were: ' --uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a+id=1197 Content-ID: http://tempuri.org/0 Content-Transfer-Encoding: 8bit Content-Type: application/xop+xml;charset=utf-8;type="text/xml"

The exposed WCF service uses MTOM MessageEncoding and in traditional .NET framework client application, we can set the client to use MTOM in the application's config file but in .NET core, we don't have the config file where we can set the MessageEncoding and all this configuration is taken care of in the code present in Reference.cs(which is a generated file). I thinking changing this generated file to set the MessageEncoding is not a good option.

Any idea on what is the best way to handle this issue?

4
I fixed the problem by installing latest version of visual studio 2017. by installing latest version of visual studio it will automatically update your net core to the latest verion (1.1.2).Houtan
Thanks for answering. In my case the WCF service at the other end uses MTOM for which there is no support in .NET core clients yet.Nirmal Thakur

4 Answers

7
votes

I just came to know from WCF Core team that currently MTOM encoding is not supported in .NET Core based clients. This is a requested feature which will be available in future versions. Here is github link which has more information: Adding MTOM support in WCF runtime

6
votes

I was facing the same MTOM consumtion issue in my project, and had to find a way to be able to consume the service. It ended up in some (ugly) code, but functional.

I just wanted to share the solution (as I wasn't able to find anything on the web) :

  • To start, generate the Client with Visual Studio (2017 in my case) by adding a connected service (as you would do for a regular SOAP client). This will help you save lot a dummy code typing ;)

  • then, use RestSharp to call the endpoint, and serialize manually the response/request :

        var client = new RestClient("http://myService/Service");
        var request = new RestRequest(Method.POST);
        request.AddHeader("accept", "text/plain");
        request.AddHeader("content-type", "text/xml");
    
        // create parameter
        var serializer = new XmlSerializer(typeof(myParameter));
    
        var requestParameter = new myParameter(1,2,3,4);
    
        string requestParameterStr;
    
        var namepsaces = new XmlSerializerNamespaces(new[] { XmlQualifiedName.Empty });
        var settings = new XmlWriterSettings { Indent = true, OmitXmlDeclaration = true, NamespaceHandling = NamespaceHandling.OmitDuplicates }; // some parameters to make it clean, only OmitXmlDeclaration is mandatory 
        using (var stringWriter = new StringWriter())
        {
            using (var xmlWriter = XmlWriter.Create(stringWriter, settings))
            {
                serializer.Serialize(xmlWriter, requestParameter, namepsaces);
                requestParameterStr = stringWriter.ToString(); 
            }
        }
    
        // patch parameter to add the namespace prefix required by consumer service
        requestParameterStr = requestParameterStr.Replace("myParameter", "myNs:myParameter");
    
        // wrap parameter in a soap envelop
        requestParameterStr =
            $"<soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:myNs=\"http://myService/Service/\"><soapenv:Header/><soapenv:Body>{requestParameterStr}</soapenv:Body></soapenv:Envelope>";
        request.AddParameter(
            "text/xml",
            requestParameterStr,
            ParameterType.RequestBody);
        var response = client.Execute(request);
    
        var mtomMsg = response.Content;
    
        // remove MTOM elements from the received Content. here comes the ugly part ^^
        var responseContentType = response.ContentType;
        var contentTypeElements = responseContentType.Split(";");
        var boundary = contentTypeElements.FirstOrDefault(x => x.TrimStart().StartsWith("boundary="))?.Trim().Substring("boundary=".Length);
        var startElement = contentTypeElements.FirstOrDefault(x => x.TrimStart().StartsWith("start="))?.Trim().Substring("start=".Length);
        boundary = boundary.Trim('"');
        startElement = startElement.Trim('"');
    
        var startIndex = mtomMsg.IndexOf(startElement) + startElement.Length;
        var endIndex = mtomMsg.LastIndexOf("--" + boundary + "--", startIndex);
        var cleanedMtomMsg = mtomMsg.Substring(startIndex, endIndex - startIndex);
    
        // Get the result inside the Soap envelop
        var soapDocument = XDocument.Parse(cleanedMtomMsg);
    
        var envelopeElt = soapDocument.Root;
        var bodyElt = (System.Xml.Linq.XElement)envelopeElt.FirstNode;
        var responseStr = bodyElt.FirstNode.ToString();
    
        // deserialize the result
        var memstream = new MemoryStream(Encoding.UTF8.GetBytes(responseStr));
        var reader = XmlDictionaryReader.CreateTextReader(memstream, XmlDictionaryReaderQuotas.Max);
    
        var deserializer = new XmlSerializer(typeof(myResponse), "http://myService/Service/"); // don't forget the namespace
        var result = deserializer.Deserialize(reader) as myResponse;
    

note : myParameter & myResponse are the classes generated at step 1

There could be easier ways, but at least, this works. Hope some of you find this helpfull.

1
votes

In my case, I solved this issue by using WcfCoreMtomEncoder package in my .NET Core 2.1 project. You can learn more about using it here

-1
votes

I fixed the problem by installing latest version of visual studio 2017. by installing latest version of visual studio it will automatically update your net core to the latest verion (1.1.2).

you can also use "binaryMessageEncodingBindingElement":

        ChannelFactory<ITestService> factory = null;
        ITestService serviceProxy = null;

        BinaryMessageEncodingBindingElement binaryMessageEncodingBindingElement = new BinaryMessageEncodingBindingElement();
        binaryMessageEncodingBindingElement.CompressionFormat = CompressionFormat.GZip;

        HttpTransportBindingElement httpTransportBindingElement = new HttpTransportBindingElement();
        httpTransportBindingElement.MaxReceivedMessageSize = int.MaxValue;

        CustomBinding customBinding = new CustomBinding(new BindingElement[] { binaryMessageEncodingBindingElement, httpTransportBindingElement });

        factory = new ChannelFactory<ITestService>(customBinding, new EndpointAddress("http://localhost/test.svc/mex"));
        serviceProxy = factory.CreateChannel();

        var result = serviceProxy.GetResultData(50);