service.close() vs. service.abort() - WCF example

2019-01-22 10:32发布

问题:

In one of the WCF tutorials, I saw the following sample code:

Dim service as ...(a WCF service )

try

   ..

   service.close()

catch ex as Exception()
  ... 

   service.abort()

end try

Is this the correct way to ensure that resources (i.e. connections) are released even under error conditions?

回答1:

I've had good luck with this model:

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:

See Indisposable: WCF Gotcha #1*, where he comes up with a convenient wrapper method:

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

Usage:

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

* Link removed as it appears to be malicious.



回答3:

You've got the general idea correct. I've used the following extension method to keep the lines of repetitive code to a 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();
         }
      }
   }
}

Example of code using this extension method:

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

Of course this is C#, but I think that should still be of help.



回答4:

If you use a client side cache, you might consider using Expression Trees (see 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;
}

Usage:

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