WCF 客户端“使用"块问题的最佳解决方法是什么? [英] What is the best workaround for the WCF client `using` block issue?

查看:28
本文介绍了WCF 客户端“使用"块问题的最佳解决方法是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我喜欢在 using 块中实例化我的 WCF 服务客户端,因为这几乎是使用实现 IDisposable 的资源的标准方式:

I like instantiating my WCF service clients within a using block as it's pretty much the standard way to use resources that implement IDisposable:

using (var client = new SomeWCFServiceClient()) 
{
    //Do something with the client 
}

但是,如这篇 MSDN 文章所述,包装了一个using 块中的 WCF 客户端可以屏蔽导致客户端处于故障状态(如超时或通信问题)的任何错误.长话短说,当调用 Dispose() 时,客户端的 Close() 方法会触发,但会抛出错误,因为它处于错误状态.然后原始异常被第二个异常屏蔽.不好.

But, as noted in this MSDN article, wrapping a WCF client in a using block could mask any errors that result in the client being left in a faulted state (like a timeout or communication problem). Long story short, when Dispose() is called, the client's Close() method fires, but throws an error because it's in a faulted state. The original exception is then masked by the second exception. Not good.

MSDN 文章中建议的解决方法是完全避免使用 using 块,而是实例化您的客户端并像这样使用它们:

The suggested workaround in the MSDN article is to completely avoid using a using block, and to instead instantiate your clients and use them something like this:

try
{
    ...
    client.Close();
}
catch (CommunicationException e)
{
    ...
    client.Abort();
}
catch (TimeoutException e)
{
    ...
    client.Abort();
}
catch (Exception e)
{
    ...
    client.Abort();
    throw;
}

using 块相比,我认为这很丑陋.每次需要客户端时都要编写大量代码.

Compared to the using block, I think that's ugly. And a lot of code to write each time you need a client.

幸运的是,我找到了其他一些解决方法,例如(现已不存在的)IServiceOriented 博客上的这个.你开始:

Luckily, I found a few other workarounds, such as this one on the (now defunct) IServiceOriented blog. You start with:

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 块那样具有表现力和易于理解.

That's not bad, but I don't think it's as expressive and easily understandable as the using block.

我目前尝试使用的解决方法我首先在 blog.davidbarret 上阅读.net.基本上,无论您在哪里使用它,都可以覆盖客户端的 Dispose() 方法.类似的东西:

The workaround I'm currently trying to use I first read about on blog.davidbarret.net. Basically, you override the client's Dispose() method wherever you use it. Something like:

public partial class SomeWCFServiceClient : IDisposable
{
    void IDisposable.Dispose() 
    {
        if (this.State == CommunicationState.Faulted) 
        {
            this.Abort();
        } 
        else 
        {
            this.Close();
        }
    }
}

这似乎能够再次允许 using 块,而不会掩盖错误状态异常的危险.

This appears to be able to allow the using block again without the danger of masking a faulted state exception.

那么,在使用这些变通方法时,我还需要注意其他问题吗?有没有人想出更好的办法?

So, are there any other gotchas I have to look out for using these workarounds? Has anybody come up with anything better?

推荐答案

其实,虽然我 博客(见卢克的回答),我认为 这个 比我的 IDisposable 包装器更好.典型代码:

Actually, although I blogged (see Luke's answer), I think this is better than my IDisposable wrapper. Typical code:

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

<小时>

(按评论编辑)


(edit per comments)

由于 Use 返回 void,因此处理返回值的最简单方法是通过捕获的变量:

Since Use returns void, the easiest way to handle return values is via a captured variable:

int newOrderId = 0; // need a value for definite assignment
Service<IOrderService>.Use(orderService=>
  {
    newOrderId = orderService.PlaceOrder(request);
  });
Console.WriteLine(newOrderId); // should be updated

这篇关于WCF 客户端“使用"块问题的最佳解决方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆