【问题标题】:WCF call that references Windows Service引用 Windows 服务的 WCF 调用
【发布时间】:2013-01-07 08:37:53
【问题描述】:

我有一个长期运行的服务,它从一个来源获取数据、对其进行操作、将其存储在数据库中,等等。

我想将该服务上的一些方法公开给其他应用程序。目前我们通过 .NET Remoting 执行此操作,但我想迁移到 WCF。

不幸的是,我连接的端点从来都不是我通过长期运行的服务公开的端点。下面是一个简单的例子:

    [ServiceContract]
    public interface ITestWcfService
    {
        [OperationContract]
        CounterResult GetCurrentValue();
    }

public class TestWcfService : ITestWcfService
    {
        private ITestWindowsService _service;
        public TestWcfService() { /*NOTE: For discoverability*/ }
        public TestWcfService(ITestWindowsService service)
        {
            _service = service;
        }

        public CounterResult GetCurrentValue()
        {
            return _service.GetCurrentValue();
        }
    }

public interface ITestWindowsService
    {
        CounterResult GetCurrentValue();
    }

然后我有我的实际 Windows 服务,它通过 ServiceHost 类自托管 WCF 服务。

public partial class TestWindowsService : ServiceBase, ITestWindowsService
{
    private static ServiceHost _wcfService;

    public TestWindowsService()
    {
        InitializeComponent();
    }

    public void OnStart(string[] args)
    {
        //Create instance of WCF, passing in reference to this service instance
        TestWcfService wcf = new TestWcfService(this);
        _wcfService = new ServiceHost(wcf);
    }

        public CounterResult GetCurrentValue()
    {
        //Note: Some logic here
    }
}

现在,这或多或少的工作,除了每次我调用TestWcfServiceClient() 时,它使用默认构造函数并创建 Wcf 服务的新实例,而不使用由 windows 创建的实例服务。这意味着当我调用GetCurrentValue() 时,我得到一个空引用,因为_service 成员尚未设置。

我四处寻找解决方案,发现一些引用 ServiceHostFactoryServiceHostIInstanceProvider 但每个似乎都非常非常复杂。

您能提供的任何想法将不胜感激。

编辑:这是我的 ServiceModel 信息

<system.serviceModel>
    <services>
      <service name="WcfService.TestWcfService">
        <host>
          <baseAddresses>
            <add baseAddress = "http://localhost:8733/Design_Time_Addresses/WcfService/TestWcfService/" />
          </baseAddresses>
        </host>
        <!-- Service Endpoints -->
        <!-- Unless fully qualified, address is relative to base address supplied above -->
        <endpoint address="" binding="basicHttpBinding" contract="WcfService.ITestWcfService">
          <!-- 
              Upon deployment, the following identity element should be removed or replaced to reflect the 
              identity under which the deployed service runs.  If removed, WCF will infer an appropriate identity 
              automatically.
          -->
          <identity>
            <dns value="localhost"/>
          </identity>
        </endpoint>
        <!-- Metadata Endpoints -->
        <!-- The Metadata Exchange endpoint is used by the service to describe itself to clients. --> 
        <!-- This endpoint does not use a secure binding and should be secured or removed before deployment -->
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, 
          set the values below to false before deployment -->
          <serviceMetadata httpGetEnabled="True" httpsGetEnabled="True"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="False" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
  </system.serviceModel>

【问题讨论】:

    标签: c# .net wcf service


    【解决方案1】:

    WCF 是非常可扩展的,但是为了提供这种可扩展性,它也非常复杂。在我看来,如果你想使用这个实现,那么应该不止如此,这就是要走的路。您必须创建一种更改服务工厂的行为,以便您可以使用自定义构造函数而不是空构造函数。

    但是,我认为可能还有另一种选择。由于服务和 WCF 共享同一个应用程序域,因此它们可以通过静态对象共享值。

    我会将带有您想要公开的值的逻辑移动到底层程序集(如果您还没有),并且服务和 WCF 服务都会看到相同的实例,因此您不需要更改所有WCF 管道。

    【讨论】:

    • 是的,我想我要解决的问题是:如何让其他应用程序调用我的持久服务上的方法?现在我们使用一个超级复杂的自定义 .NET 远程处理库。我想使用 WCF,因为过去它对我们来说非常好。然而,这似乎不是它通常解决的那种问题(至少,不是以简单的方式)
    • 如果您实现所需的类来扩展 WCF 并传递服务所需的任何内容或使用我描述的“静态对象”方法,您应该能够做到。换句话说,忘记你想要做什么。相反,请忘记存在自动托管解决方案并使用 Windows 服务自行托管您的 WCF。完成后,您只需将缺少的行为添加到您的 Windows 服务。它非常可行。
    【解决方案2】:

    您正试图将方形钉子放入圆孔中。

    WCF 被明确设计为能够独立于托管方式调用业务逻辑。您正在尝试维护在主机层中具有业务逻辑的旧远程处理设计(在本例中为 Window 的服务)。因此,您要求以一种在 WCF 中可行但丑陋的方式将信息传回主机,并且出于许多充分的理由通常会避免这种方式。

    如果您想要一个干净的 WCF 设计,您将需要创建抽象层并将您的业务逻辑移出现有的 TestWindowsService 类。然后windows服务创建WCF服务宿主,WCF宿主创建WCF服务,WCF服务不依赖于承载它的类。

    说了这么多……

    要真正回答您的问题:

    从概念上讲,您编写的代码应该可以工作。迄今为止,将对象实例传递给 ServiceHost 构造函数是避免编写自定义 IInstanceProvider 的复杂性的最简单方法。有几件事要检查:

    1. 当您将服务实例传递给 ServiceHost 构造函数时,需要将其标记为singleton

      [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]

    2. 确保初始化确实按照您认为的方式工作:

      1. 在您的 TestService(ITestWindowsService) 构造函数上设置一个守卫,如果 service 为空则抛出该构造函数。
      2. 您对 TestWcfService() 的默认构造函数有一条注释,上面写着“用于可发现性”。我会删除该构造函数(至少在您进行故障排除时)。一段代码可能正在使用该构造函数来托管您不想要的服务实例。这可能会导致您的应用开始抛出异常或编译指出您的真正问题的错误。

    如果您仍有问题:app.config 的服务模型部分是什么样的?

    【讨论】:

    • 是的,通常当我有这种感觉时,我知道我看错了问题,也许 WCF 不是要走的路。但是 MS 吹捧 WCF 作为 .NET 远程处理的替代品,但它基本上已弃用此功能。我知道来自客户端的调用正在执行默认构造函数。好像我正在制作自托管端点但无法访问它......当我取出默认 ctr 时,当我的客户端对丢失的行为进行方法调用时,它会引发错误。我已将我的服务模型添加到帖子中。
    • 当你取出默认构造函数时,错误是什么?您真正的问题是您的配置需要修复,以便永远不会调用构造函数。您可能希望将 更改为 true 以向客户端获取更多信息。
    猜你喜欢
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多