通常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());
}
}
}
}

就可以达到目的了。

客户端测试代码:

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

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

catch (FaultException<ExceptionDetail> ee)捕获到,应该没加KownType的关系,有空试下。

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

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

WCF 服务端异常封装的更多相关文章

  1. WCF客户端获取服务端异常[自定义异常]

    引言 经过不断的摸索,询问/调试,终于学会了关于WCF客户端与服务端之间异常的处理机制,在此来记录自己的成果,用于记录与分享给需要的伙伴们. 首先感谢[.NET技术群]里群主[轩]的大力帮助,如有需要 ...

  2. WCF服务端开发和客户端引用小结

    1.服务端开发 1.1 WCF服务创建方式 创建一个WCF服务,总是会创建一个服务接口和一个服务接口实现.通常根据服务宿主的不同,有两种创建方式. (1)创建WCF应用程序 通过创建WCF服务应用程序 ...

  3. WCF服务端调用client.

    wcf服务端 1,新建一个"windows窗口程序"名称为WCFServer2. 2.然后加入一个"WCF服务"名称为Service1. 详细步骤为:解决方式试 ...

  4. 在Unity3D中连接WCF服务端

    服务端不多讲解,有一处需要改的地方.具体服务端请看WCF入门学习2-控制台做为宿主 建议实际项目不要拿去用,毕竟是mono不是原生.net.或许是个坑 由于Unity的mono版本问题不能直接用net ...

  5. WCF服务端行为的一些设置

    [ServiceBehavior( InstanceContextMode = InstanceContextMode.Single,   //表示所有的请求都用一个服务实例来处理 Concurren ...

  6. WCF服务端与客户端时间匹配问题

    当服务端部署的WCF服务服务在被客户机调用时,如果显示: 错误,展开后,详细错误为:An error occurred when verifying security for the message ...

  7. WCF服务端返回:(413) Request Entity Too Large

    出现这个原因我们应该都能猜测到,文件传出过大,超出了WCF默认范围,那么我们需要进行修改. 服务端和客户端都需要修改. 第一.客户端: <system.serviceModel> < ...

  8. WCF服务端的.NET Core支持项目Core WCF 正式启动

    长期以来在wcf客户端库 https://github.com/dotnet/wcf 里反应最强烈的就是.NET Core的服务端支持 https://github.com/dotnet/wcf/is ...

  9. 保持WCF服务端与客户端的长连接

    背景 客户端与服务端使用WCF建立连接后:1.可能长时间不对话(调用服务操作):2.客户端的网络不稳定. 为服务端与客户端两边都写“心跳检测”代码?不愿意. 解决 设置inactivityTimeou ...

随机推荐

  1. 用Unicode迎接未来

         项目中使用了emoji,然后,问题产生了,后端MySQL数据库无法存储emoji字符,悲了个剧.      emoji是Unicode字符集的子集,Unicode的使用应该非常普遍了,怎么会 ...

  2. HTTPS抓包配置

    以Charles为例 配置Charles抓取Https需要手机和PC分别进行配置. 步骤: 1.PC下载charles客户端,并安装. 2.charles客户端安装证书 注意证书安装需要保存在&quo ...

  3. 使用Django清理数据库中的数据

    数据库,数据清洗 问题叙述性说明:在系统我用在,因为历史和由于各种原因,原因记录的数据内的数据库表,有一个问题,有反复和不完整的数据 解:首先.由于数据量还是挺大的,工的清理肯定不行, 然后,我就想写 ...

  4. MLAPP——概率机器学习知识汇总

    <机器学习>课程使用Kevin P. Murphy图书<Machine Learning A Probabilistic Perspective>本英语教材,本书从一个独特的数 ...

  5. ZOJ 1649:Rescue(BFS)

    Rescue Time Limit: 2 Seconds      Memory Limit: 65536 KB Angel was caught by the MOLIGPY! He was put ...

  6. Prototype and Constructor in JavaScript

    The concept of prototype in JavaScript is very confusing, especially to those who come with a C++/JA ...

  7. 使用CNN(convolutional neural nets)关键的一点是检测到的面部教程(四):学习率,学习潜能,dropout

    第七部分 让 学习率 和 学习潜能 随时间的变化 光训练就花了一个小时的时间.等结果并非一个令人心情愉快的事情.这一部分.我们将讨论将两个技巧结合让网络训练的更快! 直觉上的解决的方法是,開始训练时取 ...

  8. Codeforces 10C Digital Root 法冠军

    主题链接:点击打开链接 #include<stdio.h> #include<iostream> #include<string.h> #include<se ...

  9. Func和Action的用法区别

    平时我们如果要用到委托一般都是先声明一个委托类型,比如: private delegate string Say(); string说明适用于这个委托的方法的返回类型是string类型,委托名Say后 ...

  10. iOS开发- &quot;duplicate symbol for architecture i386&quot; 解决的方法

    今天整合项目的时候, 遇到了这样一个问题. duplicate symbol _flag in: /Users/apple/Library/Developer/Xcode/DerivedData/bl ...