Home > Software design >  Why model is null after postback in ASP.NET MVC
Why model is null after postback in ASP.NET MVC

Time:11-10

I'm developing an ASP.NET MVC app using the latest .NET Framework and VS 2019.

In my page, I have an simple textbox and a search button. When I click the search button and postback the form, in controller, I get model.Code is NULL

Here is my code - my view model:

public class UserManagementViewModel
{
    public string Code { get; set; }
    // some other properties including simple and complex types
}

In View:

<td style="min-width: 300px">
    @Html.TextBoxFor(m => m.Code)
</td>

In Controller:

[HttpPost]
public ActionResult UpdateUserPermissions(UserManagementViewModel model)
{
    // model.Code is null here!!
    return RedirectToAction("UserManagement");
}

After hours of research, I tried following:

I looked into html source and found

<input id="Code" name="Code">

Using Chrome dev tool, I change the name of the input to "Model.Code"

<input id="Code" name="Model.Code">

And this time, I got the entered value in textbox after postback.

I don't know why this happens and why the element name is not generated correctly!

What can I do?

Edit:

I have some other controls like checkbox and radio-buttons which I use pure HTMl code and name them beginning with "Model." like below instead of using @HTML helper.

And it works fine and I get the value in Action.

Workaround:

I found a workaround here: ASP.NET MVC 4 override emitted html name and id so I change my code to:

@Html.TextBoxFor(m => m.Code, new { @Name = "Model.Code" })

However this code helps me to fix my problem, I still don't know why the name generated by Razor engine is not working.

CodePudding user response:

The helper method @Html.TextBoxFor works absolutely correctly. Basically you need to use this method for almost all situations (except some situation when you need to use no-standard behavior).

Regarding your case I think you have trouble with HtmlFieldPrefix.

This property is used for generation HTML input name. We can review MVC source codes in GitHub...

MVC generated HTML input (GitHub link) using this code snippet:

private static MvcHtmlString InputHelper(HtmlHelper htmlHelper, InputType inputType, ModelMetadata metadata, string name, object value, bool useViewData, bool isChecked, bool setId, bool isExplicitValue, string format, IDictionary<string, object> htmlAttributes)
{
    string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name);
    if (String.IsNullOrEmpty(fullName))
    {
        throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name");
    }

    TagBuilder tagBuilder = new TagBuilder("input");
    tagBuilder.MergeAttributes(htmlAttributes);
    tagBuilder.MergeAttribute("type", HtmlHelper.GetInputTypeString(inputType));
    tagBuilder.MergeAttribute("name", fullName, true);

    string valueParameter = htmlHelper.FormatValue(value, format);
    bool usedModelState = false;

    ...

    return tagBuilder.ToMvcHtmlString(TagRenderMode.SelfClosing);
}

As we can see name property calculated by method GetFullHtmlFieldName.

This method we can also inspect on GitHub (link):

public string GetFullHtmlFieldName(string partialFieldName)
{
    if (partialFieldName != null && partialFieldName.StartsWith("[", StringComparison.Ordinal))
    {
        // See Codeplex #544 - the partialFieldName might represent an indexer access, in which case combining
        // with a 'dot' would be invalid.
        return HtmlFieldPrefix   partialFieldName;
    }
    else
    {
        // This uses "combine and trim" because either or both of these values might be empty
        return (HtmlFieldPrefix   "."   (partialFieldName ?? String.Empty)).Trim('.');
    }
}

This method calculates name using HtmlFieldPrefix property. So if you change this property you can modify your generated name.

I think you use partial Views and you need render property with some prefix for correct binding.

Please review next links with examples and possible solutions:

CodePudding user response:

in other to sumbmit model back you have to use form tags. MVC sometimes counts name as model property, but it is better to do it explicitly. This code was tested and both variants of textbox are working properly. And if you use the form you don't need any name at all, other contrary in the most cases you will get null if you use the name and form together.

@model UserManagementViewModel 

<form  asp-action="UpdateUserPermissions" method="post">

     @Html.TextBoxFor(m => m.Code)

    // or

    <div class="form-group">
        <label asp-for="Code" class="control-label"></label>
        <input asp-for="Code" class="form-control" />
    </div>
    
    <div>
        <button  type="submit"> submit </button>
    </div>

</form>
  • Related