.NET Core調用WCF的最佳實踐


現在.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服務端的代碼結構如下:

采用標准的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項目。

客戶端項目結構如下:

客戶端配置文件如下:

<?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();
        }
    }

 

啟動運行結果如下:

怎么樣?是不是覺得很清爽?如果你有興趣,可以到我的Git看全部源碼,地址如下:

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

Ps:因為微軟公開的WCF類庫本身就不完善,所以我也沒法提供全部的功能,本人所作調用方式目前支持BasicHttpBinding和NetTcpBinding,並且包含消息頭支持。如果你覺得代碼對你有幫助,麻煩點個Star,不勝感激。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM