.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,不勝感激。
歡迎進入我的碼云?https://gitee.com/lishilei0523
原文地址:http://www.cnblogs.com/lishilei0523/p/8886483.html
.NET社區新聞,深度好文,歡迎訪問公眾號文章匯總 http://www.csharpkit.com
總結
以上是生活随笔為你收集整理的.NET Core调用WCF的最佳实践的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 业务配置开发平台qMISPlat 2.0
- 下一篇: asp.net ajax控件工具集 Au