为WCF服务客户端实现IDisposable - 我这样做了吗?

时间:2017-02-24 16:21:03

标签: vb.net wcf

我想安全地处理我的WCF客户端,但我不确定我是否在正确的位置实现IDisposable。

我添加了代码以在我将WCF服务添加为服务引用时创建的Reference.vb文件中的服务客户端中实现IDisposable:

Partial Public Class Service1Client
Inherits System.ServiceModel.ClientBase(Of DataConversionService.IService1)
Implements DataConversionService.IService1, IDisposable

Public Sub New()
  MyBase.New
End Sub

'skipping constructors with multiple parameters...

 Public Sub Dispose() Implements IDisposable.Dispose
  Try
    If State <> CommunicationState.Faulted Then
      Close()
    End If
  Finally
    If State <> CommunicationState.Closed Then
      Abort()
    End If
  End Try
End Sub

我是否在正确的位置添加了这个?调试时,我无法在Dispose子中命中断点。

感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

你很亲密。首先,您不应该更改Reference.vb文件,因为当服务定义更新并且更改该文件不是一个好习惯时,它将被覆盖。

你可以做的是使用Proxy Pattern。代理将用于调用服务中的方法并管理连接状态等。我将用C#编写,因为我不了解VB但你会得到这个想法。我将尽可能简化这一点。

Proxy类的接口可能如下所示:

public interface IProxy
{
    /// <summary>
    /// Execute call to service method
    /// </summary>
    /// <typeparam name="TBusiness">Service interface</typeparam>
    /// <typeparam name="TResult">Service method return type</typeparam>
    /// <param name="call">Service method</param>
    /// <returns>Returns what service method returns</returns>
    TResult Execute<TBusiness, TResult>(Func<TBusiness, TResult> call) where TBusiness : class;

    /// <summary>
    /// Execute call to void service method
    /// </summary>
    /// <typeparam name="TBusiness">Service Interface</typeparam>
    /// <param name="call">Service method</param>
    void Execute<TBusiness>(Action<TBusiness> call) where TBusiness : class;
}

如您所见,此界面中有两种方法。其中一个将用于调用具有返回类型的服务方法,另一个将用于服务中的void方法。您也可以将这些方法的非泛型版本添加到界面中。

实施可能是这样的:

public class ServiceProxy : IProxy
{
    protected void ExecuteCall<TContract>(Action<TContract> code) where TContract : class
    {
        var contractChannel = default(TContract);
        try
        {
            //Create an instance of service client and call the method
            contractChannel = Activator.CreateInstance<TContract>();
            code(contractChannel);
            ((ICommunicationObject)contractChannel).Close();
        }
        catch (FaultException)
        {
            ((ICommunicationObject)contractChannel).Abort();
        }
        catch (CommunicationException)
        {
            ((ICommunicationObject)contractChannel).Abort();
        }
        catch (TimeoutException)
        {
            ((ICommunicationObject)contractChannel).Abort();
        }
    }

    public TResult Execute<TContract, TResult>(Func<TContract, TResult> call) where TContract : class
    {
        return ExecuteCall(call);
    }

    public void Execute<TContract>(Action<TContract> call) where TContract : class
    {
        ExecuteCall(call);
    }
}

然后,您可以像这样使用它:

var proxy = new ServiceProxy();
proxy.Execute<Service1Client>(a => a.MethodInTheService());

这种方法的优点是什么,以及如何使其完美:

  • 您可能不希望将代理设置为new ServiceProxy(),而inject IProxy创建为ServiceProxy,现在将其用作WCF客户端,但如果它更改为Web API,则未来,例如,实施和注入WebApiProxy然后。
  • 您可以使用合约接口来调用代理方法。
  • 您可以在代理类中执行任何操作,例如缓存通道,从数据库获取服务端点等。

答案 1 :(得分:0)

您不需要处置客户端。实际上,如果你深入研究ClientBase的代码,你会看到它是如何实现IDisposable的,当它被处理掉它只调用Close() - 如果出现问题,它会有错误处理路径中止

说完这个之后,我会使用类似下面的模式关闭你的客户端频道(你可能需要在关闭和中止时转换为IChannel):

try
{
    client.Close();
}
catch
{
    client.Abort();
}