Search code examples
asp.net.netasp.net-coreasp.net-core-mvcasp.net-identity

Some model properties always null on post, modelbinding issue


I am making a part of a website where you can update your profile. The profile is tied to the user which is an extension of Microsofts Identity.

The problem is that LastName and FirstName is always null after making a post request. I would like to think that if this was a ModelState error I would have caught it through !ModelState.IsValid.

Firstname and lastname always null

https://i.gyazo.com/eea1e3465427eba5a731947473fca821.mp4

Model

using Microsoft.AspNetCore.Identity;
using System;
namespace Certificate_Wiki.Models {
    public class CertificateUser : IdentityUser {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Website { get; set; }
        public string Occupation { get; set; }
        public string Country { get; set; }
        public string Description { get; set; }
        public String ProfilePictureUrl { get; set; }
        public Byte[] ProfilePicture { get; set; }
        public bool isPrivate { get; set; }
    }
}

cshtml

@{
    ViewData["Title"] = "Edit Profile";
}
@model Certificate_Wiki.Models.CertificateUser
<link rel="stylesheet" href="~/css/pages/ProfileEdit.css" media="all" />

<div class="background"></div>
<div class="content">
    <div class="content-image">
        <img src="~/images/profile/Component 1 – 1.png" alt="" />
    </div>
    <div class="content-profile">
        <div class="profile-image">
            <img src="https://www.pngitem.com/pimgs/m/78-786293_1240-x-1240-0-avatar-profile-icon-png.png" alt="error loading image" />
        </div>
        <div class="profile-form">
            <h2>@User.Identity.Name</h2>
            <div asp-validation-summary="All">
            </div>
            <form asp-action="Edit" method="post">

                <div class="form-row">
                    <label>First Name</label>
                    <input asp-for="FirstName" type="text" name="name" />
                </div>
                <div class="form-row">
                    <label>Last Name</label>
                    <input asp-for="LastName" type="text" name="name" />
                </div>
                <div class="form-row">
                    <label>Occupation</label>
                    <input asp-for="Occupation" type="text" name="occupation" />
                </div>
                <div class="form-row">
                    <label>Website</label>
                    <input asp-for="Website" type="url" name="website" />
                </div>
                <div class="form-row">
                    <label>Country</label>
                    <input asp-for="Country" type="text" name="Country" />
                </div>
                <div class="form-row">
                    <label>Profile Description</label>
                    <textarea asp-for="Description" type="text" name="description"></textarea>
                </div>
                <div class="form-row">
                    <label>Private Profile</label>
                    <input asp-for="isPrivate" type="checkbox" name="Private" />
                </div>

                <div class="form-row">
                    <button type="submit">Save</button>
                </div>
            </form>
        </div>
    </div>
</div>

Controller

[HttpGet]
[Authorize]
[Route("Profile/edit")]
public async Task<IActionResult> EditAsync() 
{
    var Profile = await userManager.FindByEmailAsync(User.Identity.Name);
    if (Profile == null) { return View(); }

    return View(Profile);
}

[ValidateAntiForgeryToken]
[HttpPost]
[Authorize]
[Route("Profile/edit")]
public async Task<IActionResult> EditAsync([FromForm]CertificateUser model) 
{
    //TODO
    //Remove CW from single-line if
    if (!ModelState.IsValid) { Console.WriteLine("Modelstate invalid"); return View(model); }

    var Profile = await userManager.FindByEmailAsync(User.Identity.Name);
    if (Profile == null) { return View(); }

    //Update database
    Profile.FirstName = model.FirstName;
    Profile.LastName = model.LastName;
    Profile.Description = model.Description;
    Profile.Country = model.Country;
    Profile.Occupation = model.Occupation;
    Profile.Website = model.Website;
    await userManager.UpdateAsync(Profile);

    Console.WriteLine("Update success");

    return RedirectToAction("Index");
}

Note, While I am at it I would also like to ask if there is a "better" or a rather clean way to update the user without profile... = model... for every property to be updated.


Solution

  • If you use the asp-for attribute for input box, then you shouldn't use the name attribute in the same time (or at least use the same value for it).

    In your example you set FirstName for asp-for and then just name for the name attribute of the input for FirstName.