我有一个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?,我知道我不应该依赖于使用块。但是我应该在每个功能中创建和部署服务客户端吗?那是我真正的问题。
谢谢。
答案 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();
}