简体   繁体   中英

Wcf Service Library interface type not being exposed

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM