WCF很早就出现了,然而我感受到能够让新手重点去学习WCF而不是WebService是最近两年。我相信大部分人初步了解WCF的时候会很痛苦,尤其是生成代理类,以及配置的问题。我本人其实比较讨厌配置编程,但喜欢轻量配置,因此也一直研究如何自己定义配置节点,去让WCF服务识别,然后重量级ABC操作由编码来完成。下面,我将会提供一个我本人用于学习其他知识需要使用WCF时的开发模式,另外说明,为了更好的说明,我将提供的都是精简版本,并不适合用于测试生产的例子。
1.定义适合自己的配置
1 public class WCFServiceElement : ConfigurationElement 2 { 3 [ConfigurationProperty(name: "ServiceName", IsRequired = false)] 4 public string ServiceName 5 { 6 get 7 { 8 return (base["ServiceName"] as string); 9 }10 set11 {12 base["ServiceName"] = value;13 }14 }15 16 [ConfigurationProperty(name: "ServiceAssembly", IsRequired = false)]17 public string ServiceAssembly18 {19 get20 {21 return (base["ServiceAssembly"] as string);22 }23 set24 {25 base["ServiceAssembly"] = value;26 }27 }28 29 [ConfigurationProperty(name: "InterfaceServiceName", IsRequired = false)]30 public string InterfaceServiceName31 {32 get33 {34 return (base["InterfaceServiceName"] as string);35 }36 set37 {38 base["InterfaceServiceName"] = value;39 }40 }41 42 [ConfigurationProperty(name: "InterfaceServiceAssembly", IsRequired = false)]43 public string InterfaceServiceAssembly44 {45 get46 {47 return (base["InterfaceServiceAssembly"] as string);48 }49 set50 {51 base["InterfaceServiceAssembly"] = value;52 }53 }54 55 [ConfigurationProperty(name: "IPAddress", IsRequired = false)]56 public string IPAddress57 {58 get59 {60 return (base["IPAddress"] as string);61 }62 set63 {64 base["IPAddress"] = value;65 }66 }67 68 [ConfigurationProperty(name: "Binding", IsRequired = false)]69 public string Binding70 {71 get72 {73 return (base["Binding"] as string);74 }75 set76 {77 base["Binding"] = value;78 }79 }80 }
1 public class WCFServicesElementCollection : ConfigurationElementCollection 2 { 3 protected override ConfigurationElement CreateNewElement() 4 { 5 ConfigurationElement _element = new WCFServiceElement(); 6 return _element; 7 } 8 9 protected override object GetElementKey(ConfigurationElement element)10 {11 WCFServiceElement _element = (WCFServiceElement)element;12 return _element.ServiceName;13 }14 15 protected override string ElementName16 {17 get18 {19 return "WCFService";20 }21 }22 23 public override ConfigurationElementCollectionType CollectionType24 {25 get26 {27 return ConfigurationElementCollectionType.BasicMap;28 }29 }30 }
1 public class WCFServiceSection : ConfigurationSection 2 { 3 [ConfigurationProperty(name: "", IsDefaultCollection = true, IsRequired = false)] 4 public WCFServicesElementCollection WCFServices 5 { 6 get 7 { 8 return (base[""] as WCFServicesElementCollection); 9 }10 set11 {12 base[""] = value;13 }14 }15 }
1 23 4 5 67 1513 14
这里注意的是configSections一定要放在第一行,这个倒是听让人无语的。当然配置可以用自己希望方式配置,我这里提供一个简单的思路。
2.定义适合自己的WCFServerConfigurationManagement
1 public abstract class WCFServerConfigurationManagement 2 { 3 private static HybridDictionary _Collection = new HybridDictionary(); 4 5 public static void Register() 6 { 7 WCFServiceSection section = ConfigurationManager.GetSection("WCFServices") as WCFServiceSection; 8 if (null == section) 9 {10 throw new NullReferenceException("未能识别WCFServices,请确认configSections配置节点");11 }12 13 _Collection.Clear();14 15 foreach (WCFServiceElement element in section.WCFServices)16 {17 Assembly assemblyInterfaceService = Assembly.Load(element.InterfaceServiceAssembly);18 Assembly assemblyService = Assembly.Load(element.ServiceAssembly);19 20 Type typeInterface = assemblyInterfaceService.ExportedTypes.FirstOrDefault(type => type.Name.Equals(element.InterfaceServiceName));21 Type typeImplement = assemblyService.ExportedTypes.FirstOrDefault(type => type.Name.Equals(element.ServiceName));22 23 if (null == typeInterface && null == typeImplement)24 {25 throw new NullReferenceException("无法加载服务");26 }27 28 ServiceHost _NewHost = new ServiceHost(typeImplement);29 Binding binding = CreateBinding(element.Binding);30 _NewHost.AddServiceEndpoint(typeInterface, binding, element.IPAddress);31 32 _NewHost.Opened += (sender, e) =>33 {34 #if DEBUG35 Console.WriteLine($"服务:{element.ServiceName} 已经开启.");36 #endif37 };38 _NewHost.Open();39 }40 }41 42 public static Binding CreateBinding(string bindingType)43 {44 Binding _Binding = default(Binding);45 switch (bindingType)46 {47 case "BasicHttpBinding":48 _Binding = new BasicHttpBinding();49 break;50 case "WSHttpBinding":51 _Binding = new WSHttpBinding();52 break;53 case "WS2007HttpBinding":54 _Binding = new WS2007HttpBinding();55 break;56 default:57 throw new ArgumentNullException("根据接口名称无法匹配绑定类型");58 }59 60 return _Binding;61 }62 }
这里主要用来根据配置动态配置WCF ServiceHost 和 Binding 的.然后再您的Custom Host 里面调用如下:
1 class Program2 {3 static void Main(string[] args)4 {5 WCFServerConfigurationManagement.Register();6 7 Console.ReadLine();8 }9 }
3.定义适合自己的WCFClientConfigurationManagement
1 public abstract class WCFClientConfigurationManagement 2 { 3 private static HybridDictionary _Collection = new HybridDictionary(); 4 5 public static void Register() 6 { 7 WCFServiceSection section = ConfigurationManager.GetSection("WCFServices") as WCFServiceSection; 8 if (null == section) 9 {10 throw new NullReferenceException("未能识别WCFServices,请确认configSections配置节点");11 }12 13 _Collection.Clear();14 15 foreach (WCFServiceElement element in section.WCFServices)16 {17 _Collection.Add(element.InterfaceServiceName , element);18 }19 }20 21 public static Binding CreateBinding(string serviceName)22 {23 Binding _Binding = default(Binding);24 WCFServiceElement element = _Collection[serviceName] as WCFServiceElement;25 if (null == element)26 {27 Register();28 element = _Collection[serviceName] as WCFServiceElement;29 if (null == element)30 {31 throw new NullReferenceException("可能配置出现严重错误,根据接口名称无法获取配置文件信息.");32 }33 }34 35 switch (element.Binding)36 {37 case "BasicHttpBinding":38 _Binding = new BasicHttpBinding();39 break;40 case "WSHttpBinding":41 _Binding = new WSHttpBinding();42 break;43 case "WS2007HttpBinding":44 _Binding = new WS2007HttpBinding();45 break;46 default:47 throw new ArgumentNullException("根据接口名称无法匹配绑定类型");48 }49 50 return _Binding;51 }52 53 public static EndpointAddress CreateAddress(string serviceName)54 {55 WCFServiceElement element = _Collection[serviceName] as WCFServiceElement;56 if (null == element)57 {58 Register();59 element = _Collection[serviceName] as WCFServiceElement;60 if (null == element)61 {62 throw new NullReferenceException("可能配置出现严重错误,根据接口名称无法获取配置文件信息.");63 }64 }65 66 EndpointAddress _Address = new EndpointAddress(element.IPAddress);67 return _Address;68 }69 }
这里主要用来根据配置动态配置WCF Client 和 Binding 的。然后再您的客户端以及配置文件注册如下(我这里提供的是ASP.NET MVC 5 的环境):
1 public class MvcApplication : HttpApplication 2 { 3 protected void Application_Start() 4 { 5 AreaRegistration.RegisterAllAreas(); 6 FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); 7 RouteConfig.RegisterRoutes(RouteTable.Routes); 8 BundleConfig.RegisterBundles(BundleTable.Bundles); 9 10 WCFClientConfigurationManagement.Register();11 }12 }
12 3 4 5 6 78 1311 12
4.定义适合自己的WCF ClientBase
1 public class WCFClient 2 { 3 public static TResult ClientInvoke(Func functionInvoke) 4 { 5 string _ServiceName = typeof(TChannel).Name; 6 Binding binding = WCFClientConfigurationManagement.CreateBinding(_ServiceName); 7 EndpointAddress address = WCFClientConfigurationManagement.CreateAddress(_ServiceName); 8 TChannel _channel = ChannelFactory .CreateChannel(binding, address); 9 TResult _Result = functionInvoke.Invoke(_channel);10 return _Result;11 }12 }
以上交代完毕,当然提醒初步了解WCF的人IPAddress 配置也可以写*.svc地址,可以在自寄宿在Windows Service 里,也可以是IIS宿主环境。写到这里,希望这篇随笔能帮助到需要帮助的人,这也就是它的价值所在了。