2009-07-20 9 views
8

In einem der WCF-Tutorials, ich sah den folgenden Beispielcode:service.close() vs. service.abort() - WCF Beispiel

Dim service as ...(a WCF service) 

try 

    .. 

    service.close() 

catch ex as Exception() 
    ... 

    service.abort() 

end try 

Ist dies der richtige Weg, dass die Ressourcen, um sicherzustellen, (dh Verbindungen) werden auch unter Fehlerbedingungen freigegeben?

Antwort

4

Ich habe mit diesem Modell viel Glück hat:

Dim service As New MyService() 
Dim closed As Boolean = False 
Try 
    service.Open() 
    If Not service.State = ServiceModel.CommunicationState.Opened Then 
     ''Handle a not-opened state here 
    End If 
    service.MyMethod() 
    service.Close() 
    closed = true 
Catch ex As Exception 
    ''Handle errors here 
Finally 
    If Not closed Then 
     service.Abort() 
    End If 
End Try 
service = Nothing 
2

Sie die allgemeine Idee richtig haben. Ich habe die folgende Erweiterungsmethode verwendet, um die Zeilen wiederholten Codes auf ein Minimum zu beschränken.

public static class ICommunicationObjectExtensions 
{  
    public static void SafelyCloseConnection(this ICommunicationObject objectToClose) 
    { 
     bool success = false; 

     try 
     { 
     objectToClose.Close(); 
     success = true; 
     } 
     finally 
     { 
     if (!success) 
     { 
      objectToClose.Abort(); 
     } 
     } 
    } 
} 

Beispiel Code dieser Erweiterung Methode:

HelloWorldServiceClient client = new HelloWorldServiceClient(); 
HelloWorldDataContract dc = new HelloWorldDataContract(); 

try 
{ 
    client.Open(); 
    dc = client.SayHello(); 
} // Add catch blocks here for anything you want to handle. 
finally 
{ 
    client.SafelyCloseConnection(); 
} 

Natürlich ist die C#, aber ich denke, dass noch eine Hilfe sein soll.

15

See Indisposable: WCF Gotcha # 1 *, wo er mit einem praktischen Wrappermethode kommt:

public delegate void UseServiceDelegate<T>(T proxy); 

public static class Service<T> 
{ 
    public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>(""); 

    public static void Use(UseServiceDelegate<T> codeBlock) 
    { 
     var proxy = (IClientChannel)_channelFactory.CreateChannel(); 
     var success = false; 
     try 
     { 
      codeBlock((T)proxy); 
      proxy.Close(); 
      success = true; 
     } 
     finally 
     { 
      if (!success) 
      { 
       proxy.Abort(); 
      } 
     } 
    } 
} 

Verbrauch:

Service<IOrderService>.Use(
    orderService => 
     { 
      orderService.PlaceOrder(request); 
     }); 

* Link als es entfernt wird bösartig sein .

+0

ich Ihre Lösung mag, aber tun Sie eine haben, dass kann mit Dependency Injection verwendet werden. Da ein Service eine Abhängigkeit ist, möchte ich meinen Test dagegen nicht ausführen. –

+0

Es ist nicht meine Lösung. In jedem Fall erwarte ich, dass Sie 'Service ' nicht-statisch machen und die 'ChannelFactory ' oder den 'IClientChannel' injizieren können. –

0

Wenn Sie einen Client-Seite-Cache verwenden, können Sie mithilfe von Expression Trees betrachten (siehe http://thegrenade.blogspot.com/2009/07/using-expression-trees-for-more-elegant.html):

private static TEntity GetItem<TProxy, TEntity, TIdentity>(Expression<Func<TProxy, TIdentity, TEntity>> expression, TProxy proxy, TIdentity id) 
    where TEntity : class 
    where TProxy : ICommunicationObject 
{ 
    TEntity item = Cache.GetItem<TEntity, TIdentity>(id); 
    if (item == null) 
    { 
     try 
     { 
      var originalDelegate = expression.Compile(); 
      item = originalDelegate.Invoke(proxy, id); 
     } 
     finally 
     { 
      try{ proxy.Close(); } 
      finally { proxy.Abort(); } 
     } 
     Cache.AddItem<TEntity, TIdentity>(item); 
    } 
    return item; 
} 

Verbrauch:

Product p = GetItem((client, identifier) => client.GetProduct(identifier), new CatalogServiceClient(), 123); 
+0

Rob, ich sehe nicht, wie deine Antwort auf diese Frage zutrifft. –

+0

Vielleicht ist das Methodenbeispiel, das ich angegeben habe, etwas zu spezifisch für einen generischen Serviceaufruf-Wrapper. In der Tat benötigen Sie Methodenüberladungen für Dienstmethoden, die mehr als einen Parameter benötigen, und dieses Beispiel geht nicht so detailliert. Viele WCF-Lösungen enthalten jedoch Gruppen sehr ähnlicher Methoden, die als Antwort auf einen get-Wert mit einem id-Parameter einfach unterschiedliche Typen zurückgeben. Und du hast Recht, dass meinem finally block auch ein verschachtelter try fehlt/endlich zum abbrechen. – grenade

+0

Ich denke, Sie müssen die Frage vielleicht noch einmal lesen. Ihre Antwort behandelt die Frage in keiner Weise. –