service.close() и service.abort() — пример WCF

В одном из руководств по WCF я увидел следующий пример кода:

Dim service as ...(a WCF service )

try

   ..

   service.close()

catch ex as Exception()
  ... 

   service.abort()

end try

Является ли это правильным способом гарантировать, что ресурсы (т. е. соединения) освобождаются даже в условиях ошибки?


person Larry Watanabe    schedule 20.07.2009    source источник


Ответы (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
person Chris Porter    schedule 20.07.2009

См. 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);
        });

* Ссылка удалена, так как кажется вредоносной.

person John Saunders    schedule 20.07.2009
comment
Мне нравится ваше решение, но есть ли у вас такое, которое можно использовать с внедрением зависимостей. Поскольку служба является зависимостью, я не хочу выполнять свой тест против нее. - person Preben Huybrechts; 10.10.2012
comment
Это не мое решение. В любом случае, я ожидаю, что вы можете сделать Service<T> нестатичным и внедрить ChannelFactory<T> или IClientChannel. - person John Saunders; 10.10.2012

У вас верная общая мысль. Я использовал следующий метод расширения, чтобы свести количество строк повторяющегося кода к минимуму.

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

Конечно, это С#, но я думаю, что это все равно должно помочь.

person Daniel Auger    schedule 20.07.2009

Если вы используете кеш на стороне клиента, вы можете рассмотреть возможность использования деревьев выражений (см. ="nofollow noreferrer">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);
person grenade    schedule 21.07.2009
comment
Роб, я не понимаю, как твой ответ относится к этому вопросу. - person John Saunders; 21.07.2009
comment
Возможно, приведенный пример метода слишком специфичен для универсальной оболочки вызова службы. На самом деле вам нужны перегрузки методов для методов службы, которые принимают более одного параметра, и в этом примере эти детали не рассматриваются. Однако многие решения WCF содержат группы очень похожих методов, которые просто возвращают разные типы в ответ на запрос get с параметром id. И вы правы, что в моем блоке finally также отсутствует вложенная попытка / finally для прерывания. - person grenade; 22.07.2009
comment
Я думаю, вам, возможно, придется прочитать вопрос еще раз. Ваш ответ никоим образом не касается вопроса. - person John Saunders; 13.03.2010