Extending WCF(四)—一个统一处理异常、日志的解决方案

在实际的应用程序中,可能经常会遇到在Service端如何统一处理异常,记Log等的问题。这些问题可能很多AOP框架已经给出了解决方案。其实对于WCF来说简单的做一下扩展就可以解决这个问题了。
由于处理异常,记日志主要针对的是Operation级别,所以我选择的扩展点是IOperationInvoker接口,这个接口提供在Operation调用时的拦截。先看一下它的定义:

public interface IOperationInvoker
{
// Methods
object[] AllocateInputs();
object Invoke(object instance, object[] inputs, out object[] outputs);
IAsyncResult InvokeBegin(
object instance, object[] inputs, AsyncCallback callback, object state);
object InvokeEnd(object instance, out object[] outputs, IAsyncResult result);

// Properties
bool IsSynchronous { get; }
}

它提供了同步和异步调用Operation的方法。调用Operation的过程当然还是由WCF本身来完成,我们要做的就是在调用前和调用后来做日志和处理异常。下面是我的实现类:

public class MyInvoker : IOperationInvoker
{
IOperationInvoker m_OldInvoker;
InterceptionType m_InteType;

public MyInvoker(IOperationInvoker oldInvoker, InterceptionType inteType)
{
Debug.Assert(oldInvoker
!= null);

m_OldInvoker
= oldInvoker;
m_InteType
= inteType;
}

public virtual object[] AllocateInputs()
{
return m_OldInvoker.AllocateInputs();
}


protected void PreInvoke(object instance, object[] inputs)
{
if (m_InteType == InterceptionType.None)
{
}

else if (m_InteType == InterceptionType.LogInvoke)
{
}


}


protected void PostInvoke(object instance, object returnedValue, object[] outputs, Exception err)
{
if (m_InteType == InterceptionType.None)
{
}

else if (m_InteType == InterceptionType.LogInvoke)
{
}

else if (m_InteType == InterceptionType.LogException)
{
}

else if (m_InteType == InterceptionType.LogExceptionAndMail)
{
}

}


public object Invoke(object instance, object[] inputs, out object[] outputs)
{
PreInvoke(instance, inputs);
object returnedValue = null;
object[] outputParams = new object[] { };
Exception exception
= null;
try
{
returnedValue
= m_OldInvoker.Invoke(instance, inputs, out outputParams);
outputs
= outputParams;
return returnedValue;
}

catch (Exception err)
{
outputs
= null;
exception
= err;
return null;
}

finally
{
PostInvoke(instance, returnedValue, outputParams, exception);

}

}


public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state)
{
PreInvoke(instance, inputs);
return m_OldInvoker.InvokeBegin(instance, inputs, callback, state);
}


public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result)
{
object returnedValue = null;
object[] outputParams = { };
Exception exception
= null;
try
{
returnedValue
= m_OldInvoker.InvokeEnd(instance, out outputs, result);
outputs
= outputParams;
return returnedValue;
}

catch (Exception err)
{
outputs
= null;
exception
= err;
return null;
}

finally
{
PostInvoke(instance, returnedValue, outputParams, exception);
}

}

public bool IsSynchronous
{
get
{
return m_OldInvoker.IsSynchronous;
}

}

}

在PreInvoke和PostInvoke方法中可以加入我们自己的代码。InterceptionType是一个枚举,里面定义了拦截的类型:

public enum InterceptionType
{
None,

LogInvoke,

LogException,

LogExceptionAndMail
}
这个枚举可以根据需要来进行扩展。如何让WCF使用我们自己的这个OperationInvoker呢,可以通过加入Operation Behavior来完成:
[AttributeUsage(AttributeTargets.Method)]
public class MyOperationInterceptorAttribute : Attribute, IOperationBehavior
{
private InterceptionType m_InteType = InterceptionType.None;

public MyOperationInterceptorAttribute() { }

public MyOperationInterceptorAttribute(InterceptionType inteType)
{
this.m_InteType = inteType;
}


protected MyInvoker CreateInvoker(IOperationInvoker oldInvoker)
{
return new MyInvoker(oldInvoker, m_InteType);
}


public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
{ }

public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
{ }

public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
IOperationInvoker oldInvoker
= dispatchOperation.Invoker;
dispatchOperation.Invoker
= CreateInvoker(oldInvoker);
}


public void Validate(OperationDescription operationDescription)
{ }
}
在ApplyDispatchBehavior中换掉原来的Invoker就可以了。所以我们只要在Operation上打上这个标签就可以了,并且在打标签的同时可以指定拦截的类型。
这样可能还比较麻烦,因为我要挨个方法都去打上标签,那么我们可以往更高层次的Behavior去扩展。这里可以使用Service Behavior:
[AttributeUsage(AttributeTargets.Class)]
public class MyServiceInterceptorAttribute : Attribute,IServiceBehavior
{
protected MyOperationInterceptorAttribute CreateOperationInterceptor()
{
return new MyOperationInterceptorAttribute();
}


public void ApplyDispatchBehavior(ServiceDescription serviceDescription,ServiceHostBase host)
{
foreach(ServiceEndpoint endpoint in serviceDescription.Endpoints)
{
foreach(OperationDescription operation in endpoint.Contract.Operations)
{
bool checkresult = false;
foreach (IOperationBehavior behavior in operation.Behaviors)
{
if (behavior is MyOperationInterceptorAttribute)
{
checkresult
= true;
break;
}

}

if (!checkresult)
{
operation.Behaviors.Add(CreateOperationInterceptor());
}

}

}

}

public void AddBindingParameters(ServiceDescription serviceDescription,ServiceHostBase serviceHostBase,Collection<ServiceEndpoint> endpoints,BindingParameterCollection bindingParameters)
{}

public void Validate(ServiceDescription serviceDescription,ServiceHostBase serviceHostBase)
{}
}
}
ApplyDispatchBehavior这个方法中会去给没有打上标签的Operation都打上标签。所以我们只需要给Service打个标签就可以了。

通过这个简单的实例,我们就可以对Operation级别的异常和日志进行统一的处理了,代码中的try catch和记录日志的代码就可以通通省去了。 

http://www.cnblogs.com/yunkunyang/archive/2008/05/23/1205923.html
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值