在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(加收服务实例管理)进行收集。
您可能会奇怪为什么Abort
在catch
块?其原因是:
鉴于WCF结合使用传输会话,一个故障后,客户端将甚至无法将其关闭(如果没有传输层会话,然后客户端可以使用或关闭代理,但这是不推荐的,因为会话的配置可能会改变)。所以在发生故障之后,唯一安全的操作是中止代理。
更多关于Abort
VS Close
见this。
编辑
在你的意见,你问:
你建议创建并在每次关闭服务客户端这样的函数调用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();
}
}
}
}
的想法是相同的,如果你是从另一个客户端调用它。
你并不需要明确地配置客户端,如果你真的要怎么过,这是正确关闭&处置你的客户的一种方式:
// use client
try
{
((IClientChannel)client).Close();
}
catch
{
((IClientChannel)client).Abort();
}
finally
{
((IDisposable)client).Dispose();
}
在finally块中调用Dispose()会引起麻烦。 Dispose()调用Close(),如果通道出现故障,可能会引发异常。 –
我提供的代码示例是安全的,不会丢失。如果Close()抛出,Abort()将被调用,将内部状态设置为'Closed'。在调用Dispose()时,Close()将再次被调用,状态为Closed,这将不会执行任何操作。 就像我说的:你不需要明确地处理客户端,但如果你真的必须,上面的代码显示了一个安全的方式。 –
如果ICommunicationObject处于关闭状态,则Close()将立即返回。因此,ICommunicationObject仍然有可能出现故障,此时调用Dispose()将导致异常。 –
你建议创建和关闭一个服务客户端一样这个web服务在每个函数中调用windows服务? – cjw
@cjw请参阅编辑答案。 – CodingYoshi