欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

.NET Core调用WCF的最佳实践

程序员文章站 2022-05-05 16:09:06
现在.NET Core貌似很火,与其他.NET开发者交流不说上几句.NET Core都感觉自己落伍了一样。但是冷静背后我们要也看到.NET Core目前还有太多不足,别的不多说,与自家的服务框架WCF集成起来就不咋地,从最初不支持,到现在有个笨笨咔咔的Web Service Reference Pr ......

现在.NET Core貌似很火,与其他.NET开发者交流不说上几句.NET Core都感觉自己落伍了一样。但是冷静背后我们要也看到.NET Core目前还有太多不足,别的不多说,与自家的服务框架WCF集成起来就不咋地,从最初不支持,到现在有个笨笨咔咔的Web Service Reference Provider,生成的代理类简直不堪入目,还特别的慢。所以本人本着为将来框架的兼容性做准备,就着手研究了下能不能不通过代理类访问WCF,好在微软开源了一部分WCF代码。

WCF的开发者一定很熟悉,WCF的所有配置都是可以通过代码和配置文件两种方式,而大多数开发者都会选择配置文件,但是从.NET Core开始,微软干掉了Web/App.config,不知道别人怎么样,反正我是非常之不习惯。干掉Web/App.config的后果,就是开源支持.NET Core的那部分Client Side没有配置文件的支持,翻看源码后发现,只要是读取配置文件的地方,都是这样的代码 —— PlatformNotSupported。

protected void InitializeEndpoint(string configurationName, EndpointAddress address)
{
            _serviceEndpoint = this.CreateDescription();

            ServiceEndpoint serviceEndpointFromConfig = null;

            // Project N and K do not support System.Configuration, but this method is part of Windows Store contract.
            // The configurationName==null path occurs in normal use.
            if (configurationName != null)
            {
                throw ExceptionHelper.PlatformNotSupported();
                // serviceEndpointFromConfig = ConfigLoader.LookupEndpoint(configurationName, address, this.serviceEndpoint.Contract);
       }
}

 

但是好在微软又推出了System.Configuration.ConfigurationManager的NuGet包,所以本人仿照WCF原生的配置文件,自己实现一套配置,经过两个晚上的战斗,已经成功。好了,废话不多说,上代码了。

先看看最终的效果是什么样的,WCF服务端的代码结构如下:

.NET Core调用WCF的最佳实践

采用标准的WCF分层方式,用控制台做宿主,其中IAppService项目版本为.NET Standard 2.0,每个终结点同时使用BasicHttpBinding与NetTcpBinding双重绑定,配置文件如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <!--WCF配置-->
  <system.serviceModel>
    <!--WCF服务配置,手动增加service节点-->
    <services>
      <!--产品服务配置-->
      <service behaviorConfiguration="DefaultBehavior" name="WCF.AppService.Implements.ProductService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8098/Hosts/ProductService.svc" />
            <add baseAddress="net.tcp://localhost:8099/Hosts/ProductService.svc" />
          </baseAddresses>
        </host>
        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding" contract="WCF.IAppService.Interfaces.IProductService" />
        <endpoint binding="netTcpBinding" bindingConfiguration="tcpBinding" contract="WCF.IAppService.Interfaces.IProductService" />
      </service>
      <!--订单服务配置-->
      <service behaviorConfiguration="DefaultBehavior" name="WCF.AppService.Implements.OrderService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8098/Hosts/OrderService.svc" />
            <add baseAddress="net.tcp://localhost:8099/Hosts/OrderService.svc" />
          </baseAddresses>
        </host>
        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding" contract="WCF.IAppService.Interfaces.IOrderService" />
        <endpoint binding="netTcpBinding" bindingConfiguration="tcpBinding" contract="WCF.IAppService.Interfaces.IOrderService" />
      </service>
      <!--集成服务配置-->
      <service behaviorConfiguration="DefaultBehavior" name="WCF.AppService.Implements.IntegrationService">
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8098/Hosts/IntegrationService.svc" />
            <add baseAddress="net.tcp://localhost:8099/Hosts/IntegrationService.svc" />
          </baseAddresses>
        </host>
        <endpoint binding="basicHttpBinding" bindingConfiguration="basicBinding" contract="WCF.IAppService.Interfaces.IIntegrationService" />
        <endpoint binding="netTcpBinding" bindingConfiguration="tcpBinding" contract="WCF.IAppService.Interfaces.IIntegrationService" />
      </service>
    </services>
    <!--WCF行为配置,配置好无需修改-->
    <behaviors>
      <serviceBehaviors>
        <behavior name="DefaultBehavior">
          <!--是否允许get请求访问-->
          <serviceMetadata httpGetEnabled="true" />
          <!--允许从请求消息头中检索元数据地址信息-->
          <useRequestHeadersForMetadataAddress />
          <!--是否显示异常信息-->
          <serviceDebug includeExceptionDetailInFaults="true" />
          <!--最大序列化的对象个数-->
          <dataContractSerializer maxItemsInObjectGraph="2147483647" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <!--WCF绑定配置,配置好无需修改-->
    <bindings>
      <netTcpBinding>
        <binding name="tcpBinding" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" />
      </netTcpBinding>
      <basicHttpBinding>
        <binding name="basicBinding" maxBufferPoolSize="2147483647" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" closeTimeout="00:10:00" openTimeout="00:10:00" receiveTimeout="00:10:00" sendTimeout="00:10:00" />
      </basicHttpBinding>
    </bindings>
    <!--WCF多宿主绑定配置-->
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
</configuration>

 

运行测试没问题,服务端不多说,重点是客户端,因为IAppService是.NET Standard 2.0的类库版本,所以.NET Core客户端是可以正常引用的,新建.NET Core控制台,并引用上述IAppService项目。

客户端项目结构如下:

.NET Core调用WCF的最佳实践

客户端配置文件如下:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <!--WCF配置节点-->
    <section name="system.serviceModel" type="System.ServiceModel.ServiceModelSection, System.ServiceModel.Toolkits" />
  </configSections>

  <!--WCF配置-->
  <system.serviceModel>
    <!--WCF客户端配置,手动增加endpoint节点-->
    <client>
      <!--商品服务契约配置-->
      <endpoint address="net.tcp://localhost:8099/Hosts/ProductService.svc" binding="netTcpBinding" contract="WCF.IAppService.Interfaces.IProductService" name="WCF.IAppService.Interfaces.IProductService">
        <headerProvider type="WCF.Core.Client.HeaderProviders.MyHeaderProvider" assembly="WCF.Core.Client"/>
      </endpoint>
      <!--订单服务契约配置-->
      <endpoint address="net.tcp://localhost:8099/Hosts/OrderService.svc" binding="netTcpBinding" contract="WCF.IAppService.Interfaces.IOrderService" name="WCF.IAppService.Interfaces.IOrderService" />
      <!--集成服务契约配置-->
      <endpoint address="net.tcp://localhost:8099/Hosts/IntegrationService.svc" binding="netTcpBinding" contract="WCF.IAppService.Interfaces.IIntegrationService" name="WCF.IAppService.Interfaces.IIntegrationService" />
    </client>
  </system.serviceModel>
</configuration>

 

Main方法中代码如下:

class Program
    {
        static void Main(string[] args)
        {
            //初始化容器
            IContainer container = InitContainer();

            //调用
            IProductService productService = container.Resolve<IProductService>();
            string products = productService.GetProducts();

            Console.WriteLine(products);

            container.Dispose();
            Console.ReadKey();
        }

        static IContainer InitContainer()
        {
            ContainerBuilder builder = new ContainerBuilder();
            Assembly wcfInterfaceAssembly = Assembly.Load("WCF.IAppService");

            //获取WCF接口类型集
            IEnumerable<Type> types = wcfInterfaceAssembly.GetTypes().Where(type => type.IsInterface);

            //获取服务代理泛型类型
            Type proxyGenericType = typeof(ServiceProxy<>);

            //注册WCF接口
            foreach (Type type in types)
            {
                Type proxyType = proxyGenericType.MakeGenericType(type);
                PropertyInfo propChannel = proxyType.GetProperty(ServiceProxy.ChannelPropertyName, type);

                builder.RegisterType(proxyType).OnRelease(proxy => ((IDisposable)proxy).Dispose());
                builder.Register(container => propChannel.GetValue(container.Resolve(proxyType))).
                    As(type).
                    OnRelease(channel => channel.CloseChannel());
            }

            return builder.Build();
        }
    }

 

启动运行结果如下:

.NET Core调用WCF的最佳实践

怎么样?是不是觉得很清爽?如果你有兴趣,可以到我的Git看全部源码,地址如下:

https://gitee.com/lishilei0523/WCF-DotNetCore

Ps:因为微软公开的WCF类库本身就不完善,所以我也没法提供全部的功能,本人所作调用方式目前支持BasicHttpBinding和NetTcpBinding,并且包含消息头支持。如果你觉得代码对你有帮助,麻烦点个Star,不胜感激。