简体   繁体   中英

ASP.NET MVC not binding

hi i'm new to the asp mvc framework, and i've noticed that when i post to a controller it is not binded properly. i was trying to do a save a data to the database, but it was saving a blank data, i don't know why

here's my code for Model:

 public int ID { get; set; }
    public string UserName { get; set; }
    public string UserPass { get; set; }

    public UserLevel UserLevel { get; set; }

code for ViewModel:

public List<UserLevel> UserLevels { get; set; }
    public User Users { get; set; }

code for Controller:

    public ActionResult Index()
    {
        using (var ctx = new UserContext())
        {
            var users = ctx.Users.Include(u => u.UserLevel).ToList();

            return View(users);
        }
    }
    public ActionResult Create()
    {
        using (var ctx = new UserContext())
        {
            var userlevel = ctx.UserLevels.ToList();
            var vm = new UserViewModel()
            {
                UserLevels = userlevel
            };

            return View(vm);
        }
    }

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create([Bind] User user)
    {
        using(var ctx = new UserContext())
        {
            if (ModelState.IsValid)
            {
                ctx.Users.Add(user);
                ctx.SaveChanges();

                return RedirectToAction("Index", "Users");
            }
            else
            {
                return new EmptyResult();
            }
        }
    }

here's the view code:

@using (Html.BeginForm("Create", "Users"))

{ @Html.AntiForgeryToken()

@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
    @Html.LabelFor(model => model.Users.UserName, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Users.UserName, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Users.UserName, "", new { @class = "text-danger" })
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.Users.UserPass, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.EditorFor(model => model.Users.UserPass, new { htmlAttributes = new { @class = "form-control" } })
        @Html.ValidationMessageFor(model => model.Users.UserPass, "", new { @class = "text-danger" })
    </div>
</div>
<div class="form-group">
    @Html.LabelFor(model => model.Users.UserLevel, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.DropDownListFor(model => model.Users.UserLevel, new SelectList(Model.UserLevels, "ID", "Name"), "", new { @class = "form-control" })
        @Html.ValidationMessageFor(model => model.Users.UserLevel, "", new { @class = "text-danger" })
    </div>
</div>
<div class="form-group">
    <input type="submit" class="btn btn-primary" value="Submit" />
</div>

}

Thanks in advance

Your current code will generate HTML markup like below for the input elements

<input name="Users.UserName" type="text" value="">

and you are submitting this form to an action method which has a parameter of type User . For model binding to work, the form input element's name attribute values should match to the structure of your parameter type. That means, if your parameter type is User , which has properties like UserName , your input element name should be also UserName .

The best way to solve your problem is to use pure a view model for your view. Do not mix your entity models in the view models. view models are simply POCOS with properties absolutely needed by the view. So create a flat view model like this

public class CreateUserVm
{
   public string UserName { set;get; }
   public string Password { set;get; }

   public List<SelectListItem> UserLevels { set; get; }
   public int UserLevelId { set; get; }
}

The last 2 properties are for rendering the SELECT element. The collection property is for the list of options we want to render in the SELECT and the UserLevelId property is for storing the selected value.

now in your GET action, create an object of this, set the UserLevels property and send that to the view

public ActionResult Create()
{
  var vm = new CreateUserVm();
  vm.UserLevels = GetTypes();
  return View(vm);
}
private List<SelectListItem> GetTypes()
{
    return db.UserLevels.Select(a => new SelectListItem
    {
        Value = a.Id.ToString(),
        Text = a.Name
    }).ToList();
}

Now in your view, which is strongly typed to your new view model, use the helper methods to generate the input elements

@model CreateUserVm
@using(Html.BeginForm())
{
  @Html.TextBoxFor(a=>a.UserName)
  @Html.TextBoxFor(a=>a.Password)
  @Html.DropDownListFor(a=>a.UserLevelId, Model.UserLevels)
  <button type="submit">Save</button>
}

Now, we will use the same view model as the HttpPost action method parameter. Once the form is submitted, model binder will be able to map the form element values to the property values of this object because the name attribute of the input element matches with the property name/structure. We can read the property values of the view model object and use that to create the domain entity object and save

[HttpPost]
public ActionResult Create(CreateUserVm model)
{
  var user = new User { UserName = model.UserName, Password = model.Password };
  user.UserLevelId = model.UserLevelId;

  yourDbContext.Users.Add(user);
  yourDbContext.SaveChanges();

  return RedirectToAction("Index");
}

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