0

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

我想将该服务上的一些方法公开给其他应用程序。目前我们通过 .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>
4

2 回答 2

0

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

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

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

说了这么多...

要实际回答您的问题:

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

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

    [服务行为(InstanceContextMode=InstanceContextMode.Single)]

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

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

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

于 2013-01-24T16:51:02.767 回答
0

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

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

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

于 2013-01-23T18:47:20.837 回答