WCF进阶:扩展bindingElementExtensions支持对称加密传输
前面两篇文章WCF进阶:将编码后的字节流压缩传输和WCF 进阶: 对称加密传输都是实现了自定义编码,那两个例子中托管服务或者客户端调用都采用的代码实现,WCF更友好的方式是在app.config或web.config来配置服务的运行和调用,本文是介绍如何在配置文件中配置自定义的BindingElement。
上文WCF 进阶: 对称加密传输中我们实现了一个自定义的BindingElement:CryptEncodingBindingElement,它是一个MessageEncodingBindingElement,在宿主程序中,我们通过代码的方式将其添加到CustomBinding中去,方法为:
ICollection<BindingElement> bindingElements = new List<BindingElement>(); HttpTransportBindingElement httpBindingElement = new HttpTransportBindingElement(); string key = "JggkieIw7JM="; string iv = "XdTkT85fZ0U="; CryptEncodingBindingElement textBindingElement = new CryptEncodingBindingElement(new BinaryMessageEncodingBindingElement(), key, iv); bindingElements.Add(textBindingElement); bindingElements.Add(httpBindingElement); CustomBinding bind = new CustomBinding(bindingElements);
如果是缺省的BindingElement,如TextMessageEncodingElement,HttpTransportElement,ReliableSessionElement,SecurityElement都可以像如下这样的方式进行配置:
<bindings> <customBinding> <binding name="myBinding"> <textMessageEncoding/> <reliableSession/> <security/> <httpTransport/> </binding> </customBinding> </bindings>
如果要想让我们自定义的BindingElement和上面的一样享受同等待遇的话,我们需要再额外做一些事情,那就是重载BindingElementExtensionElement,在.Net中扩展配置的基类为:ConfigurationElement,它定义声明了一些扩展配置的属性和方法,为了方便WCF重载了ConfigurationElement形成了ServiceModelExtensionElement,而为了进一步的方便扩展BindingElement,又提供了BindingElementExtensionElement的基类,创建自定义的BindingElementExtension,只需要重载BindingElementExtensionElement三个方法:
using System; using System.ServiceModel.Channels; namespace System.ServiceModel.Configuration { // 摘要: // 为使用计算机或应用程序配置文件中的自定义 System.ServiceModel.Channels.BindingElement 实现提供支持。 public abstract class BindingElementExtensionElement : ServiceModelExtensionElement { // 摘要: // 初始化 System.ServiceModel.Configuration.BindingElementExtensionElement 类的新实例。 protected BindingElementExtensionElement(); // 摘要: // 在派生类中重写时,获取表示自定义绑定元素的 System.Type 对象。 // // 返回结果: // 一个表示自定义绑定类型的 System.Type 对象。 public abstract Type BindingElementType { get; } // 摘要: // 将指定绑定元素的内容应用到此绑定配置元素。 // // 参数: // bindingElement: // 一个绑定元素。 // // 异常: // System.ArgumentNullException: // bindingElement 为 null。 public virtual void ApplyConfiguration(BindingElement bindingElement); // // 摘要: // 在派生类中重写时,返回一个自定义绑定元素对象。 // // 返回结果: // 一个自定义 System.ServiceModel.Channels.BindingElement 对象。 protected internal abstract BindingElement CreateBindingElement(); // // 摘要: // 使用指定绑定元素的内容来初始化此绑定配置节。 // // 参数: // bindingElement: // 一个绑定元素。 protected internal virtual void InitializeFrom(BindingElement bindingElement); } }
public abstract Type BindingElementType { get; } 这个属性中只需要返回自定义类的类型,protected internal abstract BindingElement CreateBindingElement()的重载就是在这创建需要的自定义BindingElement,如果自定义的BindingElement有额外的属性或者参数,我们可以还可以通过创建带有ConfigurationPropertyAttribute的属性来指定。这个是.Net配置中的通性。在我们的需求中,需要一个CryptEncodingBindingElement实例,而CryptEncodingBindingElement带有三个参数:InnerMessageEncodingBindingElement,Key,IV。分析到这,我们的自定义BindingElement配置扩展类就成形了,代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel.Configuration; using System.Configuration; namespace RobinLib { public class CryptEncodingBindingElementConfiguration : BindingElementExtensionElement { public override void ApplyConfiguration(System.ServiceModel.Channels.BindingElement bindingElement) { CryptEncodingBindingElement bind = bindingElement as CryptEncodingBindingElement; if (InnerMessageEncoding.ToLower() == "text") { bind.InnerMessageEncodingBindingElement = new System.ServiceModel.Channels.TextMessageEncodingBindingElement(); } else if (InnerMessageEncoding.ToLower() == "binary") { bind.InnerMessageEncodingBindingElement = new System.ServiceModel.Channels.BinaryMessageEncodingBindingElement(); } else if (InnerMessageEncoding.ToLower() == "mtom") { bind.InnerMessageEncodingBindingElement = new System.ServiceModel.Channels.MtomMessageEncodingBindingElement(); } bind.Key = Key; bind.IV = IV; base.ApplyConfiguration(bindingElement); } [ConfigurationProperty("innerMessageEncoding",DefaultValue="text")] public string InnerMessageEncoding { get { return base["innerMessageEncoding"] as string; } set { base["innerMessageEncoding"] = value; } } [ConfigurationProperty("key", DefaultValue = "")] public string Key { get { return base["key"] as string; } set { base["key"] = value; } } [ConfigurationProperty("iv", DefaultValue = "")] public string IV { get { return base["iv"] as string; } set { base["iv"] = value; } } public override Type BindingElementType { get { return typeof(CryptEncodingBindingElementConfiguration); } } protected override System.ServiceModel.Channels.BindingElement CreateBindingElement() { if (InnerMessageEncoding.ToLower() == "text") { CryptEncodingBindingElement bindElement = new CryptEncodingBindingElement(new System.ServiceModel.Channels.TextMessageEncodingBindingElement(), Key, IV); return bindElement; } else if (InnerMessageEncoding.ToLower() == "binary") { CryptEncodingBindingElement bindElement = new CryptEncodingBindingElement(new System.ServiceModel.Channels.BinaryMessageEncodingBindingElement(), Key, IV); return bindElement; } else if (InnerMessageEncoding.ToLower() == "mtom") { CryptEncodingBindingElement bindElement = new CryptEncodingBindingElement(new System.ServiceModel.Channels.MtomMessageEncodingBindingElement(), Key, IV); return bindElement; } throw new Exception("只支持Text,Binary,MTOM三种内置编码器!"); } } }
重载实现之后,我们就可以使用它在App.Config或者Web.Config来配置BindingElement,使用的方法为:
1. 在<system.serviceModel><extensions> <bindingElementExtensions>中添加新的配置节点的绑定。
2. 创建新的注册后的节点到自定义绑定中。
来看一下服务的配置文件吧:
<?xml version="1.0" encoding="utf-8" ?> <configuration> <system.serviceModel> <services> <clear/> <service name="Robin_Wcf_CustomMessageEncoder_SvcLib.Service1"> <host> <baseAddresses> <add baseAddress="http://127.0.0.1:8081/"/> </baseAddresses> </host> <endpoint address="Robin_Wcf_Formatter" name="ep" contract="Robin_Wcf_CustomMessageEncoder_SvcLib.IService1" binding="customBinding" bindingConfiguration="myBinding"></endpoint> </service> </services> <bindings> <customBinding> <binding name="myBinding"> <cryptMessageEncoding key="JggkieIw7JM=" iv="XdTkT85fZ0U=" innerMessageEncoding="Binary"/> <httpTransport/> </binding> </customBinding> </bindings> <extensions> <bindingElementExtensions> <add name="cryptMessageEncoding" type="RobinLib.CryptEncodingBindingElementConfiguration,RobinLib,Version=1.0.0.0, Culture=neutral,PublicKeyToken=null"/> </bindingElementExtensions> </extensions> </system.serviceModel> </configuration>
托管服务的代码就轻便了好多,如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ServiceModel; using Robin_Wcf_CustomMessageEncoder_SvcLib; using System.ServiceModel.Channels; using RobinLib; namespace Robin_Wcf_CustomMessageEncoder_Host { class Program { static void Main(string[] args) { ServiceHost host = new ServiceHost(typeof(Service1)); if (host.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>() == null) { System.ServiceModel.Description.ServiceMetadataBehavior svcMetaBehavior = new System.ServiceModel.Description.ServiceMetadataBehavior(); svcMetaBehavior.HttpGetEnabled = true; svcMetaBehavior.HttpGetUrl = new Uri("http://127.0.0.1:8001/Mex"); host.Description.Behaviors.Add(svcMetaBehavior); } host.Opened += new EventHandler(delegate(object obj, EventArgs e) { Console.WriteLine("服务已经启动!"); }); host.Open(); Console.Read(); } } }
运行项目,能得到和WCF 进阶: 对称加密传输中一致的输出!
出处:http://jillzhang.cnblogs.com/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。