Может ли несколько служб 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 для нескольких сервисов?

Конечно, мне нужно что-то подобное для клиента.

Ответ 1

Вы можете комбинировать все контракты в одном классе, поэтому у вас есть одна служба с базовым адресом и одной (или более) конечной точкой (терминалами) для каждого контракта.

Чтобы избежать использования одного большого файла класса, вы можете использовать частичное ключевое слово (при условии, что вы используете С#), чтобы разделить класс на несколько файлов. Каждый файл может реализовать один контракт, что упрощает обслуживание отдельных интерфейсов.

В С++ вы можете использовать #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>

Ответ 2

Службы могут совместно использовать значения BaseAddress (включая порт #, если работает служба общего доступа к сети Net.Tcp). Это адреса конечных точек, которые должны быть уникальными. Обратите внимание, что в вашем файле конфигурации конечные точки MEX для каждого ServiceHost имеют адрес "mex". У ваших других конечных точек есть адрес пустой строки. Когда вы указываете относительный адрес для конечной точки для WCF (по крайней мере, в файле конфигурации), базовый адрес добавляется к нему. Таким образом, адрес конечной точки MEX для службы LogReader является "net.tcp://localhost: 8731/Design_Time_Addresses/SamAlyza/LogReader/mex".

Поскольку относительный адрес не был установлен в конечной точке основной службы, базовый адрес ServiceHost используется как фактический адрес для главной конечной точки обслуживания. Поскольку никакие две конечные точки не могут перекрывать значения Uri.AbsolutePath, ваш пример заставит вас поверить, что базовые значения адреса не могут использоваться совместно. Класс ServiceHost, который размещает службы WCF, не имеет встроенной конечной точки, тогда как класс ServiceEndpoint имеет свойство ListenUri, которое будет заполнено на основе параметров, которые вы предоставляете.

Если вы измените значения baseAddress в вашем примере на все совпадения, пока вы устанавливаете уникальные относительные значения адреса в элементах Endpoint, все должно работать. Однако кажется, что вы можете столкнуться с некоторыми проблемами с конечными точками MEX, так как в настоящее время у них есть адрес "mex". Сделайте их уникальными, и вы должны быть в порядке.

Теперь, я должен спросить, вы уверены, что не просто хотите, чтобы эти службы использовали пространство имен, а не базовые адреса?

Ответ 3

Вы также можете установить базовые адреса в коде, если используете пользовательскую службу 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 файлы, чтобы использовать этот factory:

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