Бесконечный цикл при привязке модели при использовании атрибута [ModelBinder] - PullRequest
0 голосов
/ 14 ноября 2018

Я изначально разместил эту проблему на GitHub здесь: https://github.com/aspnet/Mvc/issues/8723

Здесь есть репозиторий GitHub с репродукцией проблемы: https://github.com/Costo/aspnetcore-binding-bug

Я использую ASP.NET Core 2.2 Preview 3.

При использовании пользовательского связывателя модели (с атрибутом [ModelBinder]) в свойствах массива «дочерних» моделей фаза связывания модели запроса переходит в бесконечный цикл. Смотрите этот скриншот:

Model binding looping infinitely

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

Спасибо!


Вот код модели, контроллера, вида и пользовательского связующего:

Модель:

public class TestModel
{
    public TestInnerModel[] InnerModels { get; set; } = new TestInnerModel[0];

    [ModelBinder(BinderType = typeof(NumberModelBinder))]
    public decimal TopLevelRate { get; set; }
}

public class TestInnerModel
{
    public TestInnerModel()
    {
    }

    [ModelBinder(BinderType = typeof(NumberModelBinder))]
    public decimal Rate { get; set; }
}

Пользовательская модель переплета (намеренно упрощена, чтобы не делать ничего особенного):

public class NumberModelBinder : IModelBinder
{
    private readonly NumberStyles _supportedStyles = NumberStyles.Float | NumberStyles.AllowThousands;
    private DecimalModelBinder _innerBinder;

    public NumberModelBinder(ILoggerFactory loggerFactory)
    {
        _innerBinder = new DecimalModelBinder(_supportedStyles, loggerFactory);
    }

    /// <inheritdoc />
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        return _innerBinder.BindModelAsync(bindingContext);
    }
}

Контроллер:

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View(new TestModel
        {
            TopLevelRate = 20m,
            InnerModels = new TestInnerModel[]
            {
                new TestInnerModel { Rate = 2.0m },
                new TestInnerModel { Rate = 0.2m }
            }
        });
    }

    [HttpPost]
    public IActionResult Index(TestModel model)
    {
        return Ok();
    }
}

Razor view:

@model TestModel;

<form asp-controller="Home" asp-action="Index" method="post" role="form">
    <div>
        <input asp-for="@Model.TopLevelRate" type="number" min="0" step=".01" />

    </div>
    <div>
        @for (var i = 0; i < Model.InnerModels.Length; i++)
        {
            <input asp-for="@Model.InnerModels[i].Rate" type="number" min="0" step=".01" />
        }
    </div>

    <input type="submit" value="Go" />
</form>

1 Ответ

0 голосов
/ 14 ноября 2018

A решение было опубликовано в выпуске GitHub:

@ Costo Проблема в том, что вы не сообщаете системе привязки модели, что в связывателе используются поставщики значений.ComplexTypeModelBinder всегда считает, что данные доступны для следующего экземпляра TestInnerModel, а самый внешний механизм связывания (CollectionModelBinder) продолжает работать - вечно.Чтобы исправить это,

[MyModelBinder]
public decimal Rate { get; set; }

private class MyModelBinderAttribute : ModelBinderAttribute
{
    public MyModelBinderAttribute()
        : base(typeof(NumberModelBinder))
    {
        BindingSource = BindingSource.Form;
    }
}

Другими словами, BindingSource.Custom значение по умолчанию [ModelBinder] не правильно в этом сценарии.К счастью, пользовательские привязки моделей для свойств типов POCO в контейнерах должны быть одним из немногих случаев, когда это имеет значение.

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