Почему .NET-служба WCF требует интерфейса
В отличие от реализации asmx, wcf требует, чтобы вы реализовали его интерфейс. Я не совсем понимаю причину этого дизайна. Интерфейс - это контракт между двумя классами... С учетом сказанного, как часто у вас есть 2 wcf-сервиса, которые удовлетворяют одному и тому же интерфейсу, но реализуются по-разному?
Еще один комментарий, msdn настоятельно рекомендует сделать это:
MyService service = new MyService();
try {
service.DoWork();
}
catch(Exception) {}
finally {
service.Close();
}
Итак, скажем, если я должен ввести свою службу с использованием этого интерфейса следующим образом:
public MyComponent : IDisposable
{
readonly IMyService service = null;
public MyComponent(IMyService service) {
this.service = service;
}
public DoWork()
{
//some additional code.
this.service.DoWork();
}
public void Dispose()
{
//The Interface does not have the Close method,
//So doing this defeats the whole purpose of polymorphysm
(this.service as MyService).Close(); //Silly.
}
}
Как вы используете преимущество интерфейса с WCF?
Ответы
Ответ 1
Нет, WCF НЕ требует иметь интерфейс и реализовывать его.
Это просто общепринятая лучшая практика, чтобы сделать это, но вы не должны, если вы этого не хотите.
Если вы хотите, вы можете поместить свой [ServiceContract]
в конкретный класс, который имеет несколько методов службы [OperationContract]
- вам ничего не мешает.
Но опять же: это общепринятая и проповедуемая передовая практика использования интерфейса для разделения фактического контракта как интерфейса (так что вы можете, например, издеваться над ним для тестирования и т.д.).
Ответ 2
Собственно, даже MSDN время от времени уступает тому, что формальность интерфейсов не всегда может быть "правильной вещью":
http://msdn.microsoft.com/en-us/library/ms733070.aspx
"Преимущество создания ваших сервисов путем применения ServiceContractAttribute и OperationContractAttribute непосредственно к классу и методам в классе, соответственно, - это скорость и простота".
Ответ 3
Вы можете создать службу WCF без использования интерфейса:
[ServiceContract]
public class TheService
{
// more stuff here
}
Тем не менее, рекомендуется их разделить. Разделение контракта от реализации может дать вам несколько преимуществ:
- Вы можете поместить интерфейсы в отдельную сборку. Эта сборка может использоваться любой частью кода, которая должна знать об интерфейсе, но не обязательно о реализации. Я иногда использовал это, чтобы создать службу сервиса для обмена служебными шлюзами.
- У вас может быть один класс, реализующий несколько интерфейсов. Это означает, что вы можете выставлять один и тот же реализованный класс по-разному с использованием разных интерфейсов в конечных точках WCF.
Есть и другие причины, но они сразу приходят в голову.
Ответ 4
в dotnet-интерфейсах используются для описания поведения.
WCF, Web-сервисы и удаленное использование этой технологии использует поведение RPC (Remote Procedure Calling).
в RPC должно быть некоторое общее связывание, которое разделяет клиент и сервер.
Если вы используете классы вместо интерфейса, вы также делитесь своим результирующим DLL файлом с клиентом.
поэтому ваша логика идет на сторону клиента, что не является хорошей практикой. почему мы используем интерфейсы.
Ответ 5
Если вы создаете сервис без интерфейса, вы теряете возможность создания канала "на лету" в вашем коде. Тогда единственный способ доступа к службе - добавить ссылку на службу.
Проработал с шаблоном службы WCF по умолчанию VS 2015; пометьте класс службы ServiceContract и методы с атрибутом OperationContract. Исключена реализация интерфейса IService1 (без реализации интерфейса).
[ServiceContract]
public class Service1
{
[OperationContract]
public string GetData(int value)
{
return string.Format("You entered: {0}", value);
}
[OperationContract]
public CompositeType GetDataUsingDataContract(CompositeType composite)
{
if (composite == null)
{
throw new ArgumentNullException("composite");
}
if (composite.BoolValue)
{
composite.StringValue += "Suffix";
}
return composite;
}
}
С этим изменением мы не можем создать прокси-канал "на лету", который я пробовал с помощью кода ниже.
BasicHttpBinding myBinding = new BasicHttpBinding();
EndpointAddress myEndpoint = new EndpointAddress("http://localhost:59420/Service1.svc");
// InvalidOperationException is thrown as below line
// Error message "The type argument passed to the generic ChannelFactory class must be an interface type"
ChannelFactory<Service1> myChannelFactory = new ChannelFactory<Service1>(myBinding, myEndpoint);
// Create a channel.
Service1 wcfClient1 = myChannelFactory.CreateChannel();
Console.WriteLine(wcfClient1.GetData(1));
Console.ReadKey();
Если мы используем и реализуем интерфейс ниже
public class Service1 : IService1
тогда код ниже запускается без каких-либо проблем. Теперь Service1 теперь заменяется интерфейсом IService1 при создании объекта ChannelFactory.
ChannelFactory<IService1> myChannelFactory = new ChannelFactory<IService1>(myBinding, myEndpoint);
Это самый важный аспект, если ваш клиент использует ChannelFactory вместо ServiceReference для доступа к сервису.