Подтвердить что ты не робот

Запуск WCF ServiceHost с несколькими контрактами

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

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

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

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

4b9b3361

Ответ 1

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

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

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

    #region IMyService2
    #endregion
}

FYI: Я часто использую частичные классы, чтобы облегчить чтение кода класса хоста:

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

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

Ответ 2

В настоящее время я сталкиваюсь с той же проблемой и решил перейти к реализации ниже. Я не уверен, есть ли какие-либо проблемы с производительностью при наличии этого большого количества контрактов на обслуживание, но в моей последней реализации у меня, вероятно, будет около 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);
    }

}

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

Ответ 5

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

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
}

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

Ответ 6

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

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

Пример

Ответ 7

Никто не зарегистрировал enpoints. Вы использовали более одного (как группа, из общего 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();

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

Ответ 8

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

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

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

Интерфейс Meta наследует все остальные интерфейсы.

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

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

Затем служба имеет только интерфейс Meta.

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

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