Behaviors in WCF are so stinking useful, and once you get past the basics of WCF they're arguably a necessity. Microsoft has saved itself from hundreds of hours of cursing by including the ability to define custom behaviors.

My favorite use of behaviors is addressing some cross cutting concerns that we consistently have in our WCF services. Specifically logging, service registration, wsdl tweaking, and error handling. Which brings us around to the IErrorHandler interface.

Implementing IErrorHandler "Allows an implementer to control the fault message returned to the caller and optionally perform custom error processing such as logging". Thank you MSDN. IErrorHandler has two methods to implement: HandleError, and ProvideFault. Implement them so that they do what they say they do. HandleError should do something with the error (in our case, we log it) and ProvideFault should return a fault message.

#region IErrorHandler Members

// HandleError. Log an error, then allow the error to be handled as usual.

// Return true if the error is considered as already handled

public bool HandleError(Exception error)

{

    try

    {

        \\our loggin service

        LoggerClient logger = new LoggerClient(basic, logAddress);

       \\build log message

        StringBuilder err = new StringBuilder();

        err.AppendLine("Source: " + error.Source);

        err.AppendLine("Target: " + error.TargetSite.ToString());

        err.AppendLine("Message: " + error.Message);

        err.AppendLine("Stack Trace: " + error.StackTrace.ToString());

        CustomLogEntry log = new CustomLogEntry();

        log.AppDomainName = AppDomain.CurrentDomain.FriendlyName;

        log.EventId = 900;

        log.EventIdSpecified = true;

        log.MachineName = Environment.MachineName;

        log.Message = err.ToString();

        log.Priority = 1;

        log.PrioritySpecified = true;

        log.Severity = TraceEventType.Error;

        log.SeveritySpecified = true;

        log.Title = "Exception Caught: " + error.Message;

        logger.Log(log);

        return true;

    }

    catch (Exception)

    {

        throw new Exception("error in the handler");

    }

}

public void ProvideFault(Exception error, System.ServiceModel.Channels.MessageVersion version, ref System.ServiceModel.Channels.Message fault)

{

    // Shield the unknown exception

    FaultException faultException = new FaultException(error.Message);

    MessageFault messageFault = faultException.CreateMessageFault();

    fault = Message.CreateMessage(version, messageFault, faultException.Action);

}

#endregion

Pretty straight forward.

Now we just have to figure out a way to get this to apply to our service, preferably without a lot of extra work.  So we don't want to go mucking around with attributes or anything else we have to remember to stick in as we're writing the code. That's where behaviors come in. You can apply them via the config file.

We know we want this particular behavior to apply to our entire service, so we want to implement IServiceBehavior in our class along with IErrorHandler. IServiceBehavior has four methods that we have to implement, but fortunately we can ignore three of them.  The one we care about in this case is ApplyDispatchBehavior, where we will apply our error handler to each of the channels in the service. In the example below ErrorHandler is the name of the class we are implementing. Inventive name, isn't it?

public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)

{
IErrorHandler errorHandler = new ErrorHandler(); foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = channelDispatcherBase as ChannelDispatcher;
channelDispatcher.ErrorHandlers.Add(errorHandler);
}
}

Great, that's done. Now there's only one thing left to do. We need a class that inherits from BehaviorExtensionElement so that we can add our behavior via configuration. Fortunately BehaviorExtensionElement is a breeze to implement. You need to impelement BehaviorType which just returns the type of your just implement IServiceBehavior class (ErrorHandler above), and CreateBehavior which returns an instantiation of the class.

class ErrorHandlerBehavior : BehaviorExtensionElement
{
public override Type BehaviorType
{
get
{
return typeof(ErrorHandler);
}
} protected override object CreateBehavior()
{
return new ErrorHandler();
}
}

Now the code is done.  The last thing to do is to apply the newly created behavior in the config file. Add our new BehaviorExtensionElement to the behaviorExtensions section, and then specify it in the serviceBehaviors section. One important caveat, if includeExceptionDetailInFaults is set to true, then the exception shielding (and I believe Error Handling) will not work.

<system.serviceModel>
<extensions>
<behaviorExtensions>
<add name="ErrorLogging" type="ErrorHandlerBehavior, ErrorHandling, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8746502a48718374" />
</behaviorExtensions>
</extensions>
<bindings>
<basicHttpBinding>
<binding name="basicBinding">
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="Service1Behavior" name="Service">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration="basicBinding" contract="Service" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="Service1Behavior">
<serviceMetadata httpGetUrl="" httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="false" />
<ErrorLogging />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

There you go. Apply this to all of your WCF services and you won't have to re-invent the wheel again.

Useful WCF Behaviors - IErrorHandler的更多相关文章

  1. Wcf实现IServiceBehavior拓展机制

    IServiceBehavior接口 描述:提供一种在整个服务内修改或插入自定义拓展机制: 命名空间:  System.ServiceModel.Description程序集:  System.Ser ...

  2. BizTalk 开发系列(四十) BizTalk WCF-SQL Adapter读取SQL Service Broker消息

    SQL Service Broker 是在SQL Server 2005中新增的功能.Service Broker 为 SQL Server 提供队列和可靠的消息传递,可以可用来建立以异步消息为基础的 ...

  3. 在web.config里使用configSource分隔各类配置

    转:http://www.yongfa365.com/Item/using-configSource-Split-Configs.html 大型项目中,可能有多个Service,也就是会有一堆配置,而 ...

  4. 【WCF】自定义错误处理(IErrorHandler接口的用法)

    当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端.在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1.Action:在服务调 ...

  5. WCF扩展系列 - 行为扩展(Behaviors)

    原文地址:http://www.cnblogs.com/Creator/archive/2011/05/21/2052687.html 这个系列的第一部分将会重点关注WCF行为(behaviors), ...

  6. 【WCF】错误处理(四):一刀切——IErrorHandler

    前面几篇烂文中所介绍到的错误方式,都是在操作协定的实现代码中抛出 FaultException 或者带泛型参数的detail方案,有些时候,错误的处理方法比较相似,可是要每个操作协定去处理,似乎也太麻 ...

  7. 利用Attribute和IErrorHandler处理WCF全局异常

    在处理WCF异常的时候,有大概几种方式: 第一种是在配置文件中,将includeExceptionDetailInFaults设置为true <behavior name="servi ...

  8. 【转】WCF扩展系列 - 行为扩展(Behaviors)

    原文:https://www.cnblogs.com/Creator/archive/2011/05/21/2052687.html 这个系列的第一部分将会重点关注WCF行为(behaviors),W ...

  9. WCF入门(22)

    前言 本还想写一集WCF入门教程的,心情实在不好,明天又还有面试,改天再写吧. 说一下今天遇到的入职坑.面试能坑,上班能坑,完全没想到入职也能坑.切身经历. 今年10月份想换工作,更新了一下简历,接到 ...

随机推荐

  1. 解决centos被minerd挖矿程序入侵方法

    记录一次服务器被入侵的解决方法 一:问题说明 1.我的服务器是使用的阿里云的CentOS,收到的阿里云发来的提示邮件如下 然后我查看了运行的进程情况(top 命令),看到一个名为minerd的进程占用 ...

  2. 理解restful 架构 && RESTful API设计指南

    restful是前端和后端接口中都会使用的设计思想. 网站即软件,我们也常说的webapp,这种互联网软件采用的是“客户端/服务器”模式,建立在分布式体系上. 网站开发,也可以完全采用软件开发的模式, ...

  3. Oracle Net Configuration(监听程序和网络服务配置)

    1.在Oracle服务端和客户端都安装完之后,就需要配置监听程序和本地网络服务,以便外部程序和工具的访问,所以Oracle提供了两款自带的工具来配置它们分别是 Net Configuration.Ne ...

  4. CoreJava笔记之线程

    程序,进程和线程程序:没有执行的指令序列和相关的数据的集合(如:qq.exe) 如:磁盘上的可执行命令进程:正在执行的程序,进程占用资源(CPU,Memoary,IO)线程:是进程中并发执行的过程(共 ...

  5. MySQL按照月进行统计

    MySQL按照月进行统计 今天需要后台提供一个按月统计的API.所以查了一下SQL语句的实现方法. 按月统计SQL select date_format(createtime, '%Y-%m') as ...

  6. [H5表单]一些html5表单知识及EventUtil对象完善

    紧接着上面的文章,一开始准备一篇文章搞定,后来看到,要总结的东西还不少,干脆,把上面文章拆成两部分吧,这部分主要讲讲表单知识! 表单知识 1.Html5的autofocus属性. 有个这个属性,我们不 ...

  7. 深入理解JavaScript系列(42):设计模式之原型模式

    介绍 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象. 正文 对于原型模式,我们可以利用JavaScript特有的原型继承特性去创建对象的方式,也就是 ...

  8. 很小的一个函数执行时间调试器Timer

    对于函数的执行性能(这里主要考虑执行时间,所耗内存暂不考虑),这里写了一个简单的类Timer,用于量化函数执行所耗时间. 整体思路很简单,就是new Date()的时间差值.我仅仅了做了一层简单的封装 ...

  9. 修改npm包管理器的registry为淘宝镜像(npm.taobao.org)<转>

    起因 安装了node,安装了npm之后,官方的源实在是 太慢了! 看了看淘宝的npm镜像,  http://npm.taobao.org/ 竟然说让我再下载一个cnpm,要不然就每次都得install ...

  10. MySQL:ERROR 2003 (HY000): Can't connect to MySQL server on 'localhost' (10061)

    错误 原因:可能是服务没有启动 以管理员身份打开cmd 输入 net start mysql