8

I have a class that inherited from an Interface , And I am returning interface from my web api get methed , The problem is I am getting values of the inherited class as json string.

This is the interface

 public interface IFoo
    { 
    string A { get ;set ; } 
    string B { get ; set ; } 
    } 

Inherited Class

 public class Child : iFoo
    { 
    string A { get ; set ; } 
    string B { get ; set ; } 
    string C { get ; set ; } 
    string D { get ; set ; } 
    } 

Then I return IFoo from my controller's GetMethod

 public IFoo GetIFoo()
        {
        return  ChildInstance ; 
        }

current result give me all the values of inherited class , and interface both but I want only values that are implemented in interface in json result.

Kas
  • 3,747
  • 5
  • 29
  • 56

4 Answers4

8

By the time it hits the Json serializer, it doesn't care what the return type of the method was. All it knows is "I have this object, let's see what I can do with it".

If you want the serializer to only contain the properties that your interface has, you better give it an object that only has the properties that your interface has. You might consider using e.g. Automapper to copy values across from ChildInstance to this new object.

The alternative is more complex - implementing your own serializer so that the Json serializer doesn't get a chance to get involved.

Damien_The_Unbeliever
  • 234,701
  • 27
  • 340
  • 448
3

Your method is contracted to return an object that implements IFoo. It can return any object that implements IFoo, but cannot return an Ifoo itself as you cannot have an instance of an interface. So it returns an instance of Child.

The JSON serializer is then given this instance of Child and uses reflection to work out it's properties. It finds A - D and so serializes them.

If you only want A - B serialised, then you'll have to return an instance of a class that only implements A - B.

Having said all that, if you are using ASP MVC, then check out http://www.creave.dk/post/2009/10/07/Excluding-properties-from-being-serialized-in-ASPNET-MVC-JsonResult.aspx. By changing your class definition to

public class Child : iFoo
{ 
    string A { get ; set ; } 
    string B { get ; set ; }

    [ScriptIgnore]
    string C { get ; set ; } 
    [ScriptIgnore]
    string D { get ; set ; } 
} 

Then you have instructed the JSON serializer to only serialise A - B.

David Arno
  • 42,717
  • 16
  • 86
  • 131
0

If you don't mind returning dynamic, you do something like this:

The flip side is that this only works out of the box if you use the json serializer, so you have to specify "accept: application/json" for it to work.

public class Person
{
    public string Name { get; set; }
}

public class User : Person
{
    public string Title { get; set; }
    public string Email { get; set; }
}

public dynamic Get()
{
    var user = new User { Title = "Developer", Email = "foo@bar.baz", Name = "MyName" };

    return new { user.Name, user.Email };
}
Francis
  • 1,214
  • 12
  • 19
0

You can also apply action filters to serialize only the interface properties if the return type of the controller method is an interface. This way you always stay in sync with your interface definition without having to change any attributes on the class implementing the interface.

For this you'd first have to create a custom InterfaceContractResolver contract resolver as explained here:

    public class InterfaceContractResolver : DefaultContractResolver
    {
        private readonly Type _interfaceType;
        public InterfaceContractResolver(Type interfaceType)
        {
            _interfaceType = interfaceType;
        }

        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> properties = base.CreateProperties(_interfaceType, memberSerialization);
            return properties;
        }
    }

Then add an action filter (either as an attribute as explained here or globally if you want this as a default behavior) that looks at the return type of the controller method and if it's an interface uses the contract resolver defined above:

    public class InterfaceFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            ObjectContent content = actionExecutedContext.Response.Content as ObjectContent;
            if (content != null)
            {
                Type returnType = actionExecutedContext.ActionContext.ActionDescriptor.ReturnType;
                if (returnType.IsInterface && content.Formatter is JsonMediaTypeFormatter)
                {
                    var formatter = new JsonMediaTypeFormatter
                        {
                            SerializerSettings =
                                {
                                    ContractResolver = new InterfaceContractResolver(returnType)
                                }
                        };
                    actionExecutedContext.Response.Content = new ObjectContent(content.ObjectType, content.Value, formatter);
                }
            }
        }
    }
Community
  • 1
  • 1
Dejan
  • 9,150
  • 8
  • 69
  • 117