Web Api 模型绑定和多态继承

Posted

技术标签:

【中文标题】Web Api 模型绑定和多态继承【英文标题】:Web Api Model Binding and Polymorphic Inheritance 【发布时间】:2013-06-21 02:00:56 【问题描述】:

我在问是否有人知道是否可以将继承自抽象类的具体类传递给 Web Api。

例如:

public abstract class A

    A();


public class B : A



[POST("api/Request/a")]
public class Request(A a)


目前我环顾四周,大多数解决方案似乎都说使用 TypeNameHandling 会起作用。

JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;

但事实并非如此。此外,我的模型正在从控制台应用程序传递到 webapi。我读过我可能能够反序列化 json 对象,在尝试了几次之后,我决定这不起作用。

我已经研究过创建一个客户模型绑定器,但是我不想让我的应用程序变得更加复杂。目前我从具有 3 个模型的抽象类继承,但将来可能会扩展它。正如您可能注意到的,添加自定义模型绑定器可能需要多个绑定器,除非有一种方法可以使一个绑定器对所有类型的抽象类都通用。

为了在我的控制台应用程序中对此进行扩展,我已经实例化了 b 类,然后在发布到我的 webapi 之前将其传递给 ObjectContent

item = B();

//serialize and post to web api
MediaTypeFormatter formatter;
JsonMediaTypeFormatter jsonFormatter = new JsonMediaTypeFormatter();
jsonFormatter.SerializerSettings.TypeNameHandling = TypeNameHandling.Auto;
formatter = jsonFormatter;

_content = new ObjectContent<A>(item, formatter);
var response = _client.PostAsync("api/Request", _content).Result;

当调用 webapi 动作时,对象为空

【问题讨论】:

您可以在这里查看我关于继承和模型绑定的回答:***.com/a/15518804/1184056 另外,JSON.NET 中的以下问题似乎已在今年 3 月得到修复。可能尝试获取最新版本的 Json.net,看看您的问题是否仍然存在:json.codeplex.com/workitem/23891 我已经对此进行了进一步研究并回答了我自己的问题。您无法通过模型绑定传递抽象类,因为您无法实例化抽象类。解决这个问题的唯一方法是使基础不抽象,这样模型绑定就可以完美地工作。 根据定义,您的请求参数是一个 DTO。避免 DTO 的继承,它几乎没有任何作用,如果必须,请编写。想想你将要实现什么——你从 HTTP 请求中获得一个属性包,然后选择 A 的随机实现并只填写基本字段以传递给你的方法?你没有一个结构良好的对象,它在普通的具体 DTO 之上没有任何用途。 【参考方案1】:

如果您真的想实现问题中提出的问题,可以使用一种自定义方法来实现。

首先,创建一个继承自 JsonConverter 的自定义 json 转换器,在其中选择一个目标类并反序列化一个实例。

然后,在您的 WebApiConfig.Register 中,将您的新转换器添加到 config.Formatters.JsonFormatter.SerializerSettings.Converters 并享受这个怪物的运行。

你应该这样做吗?没有。

了解如何使用此类 API 不会给任何新用户带来任何乐趣,记录这一点并不容易,最重要的是 - 以这种方式实现它没有任何好处。如果输入类型不同,那么它们应该使用具有不同 URL 的单独 API 方法。如果只有少数属性不同 - 将它们设为可选。

为什么这个例子不起作用? TypeNameHandling 来自 Json.NET,Web API 对此一无所知,并且类型信息不属于 JSON 规范,因此没有解决此特定问题的标准方法。

【讨论】:

【参考方案2】:

请将[POST("api/Request/a")] 更改为[POST("api/Request")]。 您的参数来自正文,而不是路由。

【讨论】:

【参考方案3】:

您可以为此目的使用JsonSubTypes 转换器。 它是使用 Json.NET 进行多态反序列化的非常有用且简单的工具。

【讨论】:

【参考方案4】:

这可以通过默认模型绑定来实现。检查下面的方法。

public abstract class RequestBase

    public int ID  get; set; 


public class MyRequest : RequestBase

    public string Name  get; set; 




[RoutePrefix("api/home")]
public class HomeController : ApiController

    [HttpPost]
    [Route("GetName")]
    public IHttpActionResult GetName([FromBody]MyRequest _request)
    
        return Ok("Test");
    

【讨论】:

我猜这不是Ian的本意,他想用基类(不是派生类)作为api方法接受的类型。

以上是关于Web Api 模型绑定和多态继承的主要内容,如果未能解决你的问题,请参考以下文章

细说 Web API参数绑定和模型绑定

Web Api 模型绑定 一

csharp Web API的抽象模型绑定

Web API 无法使用 utf-16 编码的 XML 绑定 POST 模型

来自json的web api 2绑定模型

Python进阶(十六)----面向对象之~封装,多态,鸭子模型,super原理(单继承原理,多继承原理)