根据拦截和返回值自动重试客户端WCF调用

时间:2011-11-05 19:19:27

标签: c# wcf

是否可以拦截WCF调用的结果并重试该操作?

例如,操作的返回值可能包含一个状态代码,指示我传入原始调用的会话令牌已过期。在这种情况下,我可以检索新的会话令牌,并使用新的会话令牌重试该呼叫。

是否可以通过使用WCF拦截返回值,检查它,然后完全透明地向操作调用者重试调用来执行此重试操作?

我已经知道如何使用IParameterInspector检查呼叫,但此时没有内置方法可以重试呼叫。

我正在寻找一种使用纯拦截的方法,以便它对客户端完全透明。

3 个答案:

答案 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.ContractClientTypehttp://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,以防你有多次拦截。 您可以管理呼叫处理程序的顺序,以确保这是链中的最后一个。