Запустите WCF ServiceHost с несколькими контрактами - PullRequest
51 голосов
/ 02 декабря 2008

Запуск ServiceHost с одним контрактом работает нормально, как это:

servicehost = new ServiceHost(typeof(MyService1));
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1");
servicehost.Open();

Теперь я хотел бы добавить второй (3-й, 4-й, ...) контракт. Мое первое предположение было бы просто добавить больше конечных точек, как это:

servicehost = new ServiceHost(typeof(MyService1));
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1");
servicehost.AddServiceEndpoint(typeof(IMyService2), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService2");
servicehost.Open();

Но, конечно, это не работает, так как при создании ServiceHost я могу либо передать MyService1 в качестве параметра, либо MyService2 - так что я могу добавить множество конечных точек к моей службе, но все должны использовать один и тот же контракт, так как я может предоставить только одну реализацию?
У меня такое ощущение, что я здесь упускаю смысл. Конечно, должен быть какой-то способ обеспечить реализацию для каждого добавляемого мной конечного контракта, или нет?

Ответы [ 8 ]

59 голосов
/ 02 декабря 2008

Вам необходимо реализовать обе службы (интерфейсы) в одном классе.

servicehost = new ServiceHost(typeof(WcfEntryPoint));
servicehost.Open(); 

public class WcfEntryPoint : IMyService1, IMyService2
{
    #region IMyService1
    #endregion

    #region IMyService2
    #endregion
}

К вашему сведению: я часто использую частичные классы, чтобы облегчить чтение кода моего хост-класса:

// WcfEntryPoint.IMyService1.cs
public partial class WcfEntryPoint : IMyService1
{
    // IMyService1 methods
}

// WcfEntryPoint.IMyService2.cs
public partial class WcfEntryPoint : IMyService2
{
    // IMyService2 methods
}
17 голосов
/ 17 августа 2009

В настоящее время я столкнулся с той же проблемой, и решил перейти к реализации ниже. Я не уверен, есть ли какие-либо проблемы с производительностью при наличии такого количества контрактов на обслуживание, но в моей окончательной реализации у меня, вероятно, будет около 10-15 контрактов на обслуживание, то есть около 10-15 ServiceHosts.

Я размещаю все свои службы WCF в одной службе Windows.

private void PublishWcfEndpoints()
{
    var mappings = new Dictionary<Type, Type>
    {
       {typeof (IAuthenticationService), typeof (AuthenticationService)},
       {typeof(IUserService), typeof(UserService)},
       {typeof(IClientService), typeof(ClientService)}
    };


    foreach (var type in mappings)
    {
        Type contractType = type.Key;
        Type implementationType = type.Value;

        ServiceHost serviceHost = new ServiceHost(implementationType);
        ServiceEndpoint endpoint = serviceHost.AddServiceEndpoint(contractType, ServiceHelper.GetDefaultBinding(),
                                                                  Properties.Settings.Default.ServiceUrl  + "/" + contractType.Name);
        endpoint.Behaviors.Add(new ServerSessionBehavior());

        ServiceDebugBehavior serviceDebugBehaviour =
            serviceHost.Description.Behaviors.Find<ServiceDebugBehavior>();
        serviceDebugBehaviour.IncludeExceptionDetailInFaults = true;

        log.DebugFormat("Published Service endpoint: {0}", Properties.Settings.Default.ServiceUrl);

        serviceHost.Open();
        serviceHosts.Add(serviceHost);
    }

}

Не стесняйтесь комментировать этот тип настройки, и если есть какие-либо проблемы с ним, особенно связанные с производительностью.

10 голосов
/ 03 декабря 2008

Этот ответ является дополнительным ответом на комментарий в принятом ответе от chilltemp.

Сэм, Вы действительно должны определить, зачем вам нужно 10-50 контрактов, и попытаться найти другое решение. Я просмотрел стандарты кодирования WCF Ювала Лоуи (найдены на http://www.idesign.net/) и нашел следующие ссылки:

3 Договора на обслуживание ... 4. Избегайте контрактов с одним участником. 5. Стремитесь иметь от трех до пяти участников на контракт на обслуживание. 6. Не иметь более двадцати участников на контракт на обслуживание. Двенадцать, вероятно, практический предел.

Он не упоминает ограничение на реализацию контрактов (которое я могу найти), но я не могу представить, чтобы он рассматривал 50 контрактов на обслуживание как что-то, напоминающее лучшую практику. Одно решение, которое я нашел, которое работает хорошо, - это использование совместного использования элементов для похожих функций.

Например, если вы используете службу WCF для выполнения математики над 2 значениями, у вас может быть 4 члена на стороне службы: сложение (x, y), вычитание (x, y), умножение (x, y), Разделить (х, у). Если вы объедините их в более общий элемент и используете объект для передачи необходимых данных, вы можете легко уменьшить количество участников и повысить масштабируемость. Пример: PeformCalculation (obj), где obj имеет свойства x, y и action (сложение, вычитание, умножение, деление).

Надеюсь, это поможет.

8 голосов
/ 01 марта 2012

Я нашел другое решение этой проблемы с помощью класса RoutingService . Каждый контракт должен по-прежнему размещаться в своем собственном ServiceHost, но может быть RoutingService поверх всех из них - и представлять их через единую «конечную точку». Я также написал статью кода проекта об этом. Пример кода также доступен на Bitbucket .

6 голосов
/ 02 декабря 2008

Ответ Чили сработает, если вы согласны с контрактами, предоставляемыми сервисом. Если вы хотите, чтобы они были разделены, попробуйте это:

host1 = new ServiceHost(typeof(MyService1));
host2 = new ServiceHost(typeof(MyService2));

host1.Open();
host2.Open();

public class MyService1 : IMyService1
{
    #region IMyService1
    #endregion
}

public class MyService2 : IMyService2
{
    #region IMyService2
    #endregion
}

Редактировать: Как написал Мэтт, для каждой услуги / контракта потребуется несколько конечных точек

3 голосов
/ 19 сентября 2015

Никто не задокументировал. Когда используется более одного (как группа из общего URL, например, http), должен использоваться один и тот же экземпляр привязки (не более), т. Е.

Ваш образец:

servicehost = new ServiceHost(typeof(MyService1));
servicehost.AddServiceEndpoint(typeof(IMyService1), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService1");
servicehost.AddServiceEndpoint(typeof(IMyService2), new NetTcpBinding(), "net.tcp://127.0.0.1:800/MyApp/MyService2");
servicehost.Open();

должен быть только один новый Binding (), который я тестировал через http.

servicehost = new ServiceHost(typeof(MyService1));
 BasicHttpBinding binding = new BasicHttpBinding();
servicehost.AddServiceEndpoint(typeof(IMyService1),binding , "http://127.0.0.1:800/MyApp/MyService1");
servicehost.AddServiceEndpoint(typeof(IMyService2), binding, "http://127.0.0.1:800/MyApp/MyService2");
servicehost.Open();

Я полностью согласен с частичным классом, реализующим несколько контрактов в нескольких файлах.

1 голос
/ 19 августа 2009

Как насчет разделения его с базовым адресом и несколькими службами / контрактами под ним? Я сейчас не за разработкой машины, а что-то вроде:

http://myserver/myservices/serviceA
http://myserver/myservices/serviceB
http://myserver/myservices/serviceC

Каждый сервис реализует свой собственный ServiceContract.

Вы можете изменить
public class WcfEntryPoint : IMyService1, IMyService2
до
public partial class WcfEntryPoint : IMyService1
public partial class WcfEntryPoint : IMyService2

* * Пример тысячи двадцать-одина * +1022 *

0 голосов
/ 15 июня 2016

Я что-то упустил, или здесь не упоминается самое простое решение? Самое простое решение: не используйте несколько интерфейсов для веб-службы.

Но это не значит, что вы все равно можете разделить свои интерфейсы. Вот почему у нас есть наследование интерфейса.

[ServiceContract]
public interface IMetaSomeObjectService : ISomeObjectService1, ISomeObjectService2
{
}

Мета-интерфейс наследует от всех других интерфейсов.

[ServiceContract]
public interface ISomeOjectService1
{
    [OperationContract]
    List<SomeOject> GetSomeObjects();
}

[ServiceContract]
public interface ISomeOjectService2
{
    [OperationContract]
    void DoSomethingElse();
}

Тогда у сервиса просто есть мета-интерфейс.

public class SomeObjectService : IMetaSomeObjectService
{
   public List<SomeOject> GetSomeObjects()
   {
       // code here
   }

   public void DoSomethingElse()
   {
       // code here
   }
}
...