zoukankan      html  css  js  c++  java
  • Wcf实现IServiceBehavior拓展机制

    Wcf实现IServiceBehavior拓展机制

    IServiceBehavior接口
    描述:提供一种在整个服务内修改或插入自定义拓展机制;
    命名空间:  System.ServiceModel.Description
    程序集:  System.ServiceModel(在 System.ServiceModel.dll 中)
     
    IServiceBehavior接口中有3个方法:
          1.AddBindingParameters:该方法可以向绑定元素传递服务的自定义信息,这样绑定元素就可向服务提供正确的支持。
          2.ApplyDispatchBehavior:该方法可以更改运行时属性值或插入自定义扩展对象,例如错误处理程序、消息或参数拦截器、安全扩展以及其他自定义扩展对象。
          3.Validate:该方法可以在 WCF构造执行服务前检查说明,从而确认该执行服务是否可正确执行。
     
    在上面的3个中最常用到的就是2和3,1本人还没有用过这里也就不使用了!!


     
     
    方法:ApplyDispatchBehavior
     
    该方法应该说是这个接口最主要的方法,我们要对服务进行自定义拓展也是通过它进行注入,下面我们举个例子使用IServiceBehavior对WCF服务异常的处理
    大家都知道WCF一般是使用SAOP进行传输的,如果服务端出现异常客户端是只能够接收到FaultException异常,这里我们通过IServiceBehavior来解决使客户端可以接收到所有异常信息。
     
    代码:
     
        /// <summary>
        /// WCF服务异常处理机制,服务的行为将默认的异常处理添加到所有通信的调度程序中
        /// </summary>
        [AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
        public sealed class ServiceErrorHandlerBehavior
            : Attribute, IServiceBehavior
        {
            /// <summary>
            /// 用于更改运行时属性值或插入自定义扩展对象(例如错误处理程序、消息或参数拦截器、安全扩展以及其他自定义扩展对象)。
            /// </summary>
            /// <param name="serviceDescription"> 服务说明</param>
            /// <param name="serviceHostBase"> 当前正在生成的宿主 </param>
            public void ApplyDispatchBehavior( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                if (serviceHostBase != null && serviceHostBase.ChannelDispatchers.Any())
                {
                    foreach ( ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
                        dispatcher.ErrorHandlers.Add( new InstallErrorHandler());
                }
            }
     
            public void AddBindingParameters( ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection bindingParameters)
            {
                //当前拓展机制不适用
            }
     
            public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                //当前拓展机制不适用
            }
        }
    从ServiceHostBase宿主中遍历通道调度程序集ChannellDispatchers合并在每个ChannelDispatcher中的ErrorHandlers插入自定义异常ServiceErrorHandler,这样的话当WCF服务出现异常时就会转交给ServiceErrorHandler处理;
    下面是InstallErrorHandler代码:
     
        public class ServiceErrorHandler
            : IErrorHandler
        {
            /// <summary>
            /// 启用错误相关处理并返回一个值,该值指示调度程序在某些情况下是否中止会话和实例上下文。
            /// </summary>
            /// <param name="error">处理过程中引发的异常</param>
            /// <returns></returns>
            public bool HandleError(Exception error)
            {
                //不终止会话和实例上下文
                return true;
            }
     
            /// <summary>
            /// 启用创建从服务方法过程中的异常返回的自定义SOAP错误
            /// </summary>
            /// <param name="error">服务操作过程中引发的异常 </param>
            /// <param name="version">消息的 SOAP 版本</param>
            /// <param name="fault">双工情况下,返回到客户端或服务的通信单元对象 </param>
            public void ProvideFault( Exception error, MessageVersion version, ref Message fault)
            {
                var faultException = error is FaultException ?
                    ( FaultException)error : new FaultException(error.Message);
     
                MessageFault messageFault = faultException.CreateMessageFault();
                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }
        }
     
     
    下面是使用方法,非常的简单,只需要在WCF服务类上打上ServiceErrorHandlerBehavior标记就可以了:
    代码:
        [ServiceErrorHandlerBehavior ]
        public class Service1 : IService1
        {
            public string GetData(int value)
            {
                throw new Exception( "我的测试");
            }
        }
    测试代码:
        protected void Page_Load(object sender, EventArgs e)
        {
            WcfWrapper<ServiceReference1. Service1Client> wrapper = new WcfWrapper<ServiceReference1. Service1Client>();
            wrapper.Using(client =>
            {
                xtResult.Text = client.GetData(1);
            });
        }
    输出结果:

    “/”应用程序中的服务器错误。


     我的测试

    说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 

    异常详细信息: System.ServiceModel.FaultException: 我的测试

    源错误: 

    行 114:        
    行 115:        public string GetData(int value) {
    行 116:            return base.Channel.GetData(value);
    行 117:        }
    行 118:        

    源文件: f:cyProjectBulrush.LibraryWebTestService ReferencesServiceReference1Reference.cs    行: 116 

    当然除了使用Attribute特性也可以在WebConfig中配置,配置也非常的简单;
    首先为ServiceErrorHandlerBehavior创建一个Behavior的拓展配置节点,代码如下:
     
        public class ServiceErrorHandlerBehaviorExtension
            : BehaviorExtensionElement
        {
            public override Type BehaviorType
            {
                get { return typeof( ServiceErrorHandlerBehavior); }
            }
     
            protected override object CreateBehavior()
            {
                return new ServiceErrorHandlerBehavior();
            }
        }
    配置如下:
     
      <system.serviceModel>
        <services>
          < service name =" WcfServiceTest.Service1" behaviorConfiguration="defaultBehavior" >
            < endpoint address ="" binding =" basicHttpBinding" contract="WcfServiceTest.IService1" >
            </ endpoint>
            < host>
              < baseAddresses>
                < add baseAddress="http://localhost:2708/Service1.svc" />
              </ baseAddresses>
            </ host>
          </ service>
        </services>
        <behaviors>
          < serviceBehaviors>
            < behavior name =" defaultBehavior" >
              < serviceMetadata httpGetEnabled =" true" httpsGetEnabled="true"/>
              < serviceDebug includeExceptionDetailInFaults =" false" />
              < ErrorBehavior />
            </ behavior>
          </ serviceBehaviors>
        </behaviors>
        <extensions>
          < behaviorExtensions>
            < add name= "ErrorBehavior "
              type="Bulrush.WCF.Behaviors.Errors.ServiceErrorHandlerBehaviorExtension, Bulrush.WCF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
            />
          </ behaviorExtensions>
        </extensions>
      </system.serviceModel>
     
     
    到这里自定义异常处理机制就已经完成了!
     
     
    方法:Validate
     
    该方法主要是对当前的拓展机制进行检查,主要检测两个东西ServiceDescription服务说明和ServiceHostBase服务宿主,它的返回值并不是bool类型而是void类型,所以标识它是否通用验证的方式就是是否抛出异常,抛出异常代表验证不通过。
    为了演示这个方法,我们把上面的ServiceErrorHandler中的ProvideFault方法简单的修改下,修改如下:
     
            public void ProvideFault( Exception error, MessageVersion version, ref Message fault)
            {
                var faultException = error is FaultException<ServiceError> ?
                    ( FaultException< ServiceError>)error :
                    new FaultException< ServiceError>( new ServiceError { Message = "此操作不能在这个时刻处理。请稍后尝试。如果问题仍然存在与您的系统管理员联系" });
     
                MessageFault messageFault = faultException.CreateMessageFault();
                fault = Message.CreateMessage(version, messageFault, faultException.Action);
            }
     
    这里ServiceError只是一个SOAP的传输对象,里面只有一个Message属性就不贴代码了,改成这个方式后呢,假设业务上必须让该服务的每个方法建立错误契约[FaultContract(typeof(ServiceError))],虽然不建立这个服务契约服务可以正常运行,但是所有的错误信息都是“此操作不能在这个时刻处理....”,那么就变的没有意义了,所以我们强制要求每Coder在编写服务方法是必须建立这个错误契约,这个时候我们就可以实现Validate来检查了,具体代码如下:
     
        public void Validate( ServiceDescription serviceDescription, System.ServiceModel.ServiceHostBase serviceHostBase)
        {
            bool flag = false;
     
            foreach ( var point in serviceDescription.Endpoints)
            {
                foreach ( var operation in point.Contract.Operations)
                {
                    if (operation.Faults.Count == 0)
                        throw new InvalidOperationException (string .Format("使用SeriveErrorHandlerBehavior机制,必须为服务方法{0}标识 FaultContractAttribute(typeof(ServiceError)) 错误契约", operation.Name));
     
                    flag = false;
                    foreach ( var fault in operation.Faults)
                    {
                        if (fault.DetailType.Equals(typeof(ServiceError )))
                        {
                            flag = true;
                            break;
                        }
     
                    }
                    if (!flag)
                    {
                        throw new InvalidOperationException(string .Format("使用SeriveErrorHandlerBehavior机制,必须为服务方法{0}标识 FaultContractAttribute(typeof(ServiceError)) 错误契约", operation.Name));
                    }
                }
            }
        }
     
    这个时候如果服务标识了ServiceErrorHandlerBehavior拓展机制,那么下边的所有方法都必须建立错误契约,只要有一个方法没有建立错误契约这个服务就无法被链接!
        
        [ ServiceContract]
        public interface IService1
        {
            //[FaultContract(typeof(ServiceError))]
            [ OperationContract]
            string GetData( int value);
        }
     
    运行服务http://localhost:2708/Service1.svc运行服务则会出现异常:

    “/”应用程序中的服务器错误。


     使用SeriveErrorHandlerBehavior机制,必须为服务方法GetData标识 FaultContractAttribute(typeof(ServiceError)) 错误契约

    说明: 执行当前 Web 请求期间,出现未经处理的异常。请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息。 

    异常详细信息: System.InvalidOperationException: 使用SeriveErrorHandlerBehavior机制,必须为服务方法GetData标识 FaultContractAttribute(typeof(ServiceError)) 错误契约
     
    好了,就写到这里了,写博客真心不容易,感谢那些为我们提供帮助的博主们!!!!
     

    WCF学习--我的第一个WCF例子

     

    Windows Communication Foundation(WCF)是由微软发展的一组数据通信的应用程序开发接口,可以翻译为Windows通讯接口。

    通信双方的沟通方式,由合约来订定。通信双方所遵循的通信方法,由协议绑定来订定。通信期间的安全性,由双方约定的安全性层次来订定。

    契约(Contract)

    WCF 的基本概念是以契约(Contract) 来定义双方沟通的协议,合约必须要以接口的方式来体现,而实际的服务代码必须要由这些合约接口派生并实现。合约分成了四种:
    数据契约(Data Contract),订定双方沟通时的数据格式。服务契约(Service Contract),订定服务的定义。操作约(Operation Contract),订定服务提供的方法。消息约(Message Contract),订定在通信期间改写消息内容的规范。

    协议绑定 (Binding)

    由于 WCF 支持了HTTPTCP,Named Pipe,MSMQ,Peer-To-Peer TCP 等协议,而 HTTP 又分为基本 HTTP 支持 (BasicHttpBinding) 以及 WS-HTTP 支持 (WsHttpBinding),而 TCP 亦支持 NetTcpBinding,NetPeerTcpBinding 等通信方式,因此,双方必须要统一通信的协议,并且也要在编码以及格式上要有所一致。

    安全性层次

    WCF 实现上已经支持了传输层次安全性 (Transport-level security) 以及消息层次安全性 (Message-level security) 两种。
    传输层次安全性:在数据传输时期加密,例如 SSL。消息层次安全性:在数据处理时就加密,例如使用数字签名,散列或是使用密钥加密法等。
    (以上概念从百度百科复制而来,希望对大家有所帮助。)
     
    创建控制台项目实现服务端(WCF_Conosle_Service)
     
      一般地,我们通过接口的形式定义服务契约,下面代码将IHelloWord定义成服务契约

      通过应用ServiceContractAttribute特性将接口定义成服务契约,要在相应的操作方法上面显式地应用OperationContractAttribute特性。

         HelloWorld实现IHelloWorld接口,并具体实现接口定义的方法。

        

      在Program中实现WCF服务的启动

      

    现在服务已经启动,下面实现客户端的调用。(Client层)

    有两种实现方式:

    1:客户端层引用服务端DLL(WCF_Console_Service)

     

    2:添加服务引用

    利用svcUtil.exe生成代码,输入http://127.0.0.1:9999/HelloWord/HelloWord参数(添加svcutil.exe见http://www.cnblogs.com/scottckt/archive/2012/05/20/2510716.html

    生成一个cs文件和一个config文件,生成的cs文件为

      生成的config为

      Program代码为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    class Program
     {
         static void Main(string[] args)
         {
             HelloWorldClient client = new HelloWorldClient();
             string s = client.GetData();
             Console.WriteLine(s);
         }
     }

      运行结果

                       

    以上为新手学习,高手大神就绕过啦,和大家一起学习

     
     
     
    标签: WCF
     
    标签: wcf
  • 相关阅读:
    jquery的get方式发送AJAX请求
    原生JS发送AJAX请求
    正则表达式(二)
    正则表达式(一)
    旅游攻略-北京三日游攻略(已实践)
    边旅游边赚钱的噱头,这是一种传销!
    hdu 1106 排序(水题)
    hdu 1258 Sum It Up(dfs+去重)
    hdu 1455 Sticks(dfs+剪枝)
    解决“LINK : fatal error LNK1123: 转换到 COFF 期间失败: 文件无效或损坏”问题
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3653236.html
Copyright © 2011-2022 走看看