在.NET Web API POST/PUT方法中使用继承的类 [英] Using inherited classes in .NET web API POST/PUT method
问题描述
我不知道如何在Web API控制器中处理继承的类.我必须创建一个 API控制器以创建和更新数据库中的继承对象.
I can't figure out how I can work with inherited classes in an web API controller. I have to create only one API controller to create and update inherited objects in the database.
类似于我的模型(所有这些模型都具有一个Dto):
Similar to my models (to all these models exists a Dto):
public class Animal
{
public virtual string Name {get; set;} // e.g. Harry
public virtual string Type {get; set;} // e.g. Dog
}
public class AnimalDto
{
public string Name;
public Type Type;
}
public class Dog : Animal
{
public virtual bool CanBark {get; set;} // e.g. true
}
public class Cat : Animal
{
public virtual bool CanMiau {get; set;}
}
我已经尝试在控制器中使用json了.但是总是有json null
I already tried to use the json in the controller. But there was the json always null
[HttpPost]
public ActionResult Post([FromBody]JObject json)
{
// idk what's going here?!
}
现在是我的控制器,但这切断了Dog或Cat模型的所有属性
My controller now, but that cuts off all attributes of Dog or Cat model
[HttpPost]
public ActionResult Post([FromBody]AnimalDto animal)
{
// idk what's going here?!
}
我正在使用.NET Core 2.0
I'm using .NET Core 2.0
有什么想法吗?谢谢!
编辑
如果我想动态地执行此操作怎么办?像这样:
What if I want to do this dynamically? Something like:
var animal = json.ToObject<Animal>();
var actualAnimal = json.ToObject<typeof(animal.Type)>();
我该怎么做?
推荐答案
我已经尝试在控制器中使用json了.但是json总是为空
I already tried to use the json in the controller. But there was the json always null
总是得到null
的原因是您没有声明正确的Type
.您不应该通过[FromBody]
接收string
类型的动物.
The reason why you always get null
is that you didn't declare the correct Type
. You're not supposed to receive a string
type of animal via [FromBody]
.
[HttpPost]
public ActionResult Post([FromBody]string json)
public ActionResult Post([FromBody]Dog dog)
{
// now you get the dog
}
请注意,如果您根本不关心类型,则一种方法是声明dynamic
类型:
As a side note, if you don't care the type at all, one approach is to declare a dynamic
type:
[HttpPost]
public IActionResult Post([FromBody] dynamic json)
{
return new JsonResult(json);
}
在这种情况下,动态类型为JObject
,您可以将它们强制转换为任意类型:
In this scenario, the dynamic type is JObject
, you could cast them to any type as you like:
public IActionResult Post(/*[ModelBinder(typeof(AnimalModelBinder))]*/[FromBody] JObject json)
{
var animal=json.ToObject<Animal>();
var dog = json.ToObject<Dog>();
return new JsonResult(json);
}
现在是我的控制器,但这切断了Dog或Cat模型的所有属性
My controller now, but that cuts off all attributes of Dog or Cat model
如果要使用AnimalDto
,则应使属性可访问:
If you would like to use the AnimalDto
, you should make the properties accessible:
public class AnimalDto
{
public string Name;
public string Name{get;set;}
public string Type;
public string Type{get;set;}
}
如果我想动态地执行此操作怎么办?像这样:
What if I want to do this dynamically? Something like:
var animal = json.ToObject<Animal>();
var actualAnimal = json.ToObject<typeof(animal.Type)>();
如果我们想将json转换为某种特定类型,我们首先必须知道目标Type
是什么.但是您的animal.Type
属性是String
的类型,并且可能是约定俗成的字符串.如果此Type
属性恰好是没有名称空间的类名,例如
If we want to cast the json to some particular type, we must firstly know what the target Type
is . But your animal.Type
property is a type of String
, and that might be a by-convention string. If this Type
property is exactly the class name without namespace , e.g.
-
Cat.Type
必须等于Cat
-
Dog.Type
必须等于Dog
-
Fish.Type
必须等于Fish
Cat.Type
must equalsCat
Dog.Type
must equalsDog
Fish.Type
must equalsFish
然后您可以使用Type.GetType()
解析目标类型.例如:
then you can you use Type.GetType()
to resolve the target type. For example :
// typename : the Animal.Type property
// ns : the namespace string
private Type ResolveAnimalType(string typename,string ns){
if(string.IsNullOrEmpty(ns)){ ns = "App.Models";}
typename= $"{ns}.{typename}";
var type=Type.GetType(
typename,
assemblyResolver:null, // if you would like load from other assembly, custom this resovler
typeResolver: (a,t,ignore)=> a == null ?
Type.GetType(t, false, ignore) :
a.GetType(t, false, ignore),
throwOnError:true,
ignoreCase:false
);
return type;
}
无论如何,您可以根据自己的需求自定义我们解决目标Type
的方式.然后通过方法ToObject<T>()
将json对象投射到所需的Type
中:
Anyway, you could custom the way we resolve the target Type
according to your own needs. And then cast the json object to your wanted Type
by method ToObject<T>()
:
[HttpPost]
public IActionResult Post([FromBody] JObject json)
{
var typename = json.Value<string>("type");
if(String.IsNullOrEmpty(typename))
ModelState.AddModelError("json","any animal must provide a `type` property");
// resolve the target type
var t= ResolveAnimalType(typename,null);
// get the method of `.ToObject<T>()`
MethodInfo mi= typeof(JObject)
.GetMethods(BindingFlags.Public|BindingFlags.Instance)
.Where(m=> m.Name=="ToObject" && m.GetParameters().Length==0 && m.IsGenericMethod )
.FirstOrDefault()
?.MakeGenericMethod(t); // ToObject<UnknownAnimialType>()
var animal = mi?.Invoke(json,null);
return new JsonResult(animal);
}
这篇关于在.NET Web API POST/PUT方法中使用继承的类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!