2013-03-05 12 views
8

Ich suche eine saubere Art und Weise die zu haben Channel Kanäle für mich schaffen mit der Fähigkeit, sie nach Gebrauch zu entsorgen.
Das ist, was ich habe:Entsorgen Playlist erstellt von WCF Channel

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

Ist das eine gute Lösung?
Gibt es sauberere Möglichkeiten, dies zu tun?

+0

Sie den Kanal so nicht entsorgen. Verwenden Sie: {channel.Close(); } catch (CommunicationException) {channel.Abort(); } catch (TimeoutException) {channel.Abort(); } – adrianm

+0

Wie kommt es? Gibt es nicht den gleichen Kanal für mich? – David

+1

Dispose wird Close aufrufen. Close könnte werfen. Schreibe alle deine using-Anweisungen als: try {using (...) {...}} catch (CommunicationException) {} oder benutze mein Muster oben. – adrianm

Antwort

7

Nein, es gibt keine sauberere Möglichkeit, den Kanal zu umhüllen.

Alternativ können Sie auch Action/Func verwenden. Es ist nicht sauberer, könnte aber für Ihre Anwendung besser geeignet sein.

Dies ist, wie ich es tun:

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

Dann nutzen Sie den Service wie

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

Ich denke, ich werde die Fabrik behalten, wie es ist, mit Ausnahme Ihres Vorschlags in den Kommentaren. – David

+0

@espo, danke für die Code-Bereinigung. Ich entfernte das '.?', Was ich für eine Fehlentscheidung hielt. – adrianm

2

so etwas tun:

public interface IMyServiceClient : IMyService, ICommunicationObject { } 

Wenn Sie einen Kanal für das schaffen, können Sie es entsorgen.

+0

Das würde jedoch eine neue Schnittstelle pro Dienst erfordern. Ich hätte gerne einen generischen, wiederverwendbaren Ansatz. – David

+0

Nun, es ist nur eine beschreibende Schnittstelle - es ist keine weitere Implementierung erforderlich. Sie werden es nicht kürzer, ich denke, – TGlatzer