Click here to Skip to main content
15,849,494 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Hi Guys,

So I'm sure I'm missing something fairly basic but I cannot for the life of me figure out what it is.

I have the following set up:
Interface:
C#
public interface IMyFileInterface
{
    string FileName {get;set;}
    MyEnum FileType {get;set;
    DateTime UploadDate {get;set;}
}

Classes:
C#
[DataContract]
public class ReturnModel
{
   [DataMember]
   public string Name {get;set;}
   [DataMember]
   public List<IMyFileInterface> LatestFiles {get;set;}
}
[DataContract]
public class FooFileModel : IMyFileInterface
{
    [DataMember]
    string FileName {get;set;}
    [DataMember]
    MyEnum FileType {get;set;
    [DataMember]
    DateTime UploadDate {get;set;}

}


I have a web api controller with a function that returns the ReturnModel

However, when I call it I get the following error:

Type 'Common.Objects.FooFileModel' with data contract name 'FooFileModel:http://schemas.datacontract.org/2004/07/Common.Objects' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.

I've tried adding the KnownType attribute to the LatestFiles property but that errors and says it can only be added to an object, so I tried adding it to the the FooFileModel with the known type being the interface but again that has made no difference.

So my question is, how can I set up my classes and interfaces so they can be passed back to a client app view the web api? I'm sure I'm missing something simple, but I cannot for the life of me figure it out.

Any help would be greatly appreciated.

Regards
Posted
Comments
Kornfeld Eliyahu Peter 8-Dec-14 12:02pm    
Add before! ReturnModel this line: [KnownType(typeof(FooFileModel))]
Pheonyx 9-Dec-14 3:55am    
Can I ask why? as I'd like to understand the reasoning for it.
Kornfeld Eliyahu Peter 9-Dec-14 4:10am    
Because ReturnModel has a property of type that is an interface. That is not a run-time type and serialization is done using run-time types...
How it done? The underlying framework (that of data contract of WebAPI) try to load all the relevant run-time types BEFORE actual serialization. In the case of interface it can not be done...That line of KnownType instructs the framework to load also FooFileModel for later use...
If you intend to use more classes that implement the interface you will have to add a KnwonType lone for each...
Pheonyx 9-Dec-14 4:13am    
Ahh, okay
Thanks very much, that makes sense. I thought you added the known type when you were inheriting from a base class or interface. Clearly I just miss understood.
If you put that as an answer I'll accept it as it seems to have solved the issue.
Wonde Tadesse 9-Dec-14 16:52pm    
Just curious why you need WCF attrib classes([DataContract],DataMember), If you are going to consume in Web API or Are you also using the DTOs in WCF as well ?

1 solution

Add before! ReturnModel this line: [KnownType(typeof(FooFileModel))]
C#
[KnownType(typeof(FooFileModel))]
[DataContract]
public class ReturnModel
{
   [DataMember]
   public string Name {get;set;}
   [DataMember]
   public List<IMyFileInterface> LatestFiles {get;set;}
}

The reason is that ReturnModel has a property of type that is an interface. That is not a run-time type and serialization is done using run-time types...
How it done? The underlying framework (that of data contract of WebAPI) try to load all the relevant run-time types BEFORE actual serialization. In the case of interface it can not be done...That line of KnownType instructs the framework to load also FooFileModel for later use...
If you intend to use more classes that implement the interface you will have to add a KnwonType lone for each...
 
Share this answer
 
Comments
Pheonyx 9-Dec-14 9:22am    
Hi Kornfeld,

Thank you for your help with the above, I was wondering if you could shed some light, or ideas on how to de serialise the objects once I've received them at the client.
My API appears to send over the correct data thanks to your help above, but my client is trying to parse the result as the interface rather than the known type.

I get the following error:

Could not create an instance of type Common.Objects.IMyFileInterface. Type is an interface or abstract class and cannot be instantiated. Path 'LatestUploads[0].SurveyType', line 1, position 220.

(I don't know if it is relevant but SurveyType is a custom enum).
I've tried putting this (as recommended by various posts on the internet)

Configuration.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Objects;

But it doesn't seem to have made a difference.

I'm basically using the example from here:
Calling a web api from a .Net Client to create a client to access my API.
Kornfeld Eliyahu Peter 9-Dec-14 9:34am    
If I understand it your client is JavaScript...Use JSON format for the returned data and the returning string will be - magically - a JavaScript object...
You may learn about it here: http://www.json.org/js.html
Pheonyx 9-Dec-14 9:42am    
Nope, my client is a .Net client.

I'm building a test console application to ensure I can receive the data and deserialise it, but in the long term the code will be migrated into a MVC reporting site. The Controller, or a data repository of sorts built in c# will call the api which is being implemented on multiple other sites.

My issue is when I try and get the result from the "response.Result.Content.ReadAsAsync<returnmodel>()" I get the error mentioned in my previous comment.
Kornfeld Eliyahu Peter 9-Dec-14 9:45am    
It seems you try to create a class of type IMyFileInterface! That's impossible you can not instantiate an interface!
I think it is better you open an other post with the relevant code and sample so all CP could see it...
Pheonyx 9-Dec-14 9:46am    
Okay, thanks.
Thought I would ask you first :-)

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900