2009-07-20 4 views
8

Dans l'un des tutoriels WCF, j'ai vu le code exemple suivant:service.close() vs. service.abort() - WCF exemple

Dim service as ...(a WCF service) 

try 

    .. 

    service.close() 

catch ex as Exception() 
    ... 

    service.abort() 

end try 

Est-ce la bonne façon de faire en sorte que les ressources (c.-à- connexions) sont libérés même dans des conditions d'erreur?

Répondre

4

J'ai eu bonne chance avec ce modèle:

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

Vous avez l'idée générale correcte. J'ai utilisé la méthode d'extension suivante pour garder les lignes de code répétitif au minimum.

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

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

Exemple de code en utilisant cette méthode d'extension:

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

Bien sûr, cela est C#, mais je pense que cela devrait encore être utile.

15

Voir Indisposable: WCF Gotcha # 1 *, où il arrive avec une méthode d'emballage pratique:

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

Utilisation:

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

* Lien supprimé car il semble être malveillant .

+0

J'aime votre solution, mais avez-vous une, que peut être utilisé avec l'injection de dépendances. Comme un service est une dépendance, je ne veux pas exécuter mon test. –

+0

Ce n'est pas ma solution. Dans tous les cas, je m'attends à ce que vous puissiez rendre 'Service ' non statique, et injecter le 'ChannelFactory ', ou le 'IClientChannel'. –

0

Si vous utilisez un cache côté client, vous pouvez envisager d'utiliser les arbres d'expression (voir 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; 
} 

Utilisation:

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

Rob, je ne vois pas comment votre réponse s'applique à cette question. –

+0

Peut-être que l'exemple de méthode que j'ai donné est un peu trop spécifique pour un wrapper d'appel de service générique. En réalité, vous avez besoin de surcharges de méthodes pour les méthodes de service qui prennent plus d'un paramètre et cet exemple ne va pas dans ce détail. Cependant, de nombreuses solutions WCF contiennent des groupes de méthodes très similaires qui retournent simplement différents types en réponse à un get avec un paramètre id. Et vous avez raison de dire que mon bloc finally manque aussi un try imbriqué/finalement pour l'abandon. – grenade

+0

Je pense que vous devrez peut-être relire la question. Votre réponse ne répond pas à la question. –

Questions connexes