在WCF Web服务中部署WCF Windows服务客户端

时间:2017-02-13 22:19:10

标签: c# vb.net wcf

我有一个WCF Web服务,可以访问不同计算机上的WCF Windows服务。 Windows服务会访问所有数据并将结果传递给Web服务。我已经阅读了几篇关于正确处理WCF服务的服务客户端的文章,但我不确定在Web服务中执行此操作的最佳方法是什么。 (如果这有帮助,Web服务是PerCall而不是PerSession)

这就是我现在所做的一切:

 Public Class Service1
  Implements IService1

  Private p_oWindowsService As DataService.Service1Client

  Public Sub New()
    p_oWindowsService = New DataService.Service1Client
  End Sub

  Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
    Return p_oWindowsService.GetData(value)
  End Function

  Public Function GetDataUsingDataContract(ByVal composite As CompositeType) As CompositeType Implements IService1.GetDataUsingDataContract
    If composite Is Nothing Then
      Throw New ArgumentNullException("composite")
    End If
    If composite.BoolValue Then
      composite.StringValue &= "Suffix"
    End If
    Return composite
  End Function

我现在没有处理服务客户端,从我所知道的这是一个主要问题。我在GetData函数中看到的解决方法是这样的:

 Public Function GetData(ByVal value As Integer) As String Implements IService1.GetData
     Using oWindowsService As New DataService.Service1Client
        Return oWindowsService.GetData(value)
     End Using        
  End Function

基于What is the best workaround for the WCF client `using` block issue?,我知道我不应该依赖于使用块。但是我应该在每个功能中创建和部署服务客户端吗?那是我真正的问题。

谢谢。

2 个答案:

答案 0 :(得分:2)

是的,不要使用处置。这样做:

var client = new ...;
try {
   // Do work

   // Everything went well so close the client
   client.Close();
}
catch( Exception ex ) {
   // Something went wrong so call abort
   client.Abort();

   // Other logging code 
}

if( client.State != System.ServiceModel.CommunicationState.Closed ) {
   client.Close();
}

在客户端上调用Close()会通知服务实例它已不再使用,并且可能由GC收集(受服务实例管理)。

你可能想知道为什么Abort阻止了catch?原因是:

  

鉴于WCF绑定使用传输会话,故障后的客户端甚至无法关闭它(如果没有传输层会话,则客户端可以使用或关闭代理,但不建议将其作为配置会议可能会改变)。因此,在发生故障后,唯一安全的操作是中止代理。

有关Abort vs Close的更多信息,请参阅this

修改

在你的评论中你问:

  

您是否建议在Web服务调用Windows服务的每个功能中创建和关闭这样的服务客户端?

不,我不认为这是必要的。让我们看看你是从Web应用程序(ASP MVC)调用WCF服务,然后你会在控制器的Dispose方法中执行类似的操作,因为ClientBase<TChannel>实现了ICommunicationObject

protected override void Dispose(bool disposing) {
     base.Dispose( disposing );

     ServiceHelper.DisposeService( ( this._whateverServiceClient as ICommunicationObject ) );
 }

以下是您可以在任何地方使用的ServiceHelper课程:

public static class ServiceHelper {

  /// <summary>
  /// Disposes the given service.
  /// </summary>
  /// <param name="service">The service.</param>
  public static void DisposeService(ICommunicationObject service) {

     if( service != null ) {

        bool abort = true;

        try {
           if( service.State == CommunicationState.Opened || service.State == CommunicationState.Opening ) {
              service.Close();
              abort = false;
           }
        }
        finally {

           // Determine if we need to Abort the communication object.
           if( abort )
              service.Abort();
        }
     }
  }

}

如果你是从另一个客户端调用它,那么这个想法是一样的。

答案 1 :(得分:0)

您不需要明确处理客户,如果您真的必须这样做,这是正确关闭和解决方案的一种方式。处理你的客户:

        // use client
        try
        {
            ((IClientChannel)client).Close();
        }
        catch
        {
            ((IClientChannel)client).Abort();
        }
        finally
        {
            ((IDisposable)client).Dispose();
        }