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 进阶: 对称加密传输中一致的输出!

你可能感兴趣的:(element)