Useful WCF Behaviors - IErrorHandler

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.

时间: 2024-10-10 12:18:12

Useful WCF Behaviors - IErrorHandler的相关文章

收藏2篇关于WCF异常处理的文章

WCF Extensibility – IErrorHandler Exception Handling in WCF Web Service收藏2篇关于WCF异常处理的文章,码迷,mamicode.com

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

SQL Service Broker 是在SQL Server 2005中新增的功能.Service Broker 为 SQL Server 提供队列和可靠的消息传递,可以可用来建立以异步消息为基础的应用.当然从题目大家可能也看出来了.我们本文主要不是为了讲SQL Service Broker(SSB),而是讲一下如何使用BizTalk WCF-SQL Adapter来访问SSB的数据. SQL Service Broker(SSB) 为要便于大家更好的接下来的示例,我们还是概况的讲一下SSB的

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

当被调用的服务操作发生异常时,可以直接把异常的原始内容传回给客户端.在WCF中,服务器传回客户端的异常,通常会使用 FaultException,该异常由这么几个东东组成: 1.Action:在服务调用中,action标头比较重要,它是塞在SOAP消息的Headers元素下面的,是消息头的一部分,action用来对服务操作进行定义的.用小学生能听懂的话说,就是某个服务操作的“学号”,通道层在消息调度时,会根据它来寻找要调用的Operation.记得老周举过例子,就好比你去王老板家里,你得知道王老

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

前面几篇烂文中所介绍到的错误方式,都是在操作协定的实现代码中抛出 FaultException 或者带泛型参数的detail方案,有些时候,错误的处理方法比较相似,可是要每个操作协定去处理,似乎也太麻烦,此时就应当考虑统一处理了. 在 System.ServiceModel.Dispatcher 命名空间下,有一个 IErrorHandler 接口,这个接口就是让我们统一处理错误的. 先来认识一下这个接口. public interface IErrorHandler { bool Handle

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

在处理WCF异常的时候,有大概几种方式: 第一种是在配置文件中,将includeExceptionDetailInFaults设置为true <behavior name="serviceDebuBehavior"><serviceDebug includeExceptionDetailInFaults="true" /></behavior> 但是这种方式会导致敏感信息泄漏的危险,一般我们仅仅在调试的时候才开启该属性,如果已经发

WCF Extensibility

Over the next months I intend on writing a series of posts about the (many) extensibility points from WCF (up to .NET Framework 4.0). The cadence should be around one new post every 1-2 weeks (depending on the workload I have at work). WCF is a very

WCF拦截

WCF经常会有一些性能检测,全局异常,跨域设置,动态路由设置等,可以通过以下类实现 (1)拦截类,可以实现性能检测和全局异常处理 /// <summary> /// 使用消息提取的对象以及参数数组,并利用对该对象调用方法,然后返回该方法的返回值和输出参数 /// </summary> public class OperationInvoker : IOperationInvoker { private string _operationMethod;//方法名称 private I

how to do error handing with WCF by using attributes to log your errors z

There are multiple ways to do error handling in WCF as listed by Pedram Rezaei Blog. The default way that WCF allows errors message to display is by setting IncludeExceptionDetailInFaults Property to true in web.config or on the service attribute but

WCF服务部署到IIS7.5

下面介绍如何把WCF服务部署到IIS: 为WCF服务创建.svc文件 我们知道,每一个ASP.NET Web服务都具有一个.asmx文本文件,客户端通过访问.asmx文件实现对相应Web服务的调用.与之类似,每个WCF服务也具有一个对应的文本文 件,其文件扩展名为.svc.基于IIS的服务寄宿要求相应的WCF服务具有相应的.svc文件,.svc文件部署于IIS站点中,对WCF服务的调用体 现在对.svc文件的访问上. .svc文件的内容很简单,仅仅包含一个ServiceHost指令(Direct