我可以将基于接口的对象传递给MVC 4 Web Api POST吗?

时间:2013-01-02 14:58:23

标签: c# asp.net-mvc post interface asp.net-web-api

我希望有这样的API:

public class RelayController : ApiController
{
    // POST api/values
    public void Post([FromBody]IDataRelayPackage package)
    {
        MessageQueue queue = new MessageQueue(".\\private$\\DataRelay");
        queue.Send(package);
        queue.Close();
    }
}

我得到'package'的空值,所以我想知道可能出现什么问题。我唯一的想法是默认的JSON序列化程序无法处理这个,但我不清楚如何解决它。

4 个答案:

答案 0 :(得分:17)

使用自定义模型绑定器可以相当轻松地完成此操作。这对我有用。 (使用Web API 2和JSON.Net 6)

public class JsonPolyModelBinder : IModelBinder
{
    readonly JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)
    {
        var content = actionContext.Request.Content;
        string json = content.ReadAsStringAsync().Result;
        var obj = JsonConvert.DeserializeObject(json, bindingContext.ModelType, settings);
        bindingContext.Model = obj;
        return true;
    }
}

Web API控制器如下所示。 (注意:也应该适用于常规的MVC操作 - 我之前也为他们做了类似的事情。)

public class TestController : ApiController
{
    // POST api/test
    public void Post([ModelBinder(typeof(JsonPolyModelBinder))]ICommand command)
    {
        ...
    }
}

我还应该注意,当您序列化JSON时,您应该使用相同的设置对其进行序列化,并将其序列化为接口以使Auto启动并包含类型提示。这样的事情。

    JsonSerializerSettings settings = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto };
    string json = JsonConvert.SerializeObject(command, typeof(ICommand), settings);

答案 1 :(得分:5)

您正在尝试反序列化到接口。除非被告知,否则序列化程序将不知道要实例化的类型。

查看TypeNameHandling选项Posting a collection of subclasses

或者看看创建自定义JsonConverter。看看这个问题How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

答案 2 :(得分:3)

Json.NET(ASP.NET Web API的默认Json序列化程序)可以处理这种情况。您需要做的就是更改序列化程序设置,并将TypeNameHandling设置为All(或Objects)。这将为您的json添加一个“$ type”-json属性,其中包含您实例的类型名称。另一方面,它会尝试再次反序列化为此类型。

我们自己使用它,将抽象基类作为类型。

答案 3 :(得分:1)

序列化程序需要一个可以构造的类型,一个带有空(默认)构造函数的类型。由于无法构造接口,因此序列化失败并且您获得空值。

两个选项:

  1. 使用带有默认构造函数的POCO(Plain Old Clr对象)
  2. Implement your own binder using IActionValueBinder