8

在其中一个 WCF 教程中,我看到了以下示例代码:

Dim service as ...(a WCF service )

try

   ..

   service.close()

catch ex as Exception()
  ... 

   service.abort()

end try

这是确保即使在错误条件下也能释放资源(即连接)的正确方法吗?

4

4 回答 4

15

请参阅 Indisposable: WCF Gotcha #1 *,他提出了一种方便的包装方法:

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

用法:

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

* 链接被删除,因为它似乎是恶意的。

于 2009-07-20T21:34:49.757 回答
4

我对这个模型很幸运:

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
于 2009-07-20T20:40:30.397 回答
2

你的总体思路是正确的。我使用了以下扩展方法来将重复代码行减至最少。

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

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

使用此扩展方法的代码示例:

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

当然这是 C#,但我认为这仍然会有所帮助。

于 2009-07-20T21:08:17.533 回答
0

如果您使用客户端缓存,您可能会考虑使用表达式树(请参阅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;
}

用法:

Product p = GetItem((client, identifier) => client.GetProduct(identifier), new CatalogServiceClient(), 123);
于 2009-07-21T14:04:46.447 回答