Почему.net WCF Service требует интерфейса
В отличие от реализации asmx, wcf требует от вас реализации его интерфейса. Я не совсем понимаю причину этого дизайна. Интерфейс - это контракт между 2 классами... С учетом сказанного, как часто у вас есть 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?
5 ответов
Нет, WCF НЕ требует наличия интерфейса и его реализации.
Это просто общепринятая лучшая практика - но вам не нужно, если вы не хотите.
Если вы хотите, вы можете поставить свой [ServiceContract]
на конкретном классе, который имеет ряд [OperationContract]
методы обслуживания - ничто не мешает вам сделать это.
Но опять же: общепринятая и проповедованная лучшая практика - использовать интерфейс для выделения фактического контракта в качестве интерфейса (так что вы можете, например, высмеять его для тестирования и т. Д.).
На самом деле, даже MSDN время от времени допускает, что формальность интерфейсов не всегда может быть "правильной":
http://msdn.microsoft.com/en-us/library/ms733070.aspx
"Преимущество создания ваших служб путем применения ServiceContractAttribute и OperationContractAttribute непосредственно к классу и методам класса, соответственно, заключается в скорости и простоте".
Вы можете создать службу WCF без использования интерфейса:
[ServiceContract]
public class TheService
{
// more stuff here
}
Тем не менее, рекомендуется разделить их. Отделение договора от реализации может дать вам различные преимущества:
- Вы можете поместить интерфейсы в отдельную сборку. Эта сборка может использоваться любым фрагментом кода, который должен знать об интерфейсе, но не обязательно о реализации. Иногда я использовал это для создания своего рода шлюза сервиса, оборачивающего связь со службой.
- Вы можете иметь один класс, реализующий более одного интерфейса. Это означает, что вы можете выставлять один и тот же реализованный класс по-разному, используя разные интерфейсы в конечных точках WCF.
Есть и другие причины, но они сразу приходят на ум.
В dotnet интерфейсы используются для описания поведения. WCF, Web-сервисы и все это удаленное взаимодействие использует поведение RPC (удаленный вызов процедур). в RPC должна быть общая привязка, которая используется клиентом и сервером.
если вы используете классы вместо интерфейса, вы также поделитесь своим результирующим dll-файлом с клиентом. следовательно, ваша логика переходит на сторону клиента, что не является хорошей практикой. Вот почему мы используем интерфейсы.
Если вы создаете сервис без интерфейса, вы теряете возможность создавать канал на лету в своем коде. Тогда единственный способ получить доступ к сервису - добавить ссылку на сервис.
Пробовал с шаблоном службы 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 для доступа к сервису.