Использование унаследованных классов в методе POST / PUT веб-API .NET - PullRequest
0 голосов
/ 12 января 2019

Я не могу понять, как я могу работать с унаследованными классами в контроллере веб-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 в контроллере. Но Джонс всегда был 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

Есть идеи? Спасибо!

EDIT

Что если я хочу сделать это динамически? Что-то вроде:

var animal = json.ToObject<Animal>();
var actualAnimal = json.ToObject<typeof(animal.Type)>();

Как я могу это сделать?

Ответы [ 2 ]

0 голосов
/ 14 января 2019

Я уже пытался использовать 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); 
}
0 голосов
/ 12 января 2019

Вы не упомянули, что используете .NET Core или .NET Framework, но основной причиной такого поведения является модуль привязки модели, который отображает данные из HTTP-запросов в параметры метода действия. Я думаю, что вам лучше разработать свой собственный механизм связывания моделей и использовать его вместо стандартного.

Здесь вы можете узнать больше о привязке пользовательских моделей в asp .NET Core

Здесь вы можете узнать больше о привязке пользовательской модели в asp .NET MVC

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...