简体   繁体   English

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

[英]Disposing a WCF windows service client inside a WCF web service

I have a WCF web service that accesses a WCF windows service on a different machine. 我有一个WCF Web服务,可以访问另一台计算机上的WCF Windows服务。 The windows service does all the data accessing and passes the results to the web service. Windows服务执行所有数据访问,并将结果传递给Web服务。 I have read several articles about disposing the service client for a WCF service correctly, but I'm not sure what the best way is to do this in a web service. 我已经阅读了几篇有关正确配置WCF服务的服务客户端的文章,但是我不确定在Web服务中执行此操作的最佳方法是什么。 (If this helps, the web service is PerCall not PerSession) (如果有帮助,则Web服务是PerCall而不是PerSession)

This is all I'm doing right now: 这就是我现在正在做的所有事情:

 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

I'm not disposing the service client at all right now, from what I've read this is a major issue. 从我所读的内容来看,这是一个主要问题,我现在根本不会部署服务客户端。 The workaround I'm looking at is something like this inside the GetData 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

Based off What is the best workaround for the WCF client `using` block issue? 基于WCF客户端“使用”块问题的最佳解决方法是什么? , I know I shouldn't actually depend on the using block. ,我知道我实际上不应该依赖using块。 But should I be creating and disposing a service client in every function? 但是我应该在每个功能中创建并部署服务客户端吗? That's my real question. 那是我真正的问题。

Thank you. 谢谢。

Yes do not use dispose. 是的,不要使用处置。 Do it like this: 像这样做:

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();
}

Calling Close() on client notifies the service instance that it is no longer in use and may be collected by GC (subject to service instance management). 在客户端上调用Close()会通知服务实例该服务实例不再使用,并且可能由GC收集(取决于服务实例管理)。

You may wonder why Abort in the catch block? 您可能想知道为什么在catchAbort The reason is: 原因是:

Given the WCF binding use transport sessions, the client after a fault would not even be able to close it (if there was no transport layer session then the client could use or close the proxy, but this is not recommended as the configuration of sessions could change). 给定WCF绑定使用传输会话,出现故障后客户端甚至无法关闭它(如果没有传输层会话,则客户端可以使用或关闭代理,但是不建议这样做,因为会话的配置可以更改)。 So after a fault has happened the only safe operation is to abort a proxy. 因此,在发生故障之后,唯一安全的操作是中止代理。

See this for more on Abort vs Close . 更多关于Abort VS Close


EDIT 编辑

In your comments you asked: 在您的评论中,您询问:

Do you recommend creating and closing a service client like this within every function the web service calls the windows service? 您是否建议在Web服务调用Windows服务的每个函数中创建和关闭这样的服务客户端?

No I don't think that is necessary. 不,我认为没有必要。 Let's see you are calling the WCF service from a web application (ASP MVC), then you would do something like this in the Dispose method of the controller since ClientBase<TChannel> implements ICommunicationObject : 让我们看看您正在从Web应用程序(ASP MVC)调用WCF服务,然后您将在控制器的Dispose方法中执行类似的操作,因为ClientBase<TChannel>实现了ICommunicationObject

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

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

And here is the ServiceHelper class that you can use from anywhere: 这是可以在任何地方使用的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();
        }
     }
  }

} }

The idea would be the same if you were calling it from another client. 如果您是从另一个客户端调用的,则想法将是相同的。

You don't need to explicitly dispose the client, how ever if you truly must, this is one way of properly closing & disposing your client: 您不需要显式处置客户端,如果真的需要,那么这是正确关闭并处置客户端的一种方法:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM