WCF problems with types?

When I call the WCF Soap service method, an error occurs and an error appears in the svlog file:

Enter "xxx.ActiveDirectoryService.classes.WCF.Message" with the data contract name "Message: http://schemas.datacontract.org/2004/07/xxx.ActiveDirectoryService.classes.WCF 'is not expected. Consider using DataContractResolver or add any types that are not statically known to the list of known types - for example, using the KnownTypeAttribute attribute or by adding them to the list of known types passed to the DataContractSerializer.

I tried to use KnownType here and there, but without success (I have to admit that I'm not sure that I got its use 100% to the right).

Here is my interface / classes:

[ServiceContract] public interface IActiveDirectory { [OperationContract] [WebGet] void Dummy(); [OperationContract] [WebGet] AbstractMessage Dummy2(); [OperationContract] [WebGet] AbstractMessage Dummy3(); [OperationContract] [WebGet] AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword); } [DataContract] public abstract class AbstractMessage { [DataMember] public virtual bool IsError { get; set; } [DataMember] public virtual string ErrorMessage { get; set; } [DataMember] public virtual string ReturnValue { get; set; } } public class Message : AbstractMessage { <...> } [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] [KnownType(typeof(AbstractMessage))] public class ActiveDirectory : IActiveDirectory { public void Dummy() { } public AbstractMessage Dummy2() { return new AbstractMessage(); } public AbstractMessage Dummy3() { return new Message(); } public AbstractMessage SetPassWord(string customer, string customerPassword, string userLogin, string userPassword) { <...> return message; // message is of type Message } } 

Edit: 12AM35 GMT+1

I added the Dummy () method.

  • The Dummy call from the client is working fine.
  • Calling Dummy2 from the client is working fine.
  • Calling Dummy3 from a client raises the same error.

Change 12AM39 GMT+1

Failed to make the following changes:

 [DataContract] [KnownType(typeof(AbstractMessage))] public class Message : AbstractMessage [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)] [KnownType(typeof(AbstractMessage))] [KnownType(typeof(Message))] public class ActiveDirectory : IActiveDirectory 

Edit: 13AM31 GMT+1

If I set the return type of Dummy3 to Message, the calls to Dummy3 work in the client code.
There is something strange with WCF + Polymorphism ...

+6
source share
3 answers

You need WCF services to return DTOs. They cannot be interfaces, and if you want to return abstract base classes, then you will need to tell the data serializer that implements the types that you intend to return.

He already knows about the AbstractMessage type (as his part of the operation contract), but all implementations of this type that are not explicitly declared in the operation contract must be declared in known types.

try adding this:

 [ServiceContract] [ServiceKnownType(typeof(Message))] public interface IActiveDirectory { ... } 

Here you tell the data serializer that this service can return (or wait) for objects of type Message as arguments for their methods.

and this should work too:

 [DataContract] [KnownType(typeof(Message))] public abstract class AbstractMessage { ... } 

since you want to tell the data serializer that Message is a known type of AbstractMessage

I believe that your changes did not work, because you used KnownTypes for the service instead of ServiceKnownTypes, and you tried to apply the known type to the derived class, and not to the parent class, which you do in this language (Message is AbstractMessage), but in WCF you have to flip it and put the derived implementations in the parent class (AbstractMessage has an implementation message), which can be restrictive.

you said: There something odd with WCF + Polymorphism...

Believe me, it’s better not to think of WCF as supporting polymophism, if not. You simply return the DTO, and if you want to try and make these polymorphic, you will run into many problems. Polymorphism is implemented using interfaces, and you cannot use interfaces in WCF. If you use abstract classes, due to the lack of multiple inheritance in C #, you will soon realize that a DTO can only represent one kind of your object, and you cannot create a DTO that represents several interfaces of a domain model class. (see this question on this)

See my answer here to find out how you can pass knowledge of known types, either through KnownTypes , ServiceKnownTypes or configuration.

+3
source
 [KnownType(typeof(AbstractMessage))] 

The compiler already realized that you are returning AbstractMessage. What he cannot understand from the description are instances that are derived from AbstractMessage. These are the types you need to know. Any type that you get from AbstractMessage and you return there must be a known type, and this must be declared directly in AbstractMessage.

 [KnownType(typeof(DerivedMessage1))] [KnownType(typeof(DerivedMessage2))] [KnownType(typeof(DerivedMessage3))] 

In your case, you need an attribute to tell the data serializer: "Hey, as you can see, I will return AbstractMessage , but what you cannot know: this is actually a Message ":

 [ServiceBehavior(...)] [KnownType(typeof(Message))] public class ActiveDirectory : IActiveDirectory { public AbstractMessage Dummy3() { return new Message(); } } 
+3
source

I had this problem. In my case, and as far as I was able to find out, wcf serializers require non-abstract types to work. Therefore, in my case, the transition from abstract classes and interfaces to normal objects made it work.

0
source

Source: https://habr.com/ru/post/947454/


All Articles