【问题标题】:Can I call a method in a Self-Hosted WCF Service locally?我可以在本地调用自托管 WCF 服务中的方法吗?
【发布时间】:2011-05-20 09:40:59
【问题描述】:

我有一个 WCF 服务合同,基本上是发布订阅者模式。

WCF 服务托管在我要从中发布的 Windows 服务中。客户端订阅消息,当 Windows 服务执行某些操作时,它会发布给所有客户端。

为了托管服务,我声明了一个 ServiceHost 类,并且 Contract 类有一个方法,该方法未在接口中标记,但在要发布的类中实现。

我希望能够在本地调用此方法(不通过 WCF),然后通过回调发布消息。

我似乎无法从 ServiceHost 获取到 Contract 类的实例。

这可能吗?如果可以,怎么办?我知道解决方法是在服务中也内置一个客户端,但是创建一个客户端连接到自身似乎有点奇怪。

提前致谢

DJIDave

app.config

<system.serviceModel>
    <services>
      <service behaviorConfiguration="Processor.Wcf.ServiceBehavior"
        name="Processor.Wcf.ProcessorService">
        <endpoint address="net.tcp://localhost:9000/processor/service"
              binding="netTcpBinding" name="procService"
              bindingConfiguration="netTcpBindingConfig"
              contract="Processor.Wcf.IProcessorService"/>
        <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          <host>
            <baseAddresses>
              <add baseAddress="http://localhost:8732/Design_Time_Addresses/Processor.Wcf/Service1/" />
            </baseAddresses>
          </host>
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="Processor.Wcf.ServiceBehavior">
          <!-- To avoid disclosing metadata information, 
          set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="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>
    <bindings>
      <netTcpBinding>
        <binding name="netTcpBindingConfig"
                 closeTimeout="00:01:00"
                 openTimeout="00:01:00"
                 receiveTimeout="00:10:00"
                 sendTimeout="00:01:00"
                 transactionFlow="false"
                 transferMode="Buffered"
                 transactionProtocol="OleTransactions"
                 hostNameComparisonMode="StrongWildcard"
                 listenBacklog="10"
                 maxBufferPoolSize="524288"
                 maxBufferSize="65536"
                 maxConnections="10"
                 maxReceivedMessageSize="65536">
          <readerQuotas maxDepth="32"
                        maxStringContentLength="8192"
                        maxArrayLength="16384"
                        maxBytesPerRead="4096"
                        maxNameTableCharCount="16384" />
          <reliableSession ordered="true"
                           inactivityTimeout="00:10:00"
                           enabled="false" />
          <security mode="Transport">
            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
          </security>
        </binding>
      </netTcpBinding>
    </bindings>

  </system.serviceModel>

【问题讨论】:

    标签: c# .net wcf servicehost


    【解决方案1】:

    除非您将 ServiceHost 的服务实例引用作为构造函数参数提供,否则无法让 ServiceHost 为您提供服务实例引用。如果您确实提供了该实例引用,那么您正在创建一个单例服务,这通常不是一个好主意。

    要保持服务的配置不变,您必须通过客户端调用它。这实际上比您想象的要容易。由于您的主机代码可以访问服务合同,因此您可以将其与 ChannelFactory class 一起使用以获取服务的代理。除了服务合同,您只需要提供端点 name,其余的由 ChannelFactory 完成。以下是如何执行此操作的示例:

    private IMyServiceContract GetLocalClient(string serviceEndpointName)
    {
        var factory = new ChannelFactory<IMyServiceContract>(serviceEndpointName);
        return factory.CreateChannel();
    }
    

    更新: 除了这种方法,您还应该考虑让您的服务公开NetNamedPipeBinding endpoint 以提高性能。这种绑定几乎可以在内存中完成所有操作,并且是同一机器服务调用的最快绑定。

    【讨论】:

    • 感谢您的回复,我可以成功获取工厂,但是在尝试调用 CreateChannel 时,我得到“ChannelFactory.Endpoint 上的地址属性为空。ChannelFactory 的端点必须指定有效的地址。” .我会将 app.config 作为对原始帖子的编辑发布。
    • 如果即使您传递函数的端点名称是“procService”也抛出异常,则可能是权限问题。这只是一个猜测,但 Windows 服务的帐户是用于访问 WCF 服务的帐户。由于您需要 Windows 身份验证,因此它可能无权调用该服务。如果不是这样,那么我建议您添加和配置 netNamedPipeBinding 而不是尝试对 TCP 绑定进行故障排除,因为它是您正在做的更好的选择。
    【解决方案2】:

    对于多次实例化的 WCF 服务(非单例),您可以维护一个包含每个实例对应的回调函数的列表,如下所示:mdsn。您可以直接从托管代码调用方法 CallClients()(来自此 MSDN 示例),因为它是服务类的静态成员。这是我找到的唯一其他方式..

    【讨论】:

      【解决方案3】:

      除非您提供对 ServiceHost 的服务实例引用作为构造函数参数,否则

      Sixto 解决方案中的这一行为我解决了问题。也感谢this post

      我目前正在使用双面装订。


      关键概念是您可以将Type 或实例传递给ServiceHost 构造函数。

      所以我之前的情况是:

       ServiceHost host = new ServiceHost(typeof(MyService), myUri);
      

      我需要的是:

       MyService service = new MyService(foo);  // Can now pass a parameter
       ServiceHost host = new ServiceHost(service, myUri);
      

      另外,我需要用

      标记MyService
      [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
      

      ...现在我可以从服务内部调用主机的方法了。

      但是,请记住,如果您直接调用其方法,您创建的实例将没有 OperationContexthttps://stackoverflow.com/a/15270541/385273

      祝你好运!

      【讨论】:

        【解决方案4】:

        老问题,但here 是另一种调用方式Singleton WCF Service hosted on a Windows Service

        按照@Ben 的要求,Service 需要强制为Singleton

        [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 
        

        然后:

        var host = new ServiceHost(typeof(MyService), myUri);
        var instance = (MyService)host.SingletonInstance;
        

        就是这样。基本上,主机已经有一个需要“强制转换”才能访问Service 的所有功能的属性。

        【讨论】:

          猜你喜欢
          • 2011-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-02-23
          • 1970-01-01
          • 1970-01-01
          • 2013-12-19
          相关资源
          最近更新 更多