Я уже пытался использовать JSON в контроллере. Но был JSON всегда ноль
Причина, по которой вы всегда получаете null
, заключается в том, что вы не указали правильный Type
. Вы не должны получать животное типа string
через [FromBody]
.
[HttpPost]
<strike>public ActionResult Post([FromBody]string json)</strike>
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
{
<strike>public string Name;</strike>
public string Name{get;set;}
<strike>public string Type;</strike>
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
в соответствии с вашими потребностями . А затем приведите объект json к желаемому Type
по методу 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);
}