这段日子,公司开始使用WCF技术来实现一些业务,所以:顺手推舟,借势我也学习了一把WCF。
在网上看到好多人都在讨论WCF的配置,ServiceHost,Client,EndPoint等等……,其实当我们在WEB项目中添加一个WCF服务时,系统自动生成了好多配置就放在了Web.config文件中的某个节点,刚开妈整WCF的时候还老纳闷儿,为什么别人说的配置之类的跟我做的东西没有什么关系?难道我做的就不是WCF服务?呵呵,后来才发现,原来自己太小儿科了。下面我也侃侃一个关于WCF的配置问题:
ServiceHost:配置
1 <? xml version="1.0" encoding="utf-8" ?> 2 < configuration > 3 <!-- <system.ServiceModel> section --> 4 < system.ServiceModel > 5 <!-- services 节点中包含着所有Service的配置说明 --> 6 < services > 7 <!-- 第一个服务的配置开始都是一个<service ****>节点 8 相关属性解释: 9 name - 指定这个service配置是针对的哪一个WCF服务的 10 (名称空间.类型名),ServiceHost载入一个服务后,会到配置文件中的<services>下找有没有 11 name属性跟服务匹配的<service>的配置 12 behaviorConfiguration - 指定在<serviceBehaviors>下的一个<behavior>的name,这个特定<behavior> 13 给这个service制定了一些行为,比如服务是否允许身份模拟 --> 14 < service name ="NameSpace.ClassName" behaviorConfiguration ="BehaviorName" > 15 <!-- 每个服务可以有多个Endpoint,下面<endpoint>元素对每个Endpoint分别进行配置 16 属性说明: 17 address - 指定这个Endpoint对外的URI,这个URI可以是个绝对地址,也可以是个相对于baseAddress的 18 相对地址。如果此属性为空,则这个Endpoint的地址就是baseAddress 19 binding - 指定这个Endpoint使用的binding,这个banding可以是系统预定义的9个binding之一, 20 比如是basicHttpBinding,也可以是自定义的customBinding。binding决定了通讯的类型、 21 安全、如何编码、是否基于session、是否基于事务等等 22 contract - 指定这个Endpoint对应的Contract的全限定名(名称空间.类型名),这个Contract应该被 23 service元素的name指定的那个service实现 24 bindingConfiguration - 指定一个binding的配置名称,跟<bindings>下面同类<binding>的name匹配 25 name - Endpoint的名称,可选属性,每个Contract都可以有多个Endpoint,但是每个Contract对应的 26 多个Endpoint名必须是唯一的 --> 27 < endpoint address ="URI" binding ="basicHttpBinding" contract ="Contract全限定名" bindingConfiguration ="binding名" name ="" > 28 <!-- 用户定义的xml元素集合,一般用作SOAP的header内容 --> 29 < headers > 30 <!-- 任何xml内容 --> 31 </ headers > 32 < identity > 33 <!-- <identity>下的元素都是可选的 --> 34 < userPrincipalName ></ userPrincipalName > 35 < servicePrincipalName ></ servicePrincipalName > 36 < dns ></ dns > 37 < rsa ></ rsa > 38 < certificate encodedValue ="" ></ certificate > 39 <!-- <certificateReference>的属性都是可选的 40 属性说明: 41 storeName - 证书的存储区,可能值为:AddressBook,AuthRoot,CertificateAuthority 42 Disallowed,My,Root,TrustedPeople,TrustedPublisher 43 storeLocation - 证书存储位置,可能值为:CurrentUser,LocalMachine --> 44 < certificateReference storeName ="" storeLocation ="" > 45 </ certificateReference > 46 </ identity > 47 </ endpoint > 48 < host > 49 < baseAddresses > 50 <!-- 在此可以定义每种传输协议的baseAddress,用于跟使用同样传输协议Endpoint定义的相对地 51 址组成完整的地址,但是每种传输协议只能定义一个baseAddress。HTTP的baseAddress同时是service 52 对外发布元数据的URL --> 53 < add baseAddress ="http://address" /> 54 </ baseAddresses > 55 < timeouts ></ timeouts > 56 </ host > 57 </ service > 58 </ services > 59 <!-- 绑定配置 --> 60 < bindings > 61 <!-- 指定一个或多个系统预定义的binding,比如<basicHttpBinding>,当然也可以指定自定义的customBinding, 62 然后在某个指定的binding下建立一个或多个配置,以便被Endpoint来使用这些配置 --> 63 < basicHttpBinding > 64 <!-- 某一类的binding的下面可能有多个配置,binding元素的name属性标识某个binding --> 65 < binding name ="binding名" > 66 </ binding > 67 </ basicHttpBinding > 68 </ bindings > 69 <!-- 定义service和Endpiont行为 --> 70 < behaviors > 71 <!-- 定义service的行为 --> 72 < serviceBehaviors > 73 <!-- 一个或多个系统提供的或定制的behavior元素 74 属性说明: 75 name - 一个behavior唯一标识,<service>元素的behaviorConfiguration属性指向这个name --> 76 < behavior name ="" > 77 <!-- 指定service元数据发布和相关信息 78 属性说明: 79 httpGetEnabled - bool类型的值,表示是否允许通过HTTP的get方法获取sevice的WSDL元数据 80 httpGetUrl - 如果httpGetEnabled为true,这个属性指示使用哪个URL地址发布服务的WSDL, 81 如果这个属性没有设置,则使用服务的HTTP类型的baseAddress后面加上?WSDL --> 82 < serviceMetadata httpGetEnabled ="true" httpGetUrl ="http://URI:port/address" /> 83 </ behavior > 84 </ serviceBehaviors > 85 <!-- 定义Endpiont的行为 --> 86 < endpointBehaviors > 87 </ endpointBehaviors > 88 </ behaviors > 89 <!-- 包含客户端跟服务端连接使用到的Endpoint的配置 --> 90 < client > 91 <!-- 每个客户端Endpoint设置 92 属性说明: 93 address - ServiceHost的这个Endpoint的address 94 binding - 指定这个Endpoint使用的binding,这个binding可以是系统预定义的9个binding之一, 95 比如是basicHttpBinding 96 contract - 指定这个Endpoint对应的Contract的全限定名(名称空间.类型名) 97 name - Endpoint的名称,客户端代理类的构造方法中的endpointConfigurationName对应到这个name 98 bindingConfiguration - 指定客户端binding的具体设置,指向<bindings>元素下同类型binding的name --> 99 <!-- 如果此处有多个endpoint,系统会默认使用最后一个endpoint的配置 --> 100 < endpoint address ="URI" 101 binding ="basicHttpBinding" bindingConfiguration ="binding名" 102 contract ="Contract全限定名" name ="endpoint配置名" /> 103 </ client > 104 </ system.ServiceModel > 105 </ configuration > 106 107
ServiceClient:配置 (如果我们是在一个项目中添加了WCF引用时,系统会在app.config或者是web.config文件中添加一些相应的配置)
1 < system.serviceModel > 2 < bindings > 3 < wsHttpBinding > 4 < binding name ="WSHttpBinding_ICPWService" closeTimeout ="00:01:00" 5 openTimeout ="00:01:00" receiveTimeout ="00:10:00" sendTimeout ="00:01:00" 6 bypassProxyOnLocal ="false" transactionFlow ="false" hostNameComparisonMode ="StrongWildcard" 7 maxBufferPoolSize ="524288" maxReceivedMessageSize ="65536" messageEncoding ="Text" 8 textEncoding ="utf-8" useDefaultWebProxy ="true" allowCookies ="false" > 9 < readerQuotas maxDepth ="32" maxStringContentLength ="8192" maxArrayLength ="16384" 10 maxBytesPerRead ="4096" maxNameTableCharCount ="16384" /> 11 < reliableSession ordered ="true" inactivityTimeout ="00:10:00" 12 enabled ="false" /> 13 < security mode ="None" > 14 < transport clientCredentialType ="Windows" proxyCredentialType ="None" 15 realm ="" /> 16 < message clientCredentialType ="Windows" negotiateServiceCredential ="true" 17 establishSecurityContext ="true" /> 18 </ security > 19 </ binding > 20 </ wsHttpBinding > 21 </ bindings > 22 < client > 23 < endpoint address ="http://xxx.xxx.com/wcf/Service.svc" 24 binding ="wsHttpBinding" bindingConfiguration ="WSHttpBinding_IService" 25 contract ="Namespace.IService" name ="endpointname" /> 26 </ client > 27 </ system.serviceModel >
注:其中一些说明信息是从网上“偷”来的
下面开始讲我遇到的配置问题:
不同的场景下大家都会遇到一些不一样的解决问题的方法,所以这个世界上需要有程序员。大家都说我们是搞.net的,想想也不错,确实是“搞.net” 的,.net出来什么技术我们就“搞”什么,后来又觉得“搞什么搞嘛,还不是人家提供了多少什么就搞点什么,偶尔想自己搞点什么了,还是去重新实现他们提供的接口。结果还是:人家让你怎么搞你就得怎么搞”
呵呵,今天就碰到一个问题,需要动态设置WCF的配置信息,想把WCF Client的配置从web.config文件里拿出来,重新放置在一个目录。如:App_Data/config/xxx.xml,在xxx.xml文件中添加几个节点,由程序动态决定什么时候用什么样的配置。
当时觉得没有什么太大问题,于是就找什么时候可以改变WCF Client的配置。从网上查资料,查MSDN,查Reflector,最终也没有找着好用的方法,所有的方法里提醒的比较有价值的也就只有一个:更改client 的EndPoint的相应Name属性。然后Client 会自动按照相应的Name对应的配置文件,配置当前的ServiceClient。即:说到这里大家可能觉得问题已经解决了,但是:原有的想法是,直接把配置文件拿到app_data/目录下,而现在只解决了一个“endpoint的Name”的问题,因此问题并没有解决。
难道微软就真的没有提醒方法可以重新设置WCF Client的配置的方法吗?有些了解的同志们肯定比我更清楚这个问题,WCF Client的binding,endpoint,Address……等属性都是可以重新设置的,所以是可以重新设置的。
只是找了半天也没有找着自己想要的那种“方便”的设置方法,只给client一个XElement就可以初始化一个ServiceClient,至于XElement中的关于Address,Binding,contract等解析工作还是全部抛给微软现成的类库去处理。找着ServiceClient父类是:ClientBase<TChannel>,使用Reflector查看了此类的构造方法,最终也没有找见可以指定一个XElement就可以初始化一个ServiceClient的方法,其配置信息的读取是使用了写死的从“config”文件里读。
最终失败……非常期待各位前辈能给出指点。(不想自己新建类解析自己的XElement然后再为相应的ServiceClient赋值来实现,因为我的配置节点完全跟微软提供的配置节点一致,为什么没有现有的方法呢?)