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

时间:2022-12-30 21:31:10

I want to have an API as such:

我希望有这样的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();
    }
}

I'm getting a null value for 'package' so I'm wondering what might be going wrong. My only thoughts are that the default JSON serializer can't handle this, but I'm unclear how to fix it.

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

4 个解决方案

#1


14  

You can do this fairly easily with a custom model binder. Here is what worked for me. (Using Web API 2 and JSON.Net 6)

您可以使用自定义模型绑定器轻松完成此操作。这对我有用。 (使用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;
    }
}

The Web API controller looks like this. (Note: should also work for regular MVC actions -- I've done something like this for them before as well.)

Web API控制器看起来像这样。 (注意:也应该适用于常规的MVC操作 - 我之前也为他们做了类似的事情。)

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

I should also note that when you serialize the JSON, you should serialize it with the same setting, and serialize it as an interface to make the Auto kick in and include the type hint. Something like this.

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

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

#2


5  

You are trying to deserialise to an interface. The serialiser won't know what type to instantiate unless it is told.

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

Take a look at TypeNameHandling option Posting a collection of subclasses

查看TypeNameHandling选项发布子类集合

Or look at creating a custom JsonConverter. Take a look at this question How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

或者看看创建自定义JsonConverter。看看这个问题如何在JSON.NET中实现自定义JsonConverter来反序列化基类对象的列表?

#3


3  

Json.NET (the default Json serializer for ASP.NET Web API) can handle this situation. All you need to do is change the serializer settings, and set TypeNameHandling to All (or Objects). This will add a "$type"-json property to your json, containing the type name of your instance. On the other side it'll try to deserialize to this type again.

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

We used this for ourselves, taking an abstract base class as type.

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

#4


1  

The serializer needs a type that it can construct, one with an empty (Default) constructor. Since an Interface can't be constructed, serialization fails and you get a null value.

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

Two options:

两种选择:

  1. Use a POCO (Plain Old Clr Object) with a default constructor
  2. 使用POCO(Plain Old Clr Object)和默认构造函数
  3. Implement your own binder using IActionValueBinder
  4. 使用IActionValueBinder实现您自己的活页夹

#1


14  

You can do this fairly easily with a custom model binder. Here is what worked for me. (Using Web API 2 and JSON.Net 6)

您可以使用自定义模型绑定器轻松完成此操作。这对我有用。 (使用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;
    }
}

The Web API controller looks like this. (Note: should also work for regular MVC actions -- I've done something like this for them before as well.)

Web API控制器看起来像这样。 (注意:也应该适用于常规的MVC操作 - 我之前也为他们做了类似的事情。)

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

I should also note that when you serialize the JSON, you should serialize it with the same setting, and serialize it as an interface to make the Auto kick in and include the type hint. Something like this.

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

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

#2


5  

You are trying to deserialise to an interface. The serialiser won't know what type to instantiate unless it is told.

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

Take a look at TypeNameHandling option Posting a collection of subclasses

查看TypeNameHandling选项发布子类集合

Or look at creating a custom JsonConverter. Take a look at this question How to implement custom JsonConverter in JSON.NET to deserialize a List of base class objects?

或者看看创建自定义JsonConverter。看看这个问题如何在JSON.NET中实现自定义JsonConverter来反序列化基类对象的列表?

#3


3  

Json.NET (the default Json serializer for ASP.NET Web API) can handle this situation. All you need to do is change the serializer settings, and set TypeNameHandling to All (or Objects). This will add a "$type"-json property to your json, containing the type name of your instance. On the other side it'll try to deserialize to this type again.

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

We used this for ourselves, taking an abstract base class as type.

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

#4


1  

The serializer needs a type that it can construct, one with an empty (Default) constructor. Since an Interface can't be constructed, serialization fails and you get a null value.

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

Two options:

两种选择:

  1. Use a POCO (Plain Old Clr Object) with a default constructor
  2. 使用POCO(Plain Old Clr Object)和默认构造函数
  3. Implement your own binder using IActionValueBinder
  4. 使用IActionValueBinder实现您自己的活页夹