zoukankan      html  css  js  c++  java
  • WCF 服务端异常封装

    WCF 服务端异常封装

     通常WCF服务端异常的详细信息只有在调试环境下才暴露出来,但我目前有需求需要将一部分异常的详细信息传递到客户端,又需要保证一定的安全性。

      最简单的办法当然是在服务端将异常捕获后,序列化传给客户端,但这样需要给服务段方法提供ref或out关键字支持,浪费,不漂亮,所以还是让服务器端抛出异常比较容易。

    复制代码
    <service name="HotelService.HotelService" behaviorConfiguration="ServiceExceptionBehavior">
            <endpoint address="" binding="basicHttpBinding" contract="HotelService.IHotelService"></endpoint>
            <endpoint address="mex" contract="IMetadataExchange" binding="mexHttpBinding"/>
          </service>
    <!--指定服务的Behavior
    将 IncludeExceptionDetailInFaults 设置为 true,可以使异常信息流入客户端,以便进行调试。 此属性需要支持请求响应或双工消息传递的绑定。-->
    <behavior name="ServiceExceptionBehavior"> <serviceMetadata httpGetEnabled="true" /> <serviceDebug includeExceptionDetailInFaults="true" /> </behavior>
    复制代码

       之所以一般服务端异常的细节不提倡暴露出来,主要是因为安全方面的考虑,解决这个问题可以使用自定义异常

    复制代码
      public class TestArgumentException : Exception
        {
            public TestArgumentException(string message, string reason)
                : base(message)
            {
                this.Reason = reason;
            }
    
            public string Reason { get; private set; }
        }
    复制代码

    将真正的异常中我需要的异常提取给自定义异常TestArgumentException,然后抛出TestArgumentException 

            private TestArgumentException BuildNewException(ArgumentException exception)
            {
                TestArgumentException testException = new TestArgumentException(exception.Message, exception.Source);
                return testException;
            }

    将真实的异常替换为自定义异常应该是在发生异常后,异常消息返回之前,可以通过实现IErrorHandler的ProvideFault方法来达到目的,如果需要传递真实的异常类型可以使用FaultCode传递

    复制代码
        public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
            {
                if (fault == null)
                {
                    if (error is ArgumentException)
                    {
                        TestArgumentException testException = BuildNewException(error as ArgumentException);
                        FaultCode code = FaultCode.CreateReceiverFaultCode(new FaultCode("ArgumentException"));
                        ExceptionDetail detail = new ExceptionDetail(testException);
                        FaultException exceptionMessage = new FaultException<ExceptionDetail>(detail, testException.Reason, code);
                        MessageFault message = exceptionMessage.CreateMessageFault();
                        fault = Message.CreateMessage(version, message, exceptionMessage.Action);
                    }
                }
            }
    复制代码

    通过IServiceBehavior的ApplyDispatchBehavior

    复制代码
        public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
            {
                foreach (ChannelDispatcher dispatcher in serviceHostBase.ChannelDispatchers)
                {
                    foreach (EndpointDispatcher epd in dispatcher.Endpoints)
                    {
                        if (epd.ContractName == "IHotelService")
                        {
                            dispatcher.ErrorHandlers.Add(new ServiceErrorHandler());
                        }
                    }
                }
            }
    复制代码

    就可以达到目的了。

    客户端测试代码:

    复制代码
           Exception exception = null;
                HotelService.HotelServiceClient proxy = new HotelService.HotelServiceClient();
                try
                {
                    proxy.GetData(0);
                }
                catch (FaultException<ExceptionDetail> ee)
                {
                    exception = ee;
                    string s = String.Format("{0}
    ERROR:{1}", ee.GetType(), ee.Detail.Message);
                    MessageBox.Show(s);
                }
                catch (FaultException ee)
                {
                    exception = ee;
                    string s = String.Format("{0}
    ERROR:{1}", ee.GetType(), ee.Message);
                    MessageBox.Show(s);
                }
                finally
                {
                    if (exception != null)
                    {
                        //注:在catch程序块中,我们通过代码((calculator as ICommunicationObject).Abort();)
                        //将会话信道强行中断。原因在于,对于基于会话信道(Sessionful Channel)的服务调用,
                        //服务端抛出的异常会将该信道的状态转变为出错状态(Faulted),处于Faulted状态的会话信道将不能再用于后续的通信
                        //即使你调用Close方法将其关闭。在这种情况下,需要调用Abort方法对其进行强行中止。
                        proxy.Abort();
                    }
                }
    复制代码

    这里还有一点问题:FaultException<ExceptionDetail>可以将详细的信息完整的以我想要的格式传到客户端,但ExceptionDetail的派生类会丢失很多信息并且不能被

    catch (FaultException<ExceptionDetail> ee)捕获到。

    将以上代码封装到一个类库中,可以让所有符合规则的WCF服务继承,达到我的目的。

    目前有一点始终不满意,这个DLL的名字想不出起什么好。。。

     
     
    分类: 架构相关
  • 相关阅读:
    Altium Designer 16 问题解决
    IAR FOR AVR 仿真过程中出现全局变量值不断随意变化的问题
    linux '--stdin'错误 -批量修改密码
    EmWin 字体相关函数
    EmWin 文本显示函数
    Win10下 usart驱动PL2303无法安装的问题
    EmWin 接触---基础函数
    Linux 下 Samba 服务器搭建
    MPLAB X IDE V4.15 创建工程,编译,问题处理
    EF Core MVC
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3627152.html
Copyright © 2011-2022 走看看