简体   繁体   English

如何在发布时将表单字段绑定到嵌套的 model?

[英]How can I bind form fields to a nested model on post?

I am coding a solution where the user will submit a form, posting the values back to my ASP.NET MVC controller. My model is complex and the form fields are contained in a nested object (I'm using CQRS via MediatR).我正在编写一个解决方案,用户将在其中提交表单,将值发回我的 ASP.NET MVC controller。我的 model 很复杂,表单字段包含在嵌套的 object 中(我通过 MediatR 使用 CQRS)。 When I submit the form, the values come across as null. How can I get the complex model to recognize the form fields?当我提交表单时,这些值显示为 null。如何让复杂的 model 识别表单字段?

Here is my code:这是我的代码:

Controller: Controller:

        [HttpPost]
        [Route("edit")]
        public async Task<IActionResult> Edit(UpdateApplicationCommand command)
        {
            await _mediator.Send(command)
                .ConfigureAwait(false);

            return RedirectToAction("Index");
        }

Models:楷模:

    public class UpdateApplicationCommand : IRequest<Unit>
    {
        public ApplicationEditGeneralViewModel ApplicationEditGeneralViewModel { get; set; } = null!;
    }

    public class ApplicationEditGeneralViewModel
    {
        [Required]
        public string Name { get; set; } = string.Empty;

        public string Description { get; set; } = string.Empty;
    }

View:看法:

    @model ApplicationEditGeneralViewModel

        <form method="post" asp-action="Edit" asp-controller="Applications">
            <div class="form-floating mb-3">
                @Html.TextBoxFor(m => m.Name, new { @class = "form-control", placeholder = "Application Name"})
                <label for="Name">Application Name</label>
            </div>
            <div class="form-floating mb-3">
                @Html.TextBoxFor(m => m.Description, new { @class = "form-control", placeholder = "Application Description"})
                <label for="Description">Application Description</label>
            </div>
            <div class="d-flex flex-row-reverse bd-highlight">
                <input type="submit" value="Submit" class="btn btn-primary mt-2" />
            </div>
        </form>

I've tried to reduce the complex model to its fields, by placing the contents of the ApplicationEditGeneralViewModel directly into the UpdateApplicationCommand class. This worked, but I'd really like to keep the nested structure so that I can reuse the ApplicationEditGeneralViewModel object.我试图通过将ApplicationEditGeneralViewModel的内容直接放入UpdateApplicationCommand class 来将复杂的 model 减少到它的字段。这有效,但我真的很想保留嵌套结构,以便我可以重用ApplicationEditGeneralViewModel object。

I saw this solution here:我在这里看到了这个解决方案:

But I'd rather avoid adding the name as a route object (if possible) for every form field.但我宁愿避免为每个表单字段添加名称作为路由 object(如果可能)。 Is there another, more simple way that I can do this?还有另一种更简单的方法可以做到这一点吗?

The first way, you can custom model binding like below:第一种方式,您可以自定义 model 绑定,如下所示:

public class CustomModelBinder : IModelBinder
{
    public Task BindModelAsync(ModelBindingContext bindingContext)
    {
        if (bindingContext == null)
            throw new ArgumentNullException(nameof(bindingContext));
        var model = new UpdateApplicationCommand()
        {
            ApplicationEditGeneralViewModel = new ApplicationEditGeneralViewModel()
            {
                Description = bindingContext.ValueProvider.GetValue("Description").ToString(),
                Name = bindingContext.ValueProvider.GetValue("Name").ToString()
            }
        };
        bindingContext.Result = ModelBindingResult.Success(model);
        return Task.CompletedTask;
    }
}

Apply the custom model binding like below:像下面这样应用自定义 model 绑定:

[HttpPost]
public async Task<IActionResult> Edit([ModelBinder(typeof(CustomModelBinder))]UpdateApplicationCommand model)
{
    //.....
}

The second way, just change your razor view like below:第二种方式,只需更改您的 razor 视图,如下所示:

@model UpdateApplicationCommand

<form method="post">
    <div class="form-floating mb-3">
        @Html.TextBoxFor(m => m.ApplicationEditGeneralViewModel.Name, new { @class = "form-control", placeholder = "Application Name"})
        <label for="Name">Application Name</label>
    </div>
    <div class="form-floating mb-3">
        @Html.TextBoxFor(m => m.ApplicationEditGeneralViewModel.Description, new { @class = "form-control", placeholder = "Application Description"})
        <label for="Description">Application Description</label>
    </div>
    <div class="d-flex flex-row-reverse bd-highlight">
        <input type="submit" value="Submit" class="btn btn-primary mt-2" />
    </div>
</form>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM