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