I've look over many examples (including Passing Interface in a WCF Service? ) with regards the problem I have, but until now have not found a solution. I have a Wcf Service Library (.NET 4.0) with the following
public class Service : IService
{
public bool Ping(IChannelManager channelManager)
{
return channelManager.Ping();
}
}
[ServiceContract]
public interface IService
{
[OperationContract]
bool Ping(IChannelManager channelManager);
}
[ServiceContract]
[ServiceKnownType(typeof(TestChannelName))]
public interface IChannelManager
{
[OperationContract]
bool Ping();
}
[DataContract]
public class TestChannelName : IChannelManager
{
public bool Ping()
{
//perform a ping
return true;
}
}
My project compiles fine. But when I try to add it as a Service Reference from a console app, I can add it fine and try to access the method like below;
using (Test.ServiceClient oClient = new Test.ServiceClient())
{
oClient.Ping();
}
But the problem I have is the Ping() method on the Wcf service, the interface type is coming up as object channelmanager ? Like
I tried adding [ServiceKnownType(typeof(TestChannelName ))] to the both interfaces but no luck.
Where am I going wrong ?
My answer will be split in two - a technical overview of why this happens - and philosophizing about why this happens.
first technically If you have a look at:
http://localhost:8733/Design_Time_Addresses/YourProject/Service1/?singlewsdl
the wsdl file that is created from your example code, you will find the following:
<xs:element name="Ping">
<xs:complexType>
<xs:sequence>
<xs:element minOccurs="0" name="channelManager" nillable="true" type="xs:anyType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
Either over mex or as you see above in the wsdl. you get xs:anytype
(in practical terms the c# object). This behavior although frustrating is to be expected, Mex and the WsdlExtractor
only understand concrete types - DataMembers denoted by a [DataContract]
in the service arguments, well that or simple types. Any other will be treated gracefully as 'object' rather then just failing to compile.
The philosophy part:
Effectively you are trying to pass a method [ServiceContract]
as a parameter. Services (with their logic built to IL in some DLL) do not serialize and pass over networks - not because it can't be done - because it is not what they are for.
In your example IChannelManager
is a [ServiceContract]
, and you even try to export the Ping()
as an [OperationContract]
. the [ServiceKnownType]
attribute does nothing to remedy that.
When is the [ServiceKnownType]
useful then? Well that is well documented but the gist of it is - if your DataMember in runtime is to hold some concrete class - that the compiler cannot infer at compile time (eg interfaces, abstract classes or base classes) well then a deserializer will not be able to guess what concrete types it should know when trying to deserialize.
You might then say to me - well that sounds fair and well but I need to pass my logic (Service) as a parameter. And to that I'd say - what you need is to redesign your solution. Maybe write and host more services and use the service equivalent of the Strategy or Delegation patterns.
I hope some of this helps.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.