Запустите 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();

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


person Sam    schedule 02.12.2008    source источник


Ответы (8)


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

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
}
person chilltemp    schedule 02.12.2008
comment
Черт возьми. Мне нужно больше, чем 2 контракта на обслуживание, я думаю, 10-50, и для этого числа этот подход немного громоздок - не очень полезно иметь все эти точки входа в одном классе :( Разве нет другого пути ? - person Sam; 03.12.2008
comment
Мое решение позволит вам разбить контракты на разные классы. Вы также можете объединить мое решение с chill, чтобы иметь, скажем, 5 классов, каждый с двумя конечными точками. Мне очень любопытно, зачем вам 50 контрактов. Вам следует ознакомиться с передовым опытом Juval на idesign.net. - person Chris Porter; 03.12.2008
comment
Я поддержу комментарий Криса. Похоже, вам нужно упростить дизайн. - person chilltemp; 03.12.2008
comment
Гм, ребята, вы оба говорите о совершенно разных вещах, чем я. Мне нужно 10-50 контрактов потому что я стараюсь сократить количество участников на контракт до 3-5. Я думаю, вы путаете «контракты» с «участниками». - person Sam; 05.12.2008
comment
Вы говорите о том, что одна служба предоставляет до 250 участников по WCF. Я думаю, вы сможете значительно сократить общее количество, если подойдете к своему решению с другой стороны. - person Chris Porter; 06.12.2008
comment
Одна из причин, по которой это может быть плохой подход, состоит в том, что все возможные контракты должны быть известны во время компиляции. - person Robert Jeppesen; 13.12.2011
comment
это всего лишь одна служба, в которой все методы объединены, причем в разных файлах / частичных классах. Тем не менее, он разделяет контракты, но вы по-прежнему не можете иметь одинаковые имена методов в обеих службах, например служба обмена сообщениями электронной почты и смс - где у вас есть метод отправки. - person CME64; 04.12.2016

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

}

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

person Saajid Ismail    schedule 17.08.2009
comment
здесь все усложняется - person Murhaf Sousli; 12.11.2013
comment
Было бы даже лучше, если бы вы использовали контейнер внедрения зависимостей для разрешения реализаций =) - person Th3B0Y; 25.08.2014
comment
Лучшее решение, позволяющее изолировать и индивидуально атрибутировать услуги, - person bvj; 21.09.2016

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

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

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

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

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

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

person Chris Porter    schedule 03.12.2008
comment
Жуваль говорит о 3-5 участниках по контракту. Я говорю о 10-50 контрактах на службу (каждый контракт состоит из 3-5 участников). Может быть, это создает путаницу? - person Sam; 05.12.2008
comment
Это не беспорядок, он не упоминает об ограничении контрактов, но я бы не хотел идти по пути, имея 50 контрактов на услугу. Должна быть какая-то форма рефакторинга ваших контрактов, чтобы уменьшить их размер / количество. Это ваше приложение, но я бы поискал другие варианты. - person Chris Porter; 06.12.2008

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

person m0sa♦    schedule 29.02.2012

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

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
}

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

person Chris Porter    schedule 02.12.2008
comment
Это потрясающе. Это именно то, что я искал, когда начал читать эту ветку. Сначала я подумал, что это невозможно, судя по сути этой ветки, но все работает нормально. - person Christian Findlay; 19.08.2016

Никто не задокументировал 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();

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

person Jacek Cz    schedule 19.09.2015

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

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

Пример

person Michel van Engelen    schedule 19.08.2009

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

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

[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
   }
}
person Rhyous    schedule 15.06.2016