我不知道如何在Web API控制器中处理继承的类。我必须创建仅一个 API控制器以创建和更新数据库中的继承对象。
类似于我的模型(所有这些模型都具有一个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
[HttpPost]
public ActionResult Post([FromBody]JObject json)
{
// idk what's going here?!
}
现在是我的控制器,但这切断了Dog或Cat模型的所有属性
[HttpPost]
public ActionResult Post([FromBody]AnimalDto animal)
{
// idk what's going here?!
}
我正在使用.NET Core 2.0
有什么想法吗?谢谢!
编辑
如果我想动态地执行此操作怎么办?像这样:
var animal = json.ToObject<Animal>();
var actualAnimal = json.ToObject<typeof(animal.Type)>();
我该怎么做?
答案 0 :(得分:0)
您没有提到您正在使用.NET Core或.NET Framework,但是这种行为的主要原因是模型绑定模块,该模块将数据从HTTP请求映射到操作方法参数。我认为您最好开发自己的自定义模型活页夹,并使用它代替默认的活页夹。
Here you can read more about custom model binding in asp .NET Core
Here you can read more about custom model binding in asp .NET MVC
答案 1 :(得分:0)
我已经尝试在控制器中使用json。但是json总是为空
总是得到null
的原因是您没有声明正确的Type
。您不应该通过string
来获得[FromBody]
类动物。
[HttpPost]public ActionResult Post([FromBody]string json)public ActionResult Post([FromBody]Dog dog) { // now you get the dog }
请注意,如果您根本不关心类型,则一种方法是声明dynamic
类型:
[HttpPost]
public IActionResult Post([FromBody] dynamic json)
{
return new JsonResult(json);
}
在这种情况下,动态类型为JObject
,您可以将它们强制转换为任意类型:
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模型的所有属性
如果您想使用AnimalDto
,则应使属性可访问:
public class AnimalDto {public string Name;public string Name{get;set;}public string Type;public string Type{get;set;} }
[编辑]
如果我想动态地执行此操作怎么办?像这样:
var animal = json.ToObject<Animal>(); var actualAnimal = json.ToObject<typeof(animal.Type)>();
如果我们想将json转换为某种特定类型,我们首先必须知道目标Type
是什么。但是您的animal.Type
属性是String
的类型,它可能是约定俗成的字符串。如果此Type
属性恰好是没有名称空间的类名,例如
Cat.Type
必须等于Cat
Dog.Type
必须等于Dog
Fish.Type
必须等于Fish
然后您可以使用Type.GetType()
来解析目标类型。例如:
// 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
的方式。然后通过方法Type
将json对象投射到所需的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);
}