在WCF Web服务内部处理WCF Windows服务客户端

问题描述:

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

这是我现在在做:

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?,我知道我不应该实际上取决于使用块。但是,我应该在每个功能中创建和部署服务客户端吗?这是我真正的问题。

谢谢。

是不使用处置。像这样做:

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(加收服务实例管理)进行收集。

您可能会奇怪为什么Abortcatch块?其原因是:

鉴于WCF结合使用传输会话,一个故障后,客户端将甚至无法将其关闭(如果没有传输层会话,然后客户端可以使用或关闭代理,但这是不推荐的,因为会话的配置可能会改变)。所以在发生故障之后,唯一安全的操作是中止代理。

更多关于Abort VS Closethis


编辑

在你的意见,你问:

你建议创建并在每次关闭服务客户端这样的函数调用Web服务的窗口服务?

不,我不认为这是必要的。让我们来看看您呼叫从一个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(); 
     } 
    } 
    } 

}

的想法是相同的,如果你是从另一个客户端调用它。

+0

你建议创建和关闭一个服务客户端一样这个web服务在每个函数中调用windows服务? – cjw

+0

@cjw请参阅编辑答案。 – CodingYoshi

你并不需要明确地配置客户端,如果你真的要怎么过,这是正确关闭&处置你的客户的一种方式:

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

在finally块中调用Dispose()会引起麻烦。 Dispose()调用Close(),如果通道出现故障,可能会引发异常。 –

+0

我提供的代码示例是安全的,不会丢失。如果Close()抛出,Abort()将被调用,将内部状态设置为'Closed'。在调用Dispose()时,Close()将再次被调用,状态为Closed,这将不会执行任何操作。 就像我说的:你不需要明确地处理客户端,但如果你真的必须,上面的代码显示了一个安全的方式。 –

+0

如果ICommunicationObject处于关闭状态,则Close()将立即返回。因此,ICommunicationObject仍然有可能出现故障,此时调用Dispose()将导致异常。 –