简体   繁体   English

Dispose由WCF ChannelFactory创建的频道

[英]Dispose Channel created by WCF ChannelFactory

I'm looking for a clean way to have the ChannelFactory create channels for me with the ability to dispose them after use. 我正在寻找一种干净的方法ChannelFactory为我创建通道 ,并能够在使用后处理它们
This is what I got: 这就是我得到的:

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();
}

Is this a good solution? 这是一个好的解决方案吗?
Are there cleaner ways to do this? 有更干净的方法吗?

No, there is no cleaner way to wrap the channel. 不,没有更清洁的方式来包装频道。

Another way you can do it is to use Action/Func instead. 另一种方法是使用Action / Func代替。 It is not cleaner but might be more suitable for your application. 它不是更干净,但可能更适合您的应用。

This is how I do it: 我是这样做的:

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);
    }
}

Then you use the service like 然后你使用像这样的服务

client.Invoke(channel => channel.DoStuff())

Do something like that: 做那样的事情:

public interface IMyServiceClient : IMyService, ICommunicationObject { }

If you create a channel for that, you can dispose it. 如果您为此创建了一个频道,则可以对其进行处理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM