zoukankan      html  css  js  c++  java
  • 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();
            }
        }
    }
  • 相关阅读:
    ES6新特性
    CSS + HTML 鼠标在图片上悬停时的显示文字,移走时文字消失
    APICloud closeToWin和closeWin的使用
    基于vue-cli配置移动端自适应
    Cookies,localStorage,sessionStorage,Web SQL Database(客户端)会话存储学习
    select标签默认选择选项
    MySQL数据库的配置
    jsp定义 ,JSON对象
    eclipse配置
    VS2017 C++编译时出现 "the windows sdk version for 8.1 was not found"解决办法(亲测有效)
  • 原文地址:https://www.cnblogs.com/lvdongjie/p/5577882.html
Copyright © 2011-2022 走看看