WCF自寄宿

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             set
11             {
12                 base["ServiceName"] = value;
13             }
14         }
15 
16         [ConfigurationProperty(name: "ServiceAssembly", IsRequired = false)]
17         public string ServiceAssembly
18         {
19             get
20             {
21                 return (base["ServiceAssembly"] as string);
22             }
23             set
24             {
25                 base["ServiceAssembly"] = value;
26             }
27         }
28 
29         [ConfigurationProperty(name: "InterfaceServiceName", IsRequired = false)]
30         public string InterfaceServiceName
31         {
32             get
33             {
34                 return (base["InterfaceServiceName"] as string);
35             }
36             set
37             {
38                 base["InterfaceServiceName"] = value;
39             }
40         }
41 
42         [ConfigurationProperty(name: "InterfaceServiceAssembly", IsRequired = false)]
43         public string InterfaceServiceAssembly
44         {
45             get
46             {
47                 return (base["InterfaceServiceAssembly"] as string);
48             }
49             set
50             {
51                 base["InterfaceServiceAssembly"] = value;
52             }
53         }
54 
55         [ConfigurationProperty(name: "IPAddress", IsRequired = false)]
56         public string IPAddress
57         {
58             get
59             {
60                 return (base["IPAddress"] as string);
61             }
62             set
63             {
64                 base["IPAddress"] = value;
65             }
66         }
67 
68         [ConfigurationProperty(name: "Binding", IsRequired = false)]
69         public string Binding
70         {
71             get
72             {
73                 return (base["Binding"] as string);
74             }
75             set
76             {
77                 base["Binding"] = value;
78             }
79         }
80 }
View Code
 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 ElementName
16         {
17             get
18             {
19                 return "WCFService";
20             }
21         }
22 
23         public override ConfigurationElementCollectionType CollectionType
24         {
25             get
26             {
27                 return ConfigurationElementCollectionType.BasicMap;
28             }
29         }
30 }
View Code
 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             set
11             {
12                 base[""] = value;
13             }
14         }
15 }
View Code
 1 <?xml version="1.0" encoding="utf-8" ?>
 2 <configuration>
 3   <configSections>
 4     <section name="WCFServices" type="Basic.Configuration.WCFServiceSection,Basic.Data"/>
 5   </configSections>
 6   <WCFServices>
 7     <WCFService ServiceName="AppManagementImplementation"
 8 ServiceAssembly="Service.BackgroundManagement.Implementation"
 9                           InterfaceServiceName="IAppManagement"
10 InterfaceServiceAssembly="Service.BackgroundManagement.Interface"
11                           IPAddress="http://192.168.1.4:8085/AppManagementService" 
12                           Binding="WSHttpBinding">
13     </WCFService>
14   </WCFServices>
15 </configuration>
View Code

这里注意的是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 DEBUG
35                     Console.WriteLine($"服务:{element.ServiceName} 已经开启.");
36 #endif
37                 };
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 }
View Code

这里主要用来根据配置动态配置WCF ServiceHost 和 Binding 的.然后再您的Custom Host 里面调用如下:

1 class Program
2 {
3         static void Main(string[] args)
4         {
5             WCFServerConfigurationManagement.Register();
6 
7             Console.ReadLine();
8         }
9 }
View Code

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 }
View Code

这里主要用来根据配置动态配置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  }
View Code
 1 <configuration>
 2   <configSections>
 3     <!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 -->
 4     <section name="entityFramework" type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" requirePermission="false" />
 5     <section name="WCFServices" type="Basic.Configuration.WCFServiceSection,Basic.Data"/>
 6   </configSections>
 7 <WCFServices>
 8     <WCFService InterfaceServiceName="IAppManagement"
 9                           IPAddress="http://192.168.1.4:8085/AppManagementService"
10                           Binding="WSHttpBinding">
11     </WCFService>
12 </WCFServices>
13 </configuration>
View Code

4.定义适合自己的WCF ClientBase

 1 public class WCFClient
 2 {
 3         public static TResult ClientInvoke<TChannel , TResult>(Func<TChannel , TResult> functionInvoke)
 4         {
 5             string _ServiceName = typeof(TChannel).Name;
 6             Binding binding = WCFClientConfigurationManagement.CreateBinding(_ServiceName);
 7             EndpointAddress address = WCFClientConfigurationManagement.CreateAddress(_ServiceName);
 8             TChannel _channel = ChannelFactory<TChannel>.CreateChannel(binding, address);
 9             TResult _Result = functionInvoke.Invoke(_channel);
10             return _Result;
11         }
12 }
View Code

以上交代完毕,当然提醒初步了解WCF的人IPAddress 配置也可以写*.svc地址,可以在自寄宿在Windows Service 里,也可以是IIS宿主环境。写到这里,希望这篇随笔能帮助到需要帮助的人,这也就是它的价值所在了。

原文地址:https://www.cnblogs.com/blakebook/p/5380097.html