10

我正在寻找一种干净的方式ChannelFactory为我创建通道,并能够在使用后处理它们。
这就是我得到的:

public class ClientFactory : IClientFactory
{
    private const string endpointName = "IMyService";
    private readonly ChannelFactory<IMyService> _factory;

    public ClientFactory()
    {
        _factory = new ChannelFactory<IMyService>(endpointName);
    }

    public Client<IMyService> GetClient()
    {       
        IMyService channel = _factory.CreateChannel();
        return new Client<IMyService>(channel);
    }
}

public class Client<T> : IDisposable
{
    public T Channel { get; private set; }

    public Client(T channel)
    {
        if (channel == null)
            throw new ArgumentException("channel");

        Channel = channel;
    }

    public void Dispose()
    {
        (Channel as IDisposable).Dispose();
    }
}

//usage
using (var client = _serviceFactory.GetClient())
{
    client.Channel.DoStuff();
}

这是一个好的解决方案吗?
有没有更清洁的方法来做到这一点?

4

2 回答 2

8

不,没有更清洁的方法来包装频道。

另一种方法是使用 Action/Func 代替。它不干净,但可能更适合您的应用程序。

我就是这样做的:

internal class WrappedClient<T, TResult> : IDisposable
{
    private readonly ChannelFactory<T> _factory;
    private readonly object _channelLock = new object();
    private T _wrappedChannel;

    public WrappedClient(ChannelFactory<T> factory)
    {
        _factory = factory;
    }

    protected T WrappedChannel
    {
        get
        {
            lock (_channelLock)
            {
                if (!Equals(_wrappedChannel, default(T)))
                {
                    var state = ((ICommunicationObject)_wrappedChannel).State;
                    if (state == CommunicationState.Faulted)
                    {
                        // channel has been faulted, we want to create a new one so clear it
                        _wrappedChannel = default(T);
                    }
                }

                if (Equals(_wrappedChannel, default(T)))
                {
                    _wrappedChannel = _factory.CreateChannel();
                }
            }

            return _wrappedChannel;
        }
    }

    public TResult Invoke(Func<T, TResult> func)
    {
        try
        {
            return func(WrappedChannel);
        }
        catch (FaultException)
        {
            throw;
        }
        catch (CommunicationException)
        {
            // maybe retry works
            return func(WrappedChannel);
        }
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposing ||
            Equals(_wrappedChannel, default(T)))
            return;

        var channel = _wrappedChannel as ICommunicationObject;
        _wrappedChannel = default(T);
        try
        {
            channel.Close();
        }
        catch (CommunicationException)
        {
            channel.Abort();
        }
        catch (TimeoutException)
        {
            channel.Abort();
        }
    }

    public void Dispose()
    {
        Dispose(true);
    }
}

然后你像这样使用服务

client.Invoke(channel => channel.DoStuff())
于 2013-03-05T12:58:06.653 回答
2

做这样的事情:

public interface IMyServiceClient : IMyService, ICommunicationObject { }

如果您为此创建一个通道,则可以将其丢弃。

于 2013-03-05T12:10:42.710 回答