我可以在本地调用自托管 WCF 服务中的方法吗?

发布于 2024-11-08 04:16:54 字数 3243 浏览 0 评论 0原文

我有一个 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>

I have a WCF Service contract which is basically the Publish Subscriber pattern.

The WCF Service is hosted inside the Windows Service that I want to publish from. The Clients subscribe to messages and when the Windows Service does something it publishes to all clients.

To host the service I have declared a ServiceHost class and the Contract Class has a method which is not flagged in the Interface but is implemented in the Class to publish.

I want to be able to call this method locally (not going through WCF) which then publishes the message via Callbacks.

I can't seem to get from ServiceHost to the instance of the Contract Class.

Is this possible and if so how? I know the work around is to have a client built into the service as well, but it seems a bit strange creating a client to connect to itself.

Thanks in advance

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>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

﹏半生如梦愿梦如真 2024-11-15 04:16:54

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

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

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

更新:
除了这种方法之外,您还应该考虑让您的服务向提高性能。此绑定几乎在内存中执行所有操作,并且是同一机器服务调用的最快绑定。

Unless you provide the service instance reference to the ServiceHost as a constructor parameter, there isn't a way to have the ServiceHost provide you an service instance reference. If you do provide that instance reference then you are creating a singleton service which is generally not a good idea.

To keep the service as it is configured, you will have to call it through a client. This is actually easier than you might think. Since your host code has access to the service contract, you can use it with the ChannelFactory class to get a proxy for the service. Besides the service contract, all you have to provide is the endpoint name and ChannelFactory will do the rest. Below is an example of how to do this:

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

UPDATE:
Along with this approach, you should consider having you service expose a NetNamedPipeBinding endpoint to improve performance. This binding pretty much does everything in memory and is the fastest binding for same machine service invocation.

呆头 2024-11-15 04:16:54

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

For a WCF service instantiating more than once (non-singleton), you can maintain a list containing each instance's corresponding callback function as given here: mdsn. You can call the method CallClients() (from this MSDN example) from the hosting code directly as it is a static member of the service class. This is the only other way I found..

夜雨飘雪 2024-11-15 04:16:54

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

Sixto 解决方案中的这一行为我解决了问题。感谢 这篇文章也是如此。

我现在使用的是双面装订。


关键概念是您可以将 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);

另外,我需要用

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 

... 标记 MyService ,现在我可以从服务内部调用主机的方法。

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

祝你好运!

Unless you provide the service instance reference to the ServiceHost as a constructor parameter,

This line from Sixto's solution solved things for me. Credit and thanks to this post as well.

I'm using a duplex binding at the moment.


The key concept is that you can pass in a Type or an instance to the ServiceHost constructor.

So what I had before was:

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

What I needed was:

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

Also, I needed to mark MyService with

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 

...and now I can call the host's methods from inside the service.

However, keep in mind that the instance you created will not have an OperationContext if you call its methods directly: https://stackoverflow.com/a/15270541/385273

Good luck!

很快妥协 2024-11-15 04:16:54

老问题,但是 这里是调用Windows服务上托管的单例WCF服务的另一种方法,

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

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 

然后:

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

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

Old question, but here is another way to call a Singleton WCF Service hosted on a Windows Service

Following @Ben's requirements, the Service would need to be forced to be a Singleton:

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)] 

Then:

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

That's it. Basically, the host already has a property that needs to be 'casted' to be able to access all the features from the Service.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文