現在.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服務端的代碼結構如下:
採用標準的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,不勝感激。