Как предоставить интерфейсы контрактов на обслуживание с множественным наследованием в сервисе WCF на одной конечной точке
У меня есть только простые типы данных в сигнатуре метода службы (например, int, string). Мой класс обслуживания реализует один интерфейс ServiceContract, скажем, IMathService, и этот интерфейс, в свою очередь, наследуется от какого-то другого базового интерфейса, например, IAdderService. Я хочу представить MathService, используя контрактный интерфейс IAdderService в качестве службы на одной конечной точке. Однако некоторые из клиник, которые знают об IMathService, должны иметь возможность доступа к дополнительным службам, предоставляемым IMathService на этой единственной конечной точке, то есть просто путем типизации IAdderService для IMathService.
//Interfaces and classes at server side
[ServiceContract]
public interface IAdderService
{
[OperationContract]
int Add(int num1, int num2);
}
[ServiceContract]
public interface IMathService : IAdderService
{
[OperationContract]
int Substract(int num1, int num2);
}
public class MathService : IMathService
{
#region IMathService Members
public int Substract(int num1, int num2)
{
return num1 - num2;
}
#endregion
#region IAdderService Members
public int Add(int num1, int num2)
{
return num1 + num2;
}
#endregion
}
//Run WCF service as a singleton instace
MathService mathService = new MathService();
ServiceHost host = new ServiceHost(mathService);
host.Open();
Конфигурация на стороне сервера:
<configuration>
<system.serviceModel>
<services>
<service name="IAdderService"
behaviorConfiguration="AdderServiceServiceBehavior">
<endpoint address="net.pipe://localhost/AdderService"
binding="netNamedPipeBinding"
bindingConfiguration="Binding1"
contract="TestApp.IAdderService" />
<endpoint address="mex"
binding="mexNamedPipeBinding"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.pipe://localhost/AdderService"/>
</baseAddresses>
</host>
</service>
</services>
<bindings>
<netNamedPipeBinding>
<binding name="Binding1" >
<security mode = "None">
</security>
</binding >
</netNamedPipeBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="AdderServiceServiceBehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Реализация клиентской части:
IAdderService adderService = new
ChannelFactory<IAdderService>("AdderService").CreateChannel();
int result = adderService.Add(10, 11);
IMathService mathService = adderService as IMathService;
result = mathService.Substract(100, 9);
Конфигурация на стороне клиента:
<configuration>
<system.serviceModel>
<client>
<endpoint name="AdderService" address="net.pipe://localhost/AdderService" binding="netNamedPipeBinding" bindingConfiguration="Binding1" contract="TestApp.IAdderService" />
</client>
<bindings>
<netNamedPipeBinding>
<binding name="Binding1" maxBufferSize="65536" maxConnections="10">
<security mode = "None">
</security>
</binding >
</netNamedPipeBinding>
</bindings>
</system.serviceModel>
</configuration>
Используя приведенный выше код и конфигурацию, я не могу типизировать экземпляр IAdderService в IMathService, он не работает, и я получаю нулевой экземпляр IMathService на стороне клиента.
Мое наблюдение состоит в том, что если сервер предоставляет IMathService клиенту, тогда клиент может безопасно ввести тип IAdderService и наоборот. Однако, если сервер предоставляет IAdderService, произойдет сбой приведения типа.
Есть ли какое-то решение этого? или я делаю это неправильно.
2 ответа
Как вы заметили, вы должны предоставить производную службу (MathService) вместо AdderService.
WCF не подозревает, что AdderService фактически является MathService, реализующим интерфейс MathService. Он рассматривается как AdderService - поэтому нет возможности привести его к производному классу.
Я точно повторил вашу ситуацию, за исключением того, что использовал IMathService
конечная точка, а не IAdderService
конечная точка.
IAdderService adderService = new ChannelFactory<IMathService>("MathService").CreateChannel();
int result = adderService.Add(10, 11);
IMathService mathService = adderService as IMathService;
result = mathService.Substract(100, 9);
Это работает для меня. Вы не можете привести базовый тип к производному типу. Вы можете сделать обратное, однако.