是否可以拦截WCF调用的结果并重试该操作?
例如,操作的返回值可能包含一个状态代码,指示我传入原始调用的会话令牌已过期。在这种情况下,我可以检索新的会话令牌,并使用新的会话令牌重试该呼叫。
是否可以通过使用WCF拦截返回值,检查它,然后完全透明地向操作调用者重试调用来执行此重试操作?
我已经知道如何使用IParameterInspector
检查呼叫,但此时没有内置方法可以重试呼叫。
我正在寻找一种使用纯拦截的方法,以便它对客户端完全透明。
答案 0 :(得分:3)
假设您希望在客户端进行此操作,那么您可以使用IClientMessageInspector
- 如果您想在服务器端实现此功能,则可以创建IDispatchMessageInspector
。
通过实现IClientMessageInspector
,您将检查AfterReceiveReply
event中的结果,如果需要重试,则可以启动重试...当呼叫回来时,您只需“覆盖”结果让你重新尝试新的...这样操作调用者甚至没有注意到任何东西(除了调用有时需要更长的时间)。
虽然您必须小心执行重试功能(可能需要重新处理可能的重入问题)。
对于某些示例代码(没有重试本身),请参阅http://weblogs.asp.net/paolopia/archive/2007/08/23/writing-a-wcf-message-inspector.aspx
编辑 - 根据评论:
如何实现重试操作取决于几个方面。
基本上,您需要将对请求消息的呼叫和请求消息关联到重播消息。
您可以通过实现IClientMessageFormatter.SerializeRequest
OR IParameterInspector
来实现此目的 - 这将允许您记录调用了哪些参数的方法以及框架为其创建的Message对象。< / p>
通过实施IClientMessageInspector.BeforeSendRequest
,您可以分配一个唯一的correlationState
,这样您就可以在IClientMessageInspector.AfterReceiveReply
的实施中关联回复消息,因为框架会将您的实施作为第二个参数。
从那里你可以使用Reflection来重试呼叫(所有需要的信息都可用,因为你在IClientMessageFormatter
和/或IParameterInspector
实现中记录了类型和方法以及参数)并覆盖了回复新回复的消息。
另一个(也许更容易)选项是实现一个自定义WCF客户端类并为调用者提供...这使您可以留在不同检查员等的整个混乱之外,并且可以对任何人进行更直接的控制。操作叫做。
编辑2 - 根据评论:
在实施IClientMessageInspector
时,您还必须实现IEndpointBehavior
,而ApplyClientBehavior
又有一个方法endpoint.Contract.ContractType
,WCF运行时调用该方法来添加IClientMessageInspector
。在该方法中,您实例化您的实现,该实现在构造函数中接受一个参数,而该参数又是clientRuntime.ContractClientType
或http://social.msdn.microsoft.com/Forums/en-US/wcf/thread/19500d14-78b7-4356-b817-fcc9abc2afcf/。您将此类型存储在检查器实例中...有关如何对此进行编码的提示,请参阅示例{{3}}
答案 1 :(得分:1)
您可以使用AOP框架。 Unity有足够的功能,或者您可以考虑使用“适当的”AOP框架,例如LinFu或PostSharp。
答案 2 :(得分:0)
我会使用unity interface / virtualmethod拦截。
_unityContainer.AddNewExtension<Interception>();
_unityContainer.RegisterType<ITestCaching, TestCaching>(
new Interceptor<InterfaceInterceptor>(),
new InterceptionBehavior<PolicyInjectionBehavior>());
_unityContainer.RegisterType<XRepository>(
new Interceptor<VirtualMethodInterceptor>(),
new InterceptionBehavior<PolicyInjectionBehavior>());
我使用策略注入行为,以便我可以使用Attributes添加其他行为。 拦截中涉及的自定义属性需要继承HandlerAttribute 并实施:
public override ICallHandler CreateHandler(IUnityContainer container)
{
return new RetryCallHandler(container, ConfigurationName);
}
该行为将在实现ICallHandler
的类中实现public class RetryCallHandler : ICallHandler, IDisposable
{
public IMethodReturn Invoke(IMethodInvocation args, GetNextInterceptionBehaviorDelegate getNext)
{
Exception exception = null;
int retryCounter = MAX_RETRIES;
do
{
exception = null;
try
{
var intercepted = getNext();
IMethodReturn methodReturn = intercepted(args, getNext);
return methodReturn;
}
catch (Exception ex)
{
exception = ex;
}
}while(exception!=null && retryCounter-- > 0);
return args.CreateExceptionMethodReturn(exception);
}
}
我没有编译或测试上面的代码。
我预见的唯一问题是GetNextInterceptionBehaviorDelegate,以防你有多次拦截。 您可以管理呼叫处理程序的顺序,以确保这是链中的最后一个。