WCF重试代理如何实现?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (26)

我努力寻找实现WCF重试的最佳方式。我希望尽可能让客户体验变得干净。有两种方法我知道(见下文)。我的问题是:“ 我缺少第三种方法吗?也许这是普遍接受的方法吗?

方法#1:创建一个实现服务接口的代理。对于每个对代理的调用,执行重试。

public class Proxy : ISomeWcfServiceInterface
{
    public int Foo(int snurl)
    {
        return MakeWcfCall<int>(() => _channel.Foo(snurl));
    }

    public string Bar(string snuh)
    {
        return MakeWcfCall<string>(() => _channel.Bar(snuh));
    }

    private static T MakeWcfCall<T>(Func<T> func)
    {
        // Invoke the func and implement retries.
    }
}

方法2:将MakeWcfCall()(上面)更改为public,并让消费代码直接发送func。

我不喜欢的方法#1每次界面更改时都必须更新Proxy类。

我不喜欢的方法#2是客户不得不将他们的呼叫换成func。

我错过了一个更好的方法?

提问于
用户回答回答于

我已经完成了这种类型的事情,并使用.net的RealProxy类来解决这个问题。

使用RealProxy,可以使用提供的界面在运行时创建实际的代理。从调用代码看来,它们好像在使用一个IFoo通道,但实际上它是IFoo代理服务器,然后有机会拦截对任何方法,属性,构造函数等的调用。

派生自RealProxy,然后可以重写Invoke方法来拦截对WCF方法的调用并处理CommunicationException等。

用户回答回答于

首先,消费代码展示它的工作原理:

static void Main(string[] args)
{
    var channelFactory = new WcfChannelFactory<IPrestoService>(new NetTcpBinding());
    var endpointAddress = ConfigurationManager.AppSettings["endpointAddress"];

    // The call to CreateChannel() actually returns a proxy that can intercept calls to the
    // service. This is done so that the proxy can retry on communication failures.            
    IPrestoService prestoService = channelFactory.CreateChannel(new EndpointAddress(endpointAddress));

    Console.WriteLine("Enter some information to echo to the Presto service:");
    string message = Console.ReadLine();

    string returnMessage = prestoService.Echo(message);

    Console.WriteLine("Presto responds: {0}", returnMessage);

    Console.WriteLine("Press any key to stop the program.");
    Console.ReadKey();
}

WcfChannelFactory:

public class WcfChannelFactory<T> : ChannelFactory<T> where T : class
{
    public WcfChannelFactory(Binding binding) : base(binding) {}

    public T CreateBaseChannel()
    {
        return base.CreateChannel(this.Endpoint.Address, null);
    }

    public override T CreateChannel(EndpointAddress address, Uri via)
    {
        // This is where the magic happens. We don't really return a channel here;
        // we return WcfClientProxy.GetTransparentProxy(). That class will now
        // have the chance to intercept calls to the service.
        this.Endpoint.Address = address;            
        var proxy = new WcfClientProxy<T>(this);
        return proxy.GetTransparentProxy() as T;
    }
}

WcfClientProxy :(这是我们拦截和重试的地方)

    public class WcfClientProxy<T> : RealProxy where T : class
    {
        private WcfChannelFactory<T> _channelFactory;

        public WcfClientProxy(WcfChannelFactory<T> channelFactory) : base(typeof(T))
        {
            this._channelFactory = channelFactory;
        }

        public override IMessage Invoke(IMessage msg)
        {
            // When a service method gets called, we intercept it here and call it below with methodBase.Invoke().

            var methodCall = msg as IMethodCallMessage;
            var methodBase = methodCall.MethodBase;

            // We can't call CreateChannel() because that creates an instance of this class,
            // and we'd end up with a stack overflow. So, call CreateBaseChannel() to get the
            // actual service.
            T wcfService = this._channelFactory.CreateBaseChannel();

            try
            {
                var result = methodBase.Invoke(wcfService, methodCall.Args);

                return new ReturnMessage(
                      result, // Operation result
                      null, // Out arguments
                      0, // Out arguments count
                      methodCall.LogicalCallContext, // Call context
                      methodCall); // Original message
            }
            catch (FaultException)
            {
                // Need to specifically catch and rethrow FaultExceptions to bypass the CommunicationException catch.
                // This is needed to distinguish between Faults and underlying communication exceptions.
                throw;
            }
            catch (CommunicationException ex)
            {
                // Handle CommunicationException and implement retries here.
                throw new NotImplementedException();
            }            
        }
    }

代理拦截的呼叫序列图:

扫码关注云+社区