Мне нравится создавать экземпляры моих клиентов службы WCF в блоке using
, поскольку это в значительной степени стандартный способ использования ресурсов, реализующих IDisposable
:
using (var client = new SomeWCFServiceClient())
{
//Do something with the client
}
Но, как отмечалось в этой статье MSDN , упаковка клиента WCF в блок using
может маскировать любые ошибки, которые приводят к тому, что клиент остается в неисправном состоянии (например, тайм-аут или проблема со связью). ). Короче говоря, когда вызывается Dispose (), клиентский метод Close () запускается, но выдает ошибку, потому что он находится в неисправном состоянии. Исходное исключение затем маскируется вторым исключением. Не хорошо.
Предложенный обходной путь в статье MSDN состоит в том, чтобы полностью избежать использования блока using
, а вместо этого создавать экземпляры ваших клиентов и использовать их примерно так:
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
По сравнению с блоком using
, я думаю, это ужасно. И много кода, чтобы писать каждый раз, когда вам нужен клиент.
К счастью, я нашел несколько других обходных путей, таких как этот, в IServiceOriented. Вы начинаете с:
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)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
Что позволяет:
Service<IOrderService>.Use(orderService =>
{
orderService.PlaceOrder(request);
});
Это неплохо, но я не думаю, что это так выразительно и легко понятно, как блок using
.
Обходной путь, который я сейчас пытаюсь использовать, о котором я впервые прочитал на blog.davidbarret.net . По сути, вы переопределяете метод клиента Dispose()
везде, где вы его используете. Что-то вроде:
public partial class SomeWCFServiceClient : IDisposable
{
void IDisposable.Dispose()
{
if (this.State == CommunicationState.Faulted)
{
this.Abort();
}
else
{
this.Close();
}
}
}
Похоже, что можно снова разрешить блок using
без опасности замаскировать исключение состояния ошибки.
Итак, есть ли какие-то другие ошибки, которые я должен обратить внимание на использование этих обходных путей? Кто-нибудь придумал что-нибудь лучше?