Несколько параметров модели в действии - PullRequest
0 голосов
/ 10 июня 2019

У меня есть действие, которое будет вызываться с необязательными параметрами строки запроса. Эти параметры, однако, содержатся в разных моделях представления. Когда я пытаюсь добавить эти модели в свой список параметров, заполняется только одна, а остальные всегда равны нулю. За исключением пустой строки запроса, где все модели создаются со значениями по умолчанию.

Нельзя вложить эти модели по той причине, что я не хочу, чтобы имя вложенного свойства было видно в строке запроса. Поэтому, если это не может быть каким-либо образом обойдено, это также будет жизнеспособным решением.

Я заметил, что при создании быстрого переопределения DefaultModelBuilder все модели анализируются, но в результате все равно остается только одна модель.

Это мой сценарий:

public ActionResult Index(ModelA ma, ModelB ba)
{
    return Content("ok");
}
public class ModelA
{
    public string Test { get; set; }
    public string Name { get; set; }
}

public class ModelB
{
    public int? SomeInteger { get; set; }
    public int? TestInteger { get; set; }
}

Желаемая строка запроса:

index?Test=Hi&SomeInteger=7

Чего я хочу избежать:

index?ModelA.Test=Hi&ModelB.SomeInteger=7

Ответы [ 3 ]

0 голосов
/ 10 июня 2019

Вы можете попытаться создать класс, объединяющий эти два:

public class ModelPair
{
    public ModelA A { get; set; }
    public ModelB B { get; set; }
}

И затем с

public ActionResult Index(ModelPair mp)
{
    return Content("ok");
}

Вы можете сделать ?A.Test=blah&B.SomeInteger=42

0 голосов
/ 11 июня 2019

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

Так что теперь у меня естьследующая структура класса:

public class ModelA
{
    public string Test { get; set; }
    public string Name { get; set; }
}

public class ModelB
{
    public int? SomeInteger { get; set; }
    public int? TestInteger { get; set; }
}

public class ViewModel
{
    public ModelA ModelA { get; set; }
    public ModelB ModelB { get; set; }
}

И теперь действие выглядит следующим образом:

public ActionResult Index(ViewModel model)
{
    return Content("ok");
}

, что позволит мне использовать следующую строку запроса без раскрытия уродливых имен свойств:

index?Test=Hi&SomeInteger=7&Name=Yep&TestInteger=72

Конечно, я не тестировал это в течение длительного периода времени, поэтому я не знаю, какие проблемы скрываются за углом, но все вложенные модели теперь правильно заполнены данными изСтрока запроса и классы модели могут быть легко использованы повторно:)

public class RecursiveModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        var model = base.BindModel(controllerContext, bindingContext);
        if (model != null)
        {
            var properties = bindingContext.ModelType.GetProperties().Where(x => x.PropertyType.IsClass && !x.PropertyType.Equals(typeof(string)) );
            foreach(var property in properties)
            {
                var resursiveBindingContext = new ModelBindingContext(bindingContext)
                {
                    ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(null, property.PropertyType)
                };
                var recursiveModel = BindModel(controllerContext, resursiveBindingContext);
                property.SetValue(model, recursiveModel);
            }
        }
        return model;
    }
}
0 голосов
/ 10 июня 2019

Насколько я знаю, связыватель модели по умолчанию не может этого сделать.мы должны реализовать пользовательскую модель Binder следующим образом.

 public class CustomModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        var query = bindingContext.HttpContext.Request.Query;


        var modelb = new ModelB();
        if (query.TryGetValue($"{bindingContext.ModelName}.{nameof(modelb.SomeInteger)}", out var someInteger))
        {
            modelb.SomeInteger = Convert.ToInt32(JsonConvert.DeserializeObject(someInteger).ToString());
        }
        if (query.TryGetValue($"{bindingContext.ModelName}.{nameof(modelb.TestInteger)}", out var testInteger))
        {
            modelb.TestInteger = Convert.ToInt32(JsonConvert.DeserializeObject(testInteger).ToString());
        }

        bindingContext.Result = ModelBindingResult.Success(modelb);
        return Task.FromResult(modelb);
    }
}

В действии контроллера мы можем использовать Binder следующим образом

   public IActionResult Index(ModelA modelA, [ModelBinder(typeof(CustomModelBinder))]ModelB modelB)
    {
        return Json(new {modelA, modelB});
    }

И в строке запроса мы можем иметь префикс для дифференциации каждой модели.

?modelA.test="MATests"&modelA.Name="modelANameValue"&modelB.SomeInteger="5"

Здесь вы найдете рабочий образец здесь, на github

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