简体   繁体   中英

Why do I receive null values in my controller when I submit a form from a view with multiple forms? With ASP.NET Core 5 MVC

I am developing a web application using ASP.NET Core 5 MVC, in which I seek to make multiple submissions of POST type forms to my controller from a view that receives an IEnumerable (from a model called Result ) with which I am filling in dynamically the values of the inputs of each form.

However, when I send one of those forms from the view through the controller, in the controller I only receive an object from the model with all the null or empty values, which tells me that it seems that this data was never sent through the form to my controller.

Is there a better way to accomplish this or how do I pass these values from multiple forms to my controller? In advance an apology if what I am doing is already totally wrong, I have been learning ASP.NET Core MVC for a few days.

CONSIDERATIONS

What I seek to achieve is that the user can enter multiple values that belong to the same model in the same view, since each form although it is the same seeks to update a different record or column in the same model or table, so when the submit of the form is sent to the Controller the view does not change, and only the records in the database are updated with each submit in the view. If there is a better way or correct way to do this, I am willing to change the logic, because as I mentioned, I have been using the Framework for little.

Explained the problem and my goal, I will explain in greater detail the flow and code mentioned:

  1. From the Mechanical method of my controller, I return a list of Objects to their corresponding View, which are brought by a DataBaseContext :

     // CONTROLLER() that passes an enumerable list of Objects to View Mechanical.cshtml public IActionResult Mechanical() { IEnumerable<Result> objList = _db.Results; return View(objList); }
  2. In the Mechanical() view, I get this list of objects and iterate over it through a forEach() loop, where for each object I create a form that directs to the same controller method called Update() , in which I get the values of the object in null and empty (that being my problem):

// VIEW
@model IEnumerable<FatForm.Models.Result>

@if (Model.Count() > 0)
{
    @foreach(var result in Model)
    {
        <form method="post" asp-action="Update">
            <input asp-for="@result.Id" hidden />
            <input asp-for="@result.Type" hidden />
            <input asp-for="@result.FatId" hidden />
            <div class="border p-3">
                <div class="form-group row">
                    <h2 class="text-black-50 pl-3">Edit Result</h2>
                </div>
                <div class="row">
                    <div class="col-12">
                        <div class="form-group row">
                            <div class="col-3">
                                <label asp-for="@result.Section"></label>
                            </div>
                            <div class="col-3">
                                <label asp-for="@result.Procedure"></label>
                            </div>
                            <div class="col-3">
                                <label asp-for="@result.ResultDescription"></label>
                            </div>
                            <div class="col-3">
                                <label asp-for="@result.Passed"></label>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-3">
                                <input asp-for="@result.Section" class="form-control" />
                            </div>
                            <div class="col-3">
                                <input asp-for="@result.Procedure" class="form-control" />
                            </div>
                            <div class="col-3">
                                <input asp-for="@result.ResultDescription" class="form-control" />
                                <span asp-validation-for="@result.ResultDescription" class="text-danger"></span>
                            </div>
                            <div class="col-3">
                                <input asp-for="@result.Passed" class="form-control" />
                                <span asp-validation-for="@result.Passed" class="text-danger"></span>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-8 offset-2 row">
                                <div class="col">
                                    <input type="submit" class="btn btn-info w-75" value="Save" />
                                </div>
                            </div>
                        </div>

                    </div>
                </div>
            </div>
        </form>        
    }
}
else
{
    <p>No results created yet</p>
}

@section Scripts{
    @{
        <partial name="_ValidationScriptsPartial" />
    }
}
  1. I'm supposed to be looking to send the form values to the following Update() controller method, in which I get all the object values to null:

     // POST Update [HttpPost] [ValidateAntiForgeryToken] public IActionResult Update(Result obj) { if (ModelState.IsValid) { _db.Results.Update(obj); _db.SaveChanges(); //return RedirectToAction("Index"); } return View(obj); }

在这里您可以从视图中看到控制器上的空值

As I explained at the beginning, I hope can help me by indicating what I am doing wrong or in what way I should do it. Thanks in advance for your help.

Here you need to add FromBody attribute in your action method parameter.

public IActionResult Update([FromBody]Result obj)
{
   .....
}

Model binding looks through the sources for the name pattern prefix.property_name . If nothing is found, it looks for just property_name without the prefix.In your code,the asp-for tag helper will generate the name like: result.propertyName .It could not match with backend model. You need use [Bind(Prefix ="result")] to specify the prefix:

[HttpPost]
[ValidateAntiForgeryToken]

public IActionResult Update([Bind(Prefix ="result")]Result obj)
{
    //do your stuff...
}

As for receive IEnumerable parameter in action, firstly you need change your razor view to move the form outside the foreach loop, then you need change the asp-for tag helper tattribute to @Model.ToList()[index].PropertyName :

@model IEnumerable<Result>

@if (Model.Count() > 0)
{
    <form method="post" asp-action="Update">
        @for (int i = 0; i < Model.Count(); i++)
        {
            <input asp-for="@Model.ToList()[i].Id" hidden />
            <input asp-for="@Model.ToList()[i].Type" hidden />
            <input asp-for="@Model.ToList()[i].FatId" hidden />
            <div class="border p-3">
                <div class="form-group row">
                    <h2 class="text-black-50 pl-3">Edit Result</h2>
                </div>
                <div class="row">
                    <div class="col-12">
                        <div class="form-group row">
                            <div class="col-3">
                                <label asp-for="@Model.ToList()[i].Section"></label>
                            </div>
                            <div class="col-3">
                                <label asp-for="@Model.ToList()[i].Procedure"></label>
                            </div>
                            <div class="col-3">
                                <label asp-for="@Model.ToList()[i].ResultDescription"></label>
                            </div>
                            <div class="col-3">
                                <label asp-for="@Model.ToList()[i].Passed"></label>
                            </div>
                        </div>
                        <div class="form-group row">
                            <div class="col-3">
                                <input asp-for="@Model.ToList()[i].Section" class="form-control" />
                            </div>
                            <div class="col-3">
                                <input asp-for="@Model.ToList()[i].Procedure" class="form-control" />
                            </div>
                            <div class="col-3">
                                <input asp-for="@Model.ToList()[i].ResultDescription" class="form-control" />
                                <span asp-validation-for="@Model.ToList()[i].ResultDescription" class="text-danger"></span>
                            </div>
                            <div class="col-3">
                                <input asp-for="@Model.ToList()[i].Passed" class="form-control" />
                                <span asp-validation-for="@Model.ToList()[i].Passed" class="text-danger"></span>
                            </div>
                        </div>

                    </div>
                </div>
            </div>
        }
        <div class="form-group row">
            <div class="col-8 offset-2 row">
                <div class="col">
                    <input type="submit" class="btn btn-info w-75" value="Save" />
                </div>
            </div>
        </div>
    </form>
}
else
{
<p>No results created yet</p>
}

Controller:

[HttpPost]
[ValidateAntiForgeryToken]

public IActionResult Update(IEnumerable<Result> obj)
{
    return View("Mechanical", obj);
}

Result:

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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