消耗WCF服务的.NET Core应用中的内容问题

Nir*_*kur 2 wcf .net-core

我正在尝试使用新的Visual Studio WCF Connected服务从.NET Core Web API调用WCF服务方法。

但是,当我对此进行测试时,出现以下错误:

内容类型为多部分/相关;type =“ application / xop + xml”; start =“ http://tempuri.org/0 ”; boundary =“ uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a + id = 1197”; 响应消息的start-info =“ text / xml”与绑定的内容类型不匹配(text / xml; charset = utf-8)。如果使用自定义编码器,请确保正确实施IsContentTypeSupported方法。响应的前1024个字节为:'--uuid:9e7f9b02-4d9c-4ec1-bad4-1007704a579a + id = 1197 Content-ID:http ://tempuri.org/0 Content-Transfer-Encoding:8位内容类型:application / xop + xml; charset = utf-8; type =“ text / xml”

公开的WCF服务使用MTOM MessageEncoding,在传统的.NET Framework客户端应用程序中,我们可以在应用程序的配置文件中将客户端设置为使用MTOM,但在.NET Core中,我们没有可在其中设置MessageEncoding和所有这些配置都在Reference.cs(这是一个生成的文件)中提供的代码中进行了处理。我认为更改此生成的文件以设置MessageEncoding不是一个好选择。

对解决此问题的最佳方法有什么想法?

Tim*_*Tim 6

我在我的项目中遇到了同样的 MTOM 消耗问题,并且必须找到一种能够使用该服务的方法。它以一些(丑陋的)代码结束,但功能强大。

我只是想分享解决方案(因为我在网上找不到任何东西):

  • 首先,通过添加连接的服务(就像您对常规 SOAP 客户端所做的那样)使用 Visual Studio(在我的情况下为 2017)生成客户端。这将帮助您节省大量的虚拟代码输入;)

  • 然后,使用 RestSharp 调用端点,并手动序列化响应/请求:

        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;
    
    Run Code Online (Sandbox Code Playgroud)

注意:myParameter 和 myResponse 是在步骤 1 中生成的类

可能有更简单的方法,但至少,这是有效的。希望你们中的一些人觉得这有帮助。


Nir*_*kur 5

我只是从WCF Core团队了解到,当前基于.NET Core的客户端不支持MTOM编码。这是一项要求的功能,它将在以后的版本中提供。这是具有更多信息的github链接:在WCF运行时中添加MTOM支持