FLICKER
FLICKER

Reputation: 6693

Object property is NULL, in MVC Edit action

Using below models

public class State
{
    public int StateId { get; set; }
    public string Code { get; set; }
    public string Name { get; set; }
}

public class City
{
    public int CityId { get; set; }
    public string Name { get; set; }
    public State state { get; set; }
}

and following View

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()

    <div class="form-horizontal">
        <h4>City</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
        @Html.HiddenFor(model => model.CityId)
        @Html.HiddenFor(model => model.state.StateId)
        @Html.HiddenFor(model => model.state.Name)
        @Html.HiddenFor(model => model.state.Code)


        <div class="form-group">
            @Html.LabelFor(model => model.Name, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Name, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Name, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
}

I see the State is NULL in my controller

public ActionResult Edit([Bind(Include = "CityId,Name")] City city)
{
    // City.State is NULL and ModelSAtate.IsValid is FALSE
    if (ModelState.IsValid)
    {
        db.Entry(city).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(city);
}

By this mean, City.State is NULL.

I know the workaround to make ModelState.IsValid to TRUE but I like to know the right way for hanlding object property in MVC View.

Upvotes: 3

Views: 1107

Answers (2)

taimur alam
taimur alam

Reputation: 576

Whenever you try to process a request from your view to your controller, MVC Routing tries to identify which controller action to invoke according to your route configuration. This job is assigned to the ControllerActionInvoker. After successfully identifying which action to invoke, now the default model binder takes control of binding the model correctly.

The Default Model Binding(DefaultModelBinder) works in the following order :-

  1. Request.Form - Values submitted in the form

  2. RouteData.Values - Route values e.g. id in /Employee/Edit/{id}

  3. Request.QueryString - Data extracted from the query string portion of the URL

  4. Request.Files - Uploaded Files

    There are ways to customize your binding behaviour, you may find this article interesting - https://mono.software/2017/02/09/model-binding-asp-net-mvc/

But for your problem, the given answer by @Marusyk is sufficient enough. Happy coding...

Upvotes: 0

Roman Marusyk
Roman Marusyk

Reputation: 24619

You should to add also these hidden property if you want to catch State entity in your action as a part of City

@Html.HiddenFor(model => model.state.StateId)
@Html.HiddenFor(model => model.state.Name)
@Html.HiddenFor(model => model.state.Code)

EDIT: I also had to remove the Bind() section so my action look like

public ActionResult Edit(City city)

Upvotes: 3

Related Questions