问题 几个WCF服务可以共享一个公共BaseAddress吗?


我有一个包含几个WCF服务的程序集,每个服务都有自己的合同。这一切都很好。 app.config中服务的服务配置如下所示:

<services>
  <service behaviorConfiguration="WcfService.AlyzaServiceBehavior"
    name="Sam.Alyza.WcfService.ServiceWebsites">
    <endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/Websites/" />
      </baseAddresses>
    </host>
  </service>
  <service behaviorConfiguration="Sam.Alyza.WcfService.LogReaderServiceBehavior"
    name="Sam.Alyza.WcfService.ServiceLogReader">
    <endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/LogReader/" />
      </baseAddresses>
    </host>
  </service>
  <service behaviorConfiguration="Sam.Alyza.WcfService.ServiceSystemverwaltungBehavior"
    name="Sam.Alyza.WcfService.ServiceSystemverwaltung">
    <endpoint address="" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/Systemverwaltung/" />
      </baseAddresses>
    </host>
  </service>
  [...]
</services>

由于我有一个更大的项目,有更多的合同,我想有办法在不同的服务合同之间共享BaseAddress。
如果这只是一个具有不同合同和端点的服务,我可以设置一个ommon baseaddress,但是如何为多个服务设置一个公共baseaddress?

当然,我需要为客户提供类似的东西。


2927
2018-01-12 13:42


起源



答案:


您可以将所有合同合并到一个类中,这样您就可以为每个合同提供一个带有baseaddress和一个(或多个)端点的服务。

为了避免使用一个大型类文件,您可以使用partial-keyword(假设您使用c#)将类拆分为多个文件。每个文件都可以实现一个合同,这使得维护各个接口变得更加容易。

在C ++中,您可以使用#includes或多重继承,但这意味着大量的纪律......

你的配置看起来像这样:

<services>
  <service behaviorConfiguration="WcfService.AlyzaServiceBehavior"
    name="Sam.Alyza.WcfService.ServiceAll">
    <endpoint address="Websites/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="LogReader/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="Systemverwaltung/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/" />
      </baseAddresses>
    </host>
  </service>
</services>

8
2018-01-13 09:15



好主意!唯一的问题是:部分ServiceAll类很大,有很多很多方法。 - Sam
那就对了。目前,除了切换到基于代码的实例化之外,我没有看到任何其他解决方案。 - Lars


答案:


您可以将所有合同合并到一个类中,这样您就可以为每个合同提供一个带有baseaddress和一个(或多个)端点的服务。

为了避免使用一个大型类文件,您可以使用partial-keyword(假设您使用c#)将类拆分为多个文件。每个文件都可以实现一个合同,这使得维护各个接口变得更加容易。

在C ++中,您可以使用#includes或多重继承,但这意味着大量的纪律......

你的配置看起来像这样:

<services>
  <service behaviorConfiguration="WcfService.AlyzaServiceBehavior"
    name="Sam.Alyza.WcfService.ServiceAll">
    <endpoint address="Websites/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceWebsites">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="LogReader/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceLogReader">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="Systemverwaltung/" binding="netTcpBinding" contract="Sam.Alyza.WcfInterface.IServiceSystemverwaltung">
      <identity>
        <dns value="localhost" />
      </identity>
    </endpoint>
    <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
    <host>
      <baseAddresses>
        <add baseAddress="net.tcp://localhost:8731/Design_Time_Addresses/SamAlyza/" />
      </baseAddresses>
    </host>
  </service>
</services>

8
2018-01-13 09:15



好主意!唯一的问题是:部分ServiceAll类很大,有很多很多方法。 - Sam
那就对了。目前,除了切换到基于代码的实例化之外,我没有看到任何其他解决方案。 - Lars


服务可以共享BaseAddress值(包括端口#,如果Net.Tcp端口共享服务正在运行)。它是必须唯一的端点地址。请注意,在配置文件中,每个ServiceHost的MEX端点的地址都是“mex”。您的其他端点的地址为空字符串。当您为WCF(至少在配置文件中)提供端点的相对地址时,会为其添加基址。因此,LogReader服务的MEX端点地址是“net.tcp:// localhost:8731 / Design_Time_Addresses / SamAlyza / LogReader / mex”。

由于未在主服务端点上设置相对地址,因此ServiceHost的基地址将用作主服务端点的实际地址。因为没有两个端点可以具有重叠的Uri.AbsolutePath值,所以您的示例会让您相信无法共享基址值。承载WCF服务的ServiceHost类没有内置端点,而ServiceEndpoint类具有将根据您提供的设置填充的ListenUri属性。

如果将示例中的baseAddress值更改为all match,只要在Endpoint元素上设置唯一的相对地址值,一切都应该有效。但是,看起来您可能会遇到MEX端点的一些挑战,因为它们目前都有地址“mex”。做那些独特的,你应该没事。

现在,我必须要问,你确定你不是只是希望这些服务共享命名空间而不是基地址吗?


2
2018-01-12 19:07



另一点是,baseAddress只不过是当前位置,可以这么说。我们的想法是所有端点通常都与baseAddress相关。因此,如果您尝试跨所有服务共享相同的baseAddress,则限制了部署选项。 - EnocNRoll - Ananda Gopal
如果您正在寻找一种简化配置的方法,则必须切换到使用代码而不是配置连接。您可以以编程方式创建ServiceHost和ServiceEndpoint实例,也可以从数据库中提取Uri.AbsolutPath值。 - EnocNRoll - Ananda Gopal
是的,我正在寻找一种方法来使配置文件更容易更改。所以如果你对此有任何想法,我会全力以赴。 - Sam
询问有关基于代码的WCF服务实例化的另一个问题,我将发布一个示例静态类。 - EnocNRoll - Ananda Gopal
我将发布一个问题,然后发布我的解决方案。 - EnocNRoll - Ananda Gopal


如果使用自定义ServiceHostFactory,还可以在代码中设置基址。

在配置中,您可以设置一些应用程序:

<configuration>
  <appSettings>
    <add key="BaseAddress" value="http://localhost:1234" />
  </appSettings>
<configuration>

然后创建一个自定义的ServiceHostFactory:

public sealed class MyServiceHostFactory : ServiceHostFactory
{
    protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
    {
        var baseAddy = ConfigurationManager.AppSettings["BaseAddress"];
        baseAddresses.Add(new Uri(baseAddy));
        return new ServiceHost(serviceType, baseAddresses);
    }

}

然后,您还必须更改.svc文件以使用该工厂:

<%@ ServiceHost Language="C#" Debug="true" Service="MyApp.MyService" CodeBehind="MyService.svc.cs" Factory="MyApp.MyServiceHostFactory" %>

1
2017-12-07 16:28