【问题标题】:How do I use WcfCoreMtomEncoder in a .Net Core project?如何在 .Net Core 项目中使用 WcfCoreMtomEncoder?
【发布时间】:2020-01-06 21:12:09
【问题描述】:

我想在我的 .Net Core 项目中使用这个 WcfCoreMtomEncoder lib here,但我不确定如何在语法上使用它。

我在下面有这段代码,但不能使用 MessageEncoding,因为我在一个 .Net Core 项目中(不支持 mtom):

var binding = new BasicHttpBinding(BasicHttpSecurityMode.Transport)
{ 
    // MessageEncoding = WSMessageEncoding.Mtom, not supported in .Net Core
    TransferMode = TransferMode.Streamed
};

EndpointAddress endpoint = new EndpointAddress(url);
var channelFactory = new ChannelFactory<T>(binding, endpoint);
var webService = channelFactory.CreateChannel();
user.UserName = await webService.EncryptValueAsync(userName);
user.Password = await webService.EncryptValueAsync(password);
var documentAddResult = webService.DocumentAdd(document);
channelFactory.Close();

根据我阅读的内容,我可以用下面的 library 代码替换它,我从编码器库的文档中看到,用法如下所示:

var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement());
var transport = new HttpTransportBindingElement();
var customBinding = new CustomBinding(encoding, transport);

var client = new MtomEnabledServiceClient(customBinding);

但我不确定这里是什么? 它将如何用于执行我想要实现的文档上传?图书馆是这样做的还是我误解了它的作用?

如果有人能给我提供一个如何使用这个库来执行文档上传的例子,我将不胜感激。

【问题讨论】:

  • 在我这边,我试过了,没用,总是出现同样的错误。
  • 嗨。你到底尝试了什么?也许您可以显示您的代码的 sn-p 和错误?
  • 我使用 Mtom 编码器创建了一个带有 basichttpbinding 的 WCF 服务。然后我通过使用 Mtom 编码器配置自定义绑定来调用服务。我还尝试使用给定的绑定创建 WCF 服务,并使用它。此外,具有该绑定的 Channel Factory 也不起作用。我不知道类库是用来做什么的。 GitHub 的问题也还没有解决。
  • (内容类型multipart/related; type="application/xop+xml"; start="tempuri.org/0>"; boundary="uuid:b84ef9c6-0def-4900-a3cb-27d13b846c62 +id=5"; start-info="text/xml" 的响应消息与绑定的内容类型(text/xml; charset=utf-8)不匹配。如果使用自定义编码器,请确保IsContentTypeSupported 方法已正确实现。响应的前 435 个字节为:

标签: c# wcf .net-core mtom


【解决方案1】:

经过一番努力,我设法创建了一个可以被类库使用的 WCF 服务。但它只支持自定义绑定。请参考以下示例。
服务器端(基于 Dotnet Framework 4.7.2 的控制台应用)

class Program
    {
        static void Main(string[] args)
        {
            Uri uri = new Uri("http://localhost:21011");
            MtomMessageEncodingBindingElement encoding = new MtomMessageEncodingBindingElement();
            var transport = new HttpTransportBindingElement();
            transport.TransferMode = TransferMode.Streamed;
            var binding = new CustomBinding(encoding, transport);
            using (ServiceHost sh = new ServiceHost(typeof(MyService), uri))
            {
                sh.AddServiceEndpoint(typeof(IService), binding, "");
                ServiceMetadataBehavior smb;
                smb = sh.Description.Behaviors.Find<ServiceMetadataBehavior>();
                if (smb == null)
                {
                    smb = new ServiceMetadataBehavior()
                    {
                        HttpGetEnabled = true
                    };
                    sh.Description.Behaviors.Add(smb);
                }
                Binding mexbinding = MetadataExchangeBindings.CreateMexHttpBinding();
                sh.AddServiceEndpoint(typeof(IMetadataExchange), mexbinding, "mex");


                sh.Opened += delegate
                {
                    Console.WriteLine("Service is ready");
                };
                sh.Closed += delegate
                {
                    Console.WriteLine("Service is clsoed");
                };
                sh.Open();
                Console.ReadLine();
                //pause
                sh.Close();
                Console.ReadLine();
            }
        }
    }
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        string Test();

    }
    public class MyService : IService
    {
        public string Test()
        {
            return DateTime.Now.ToLongTimeString();
        }
}

客户端(基于核心的控制台应用程序,带有WcfCoreMtomEncoder nuget 包,使用ChannelFactory 调用服务)。

    class Program
    {
        static void Main(string[] args)
        {
            var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement());
            var transport = new HttpTransportBindingElement();
            transport.TransferMode = TransferMode.Streamed;
            var binding = new CustomBinding(encoding, transport);
            EndpointAddress endpoint = new EndpointAddress("http://vabqia969vm:21011");
            ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(binding, endpoint);
            var webService = channelFactory.CreateChannel();
            Console.WriteLine(webService.Test());
        }
    }
    [ServiceContract]
    public interface IService
    {
        [OperationContract]
        string Test();

}

还有一点我们需要注意的是,如果服务器使用传输安全模式来保护通信,我们应该手动将证书绑定到服务器端的特定端口。

Netsh http 添加 sslcert ipport=0.0.0.0 证书哈希=0102030405060708090A0B0C0D0E0F1011121314 appid={00112233-4455-6677-8899-AABBCCDDEEFF}

在上面的示例中,我将具有名为 vabqia969vm 主题(DNS)的证书绑定到机器(主机名为 vabqia969vm)。以下是一些官方链接。
https://docs.microsoft.com/en-us/windows/win32/http/add-sslcert
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-configure-a-port-with-an-ssl-certificate
在客户端,在调用服务之前,我们应该建立信任关系,以便客户端和服务器端之间可以进行通信。因此,我在客户端 LocalCA(证书存储中的受信任的根证书颁发机构)上安装了服务器证书。或者,我们可以手动添加证书验证过程。

ChannelFactory<IService> channelFactory = new ChannelFactory<IService>(binding, endpoint);
            channelFactory.Credentials.ServiceCertificate.SslCertificateAuthentication = new System.ServiceModel.Security.X509ServiceCertificateAuthentication()
            {
                CertificateValidationMode = System.ServiceModel.Security.X509CertificateValidationMode.None,
                RevocationMode = System.Security.Cryptography.X509Certificates.X509RevocationMode.NoCheck
            };

如果有什么我可以帮忙的,请随时告诉我。
已更新。
我已经更新了上面的例子,它可以在HTTP 协议上正常工作。

【讨论】:

  • 您的代码使用 .Net Framework 4.7.2?我的帖子专门与 .Net Core 相关
  • 服务端使用.Net Framework 4.7.2,客户端使用.Net core Sdk。这就是库应用的地方,使基于核心的应用程序可以使用 Mtom 编码器。基于.Net Core的服务器端无法创建Wcf服务应用,因为它是一个基于.Net框架的分布式框架,目前还没有在Core中实现。 gRPC 是在 Core 中构建分布式应用程序的最佳方法
  • @user1186050 ,在上面的代码sn-ps中,我们也可以创建一个没有传输层安全模式的服务。它也可以在 Dotnet Core 应用程序中正确调用。这样的话,不需要指定`https'基地址,也不需要绑定证书,很容易搞定。我已经更新了回复,请查收。
【解决方案2】:

按以下步骤进行:

  1. 使用 WCF 生成服务客户端,这将产生命名空间和部分类,例如 DocumentWebServiceClient
  2. 在同一个项目和命名空间中,创建一个文件来扩展部分类并实现用于端点配置任务的ConfigureEndpoint 方法:
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using WcfCoreMtomEncoder;

public partial class DocumentWebServiceClient // DocumentWebServiceClient is generated by the WCF
{
    static partial void ConfigureEndpoint(ServiceEndpoint serviceEndpoint, ClientCredentials clientCredentials)
    {
        var messageEncodingBindingElementType = typeof(MessageEncodingBindingElement);
        var elements = serviceEndpoint.Binding.CreateBindingElements();

        IEnumerable<BindingElement> elementsWithoutEncodingElement = elements.Where(item => !messageEncodingBindingElementType.IsAssignableFrom(item.GetType()));
        var existingEncodingElement = (MessageEncodingBindingElement)elements.Where(item => messageEncodingBindingElementType.IsAssignableFrom(item.GetType())).First();

        var newEncodingElement = new MtomMessageEncoderBindingElement(existingEncodingElement);

        // Encoding is before transport, so we prepend the MTOM message encoding binding element
        // https://docs.microsoft.com/en-us/dotnet/framework/wcf/extending/custom-bindings
        var cb = new CustomBinding(elementsWithoutEncodingElement.Prepend(newEncodingElement));
        serviceEndpoint.Binding = cb;
    }
}

【讨论】:

    【解决方案3】:

    您的 .net 核心客户端代码应该是这样的

    var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement());
    var transport = new HttpTransportBindingElement();
    var customBinding = new CustomBinding(encoding, transport);
    
    
    EndpointAddress endpoint = new EndpointAddress(url);
    var channelFactory = new ChannelFactory<T>(customBinding, endpoint);
    var webService = channelFactory.CreateChannel();
    user.UserName = await webService.EncryptValueAsync(userName);
    user.Password = await webService.EncryptValueAsync(password);
    var documentAddResult = webService.DocumentAdd(document);
    channelFactory.Close();
    

    【讨论】:

    • 你知道这是否支持https吗?使用它我得到一个异常,上面写着:“提供的 URI 方案 'https' 无效;预期为 'http'”
    • 在这种情况下使用 HttpsTransportBindingElement 而不是 HttpTransportBindingElement
    • 但根据消息它需要 http,而不是 https。你不是建议我反其道而行之吗?
    • 如果您的服务器 url 是 http 则使用 httptransportbinding
    【解决方案4】:

    扩展@divyang4481 的答案。对于那些仍在为此苦苦挣扎的人,根据您正在与之交互的服务,您可能需要将编码更改为如下所示:

            var encoding = new MtomMessageEncoderBindingElement(new TextMessageEncodingBindingElement
            {
                MessageVersion = MessageVersion.CreateVersion(EnvelopeVersion.Soap12, AddressingVersion.None)
            });
    
            var transport = new HttpsTransportBindingElement();
            var customBinding = new CustomBinding(encoding, transport);
    

    我调用的网络服务抛出了一个错误,即 mustUnderstand headers 使用默认的 TextMessageEncodingBindingElement,所以,我必须将 AddressVersion 设置为没有解决问题。

    【讨论】:

      猜你喜欢
      • 2017-12-15
      • 1970-01-01
      • 2021-03-02
      • 2023-04-07
      • 2016-11-15
      • 1970-01-01
      • 2018-12-08
      • 1970-01-01
      • 2018-05-01
      相关资源
      最近更新 更多