【问题标题】:Web Api Model Binding and Polymorphic InheritanceWeb Api 模型绑定和多态继承
【发布时间】: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 动作时,对象为空

【问题讨论】:

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

标签: c# json asp.net-web-api json.net


【解决方案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方法接受的类型。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2016-12-20
        • 2013-03-09
        • 1970-01-01
        • 2018-02-15
        • 2021-06-30
        • 2014-06-01
        • 1970-01-01
        相关资源
        最近更新 更多