Могут ли несколько служб WCF иметь общий BaseAddress? - PullRequest
11 голосов
/ 12 января 2009

У меня есть сборка, содержащая несколько сервисов 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, но как мне установить общий базовый адрес для нескольких служб?

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

Ответы [ 3 ]

8 голосов
/ 13 января 2009

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

Чтобы не иметь один большой файл класса, вы можете использовать ключевое словоpart (если вы используете 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>
2 голосов
/ 12 января 2009

Сервисы могут использовать значения 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». Сделайте это уникальным, и у вас все будет хорошо.

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

1 голос
/ 07 декабря 2009

Вы также можете установить базовые адреса в коде, если используете пользовательский 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" %>
...