Search code examples
sql-serverasp.net-mvcasp.net-core-mvcasp.net-identity

Save ASP.NET core Identity User attributes in another table


I am developing an ASP .NET core web application. I employ Identity UI framework for the user registration and authorization in the application. I inherit Identity User to my ApplicationUser class as follows. It creates a table called as ApplicationUser and save the relevant data under the given attributes successfully: (I am using Microsoft SQL database)

ApplicationUser.cs

using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;

#nullable disable

namespace WebApp.Models
{
        public partial class ApplicationUser : IdentityUser<int>
        {
            public ApplicationUser()
            {
            }

            public string FirstName { get; set; }
            public string MiddleName { get; set; }
            public string LastNam { get; set; }
            public DateTime? DateOfBirth { get; set; }
            public string Bio { get; set; }

            public virtual UserAddress UserAddress { get; set; }
        }
}

Then I implemented UserAddress model class as follows. It creates another table in the database named as "UserAddress"\

UserAddress.cs

using System;
using System.Collections.Generic;

#nullable disable

namespace WebApp.Models
{
    public partial class UserAddress
    {
        public int UserId { get; set; }
        public string BuildingNo { get; set; }
        public string Street { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string ZipCode { get; set; }

        public virtual ApplicationUser User { get; set; }
    }
}

Next in under Areas folder in Identity UI frame work, I change the Index.cshtml file as follows. i inserting new entry to enter the building number of the user, that should be saved in UserAddress table in database.

Index.cshtml

@page
@model IndexModel
@{
    ViewData["Title"] = "Profile";
    ViewData["ActivePage"] = ManageNavPages.Index;
}

<h4>@ViewData["Title"]</h4>
<partial name="_StatusMessage" model="Model.StatusMessage" />
<div class="row">
    <div class="col-md-12">
        <form id="profile-form" method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="=row d-flex flex-row">
                <div class="form-group col-md-6">
                    <label asp-for="Input.UserName"></label>
                    <input asp-for="Input.UserName" class="form-control" />
                </div>
            </div>
            <div class="=row d-flex flex-row">
                <div class="form-group col-md-6">
                    <label asp-for="Input.FirstName"></label>
                    <input asp-for="Input.FirstName" class="form-control" />
                </div>
                <div class="form-group col-md-6">
                    <label asp-for="Input.MiddleName"></label>
                    <input asp-for="Input.MiddleName" class="form-control" />
                </div>
            </div>
            <div class="=row d-flex flex-row">
                <div class="form-group col-md-6">
                    <label asp-for="Input.LastNam"></label>
                    <input asp-for="Input.LastNam" class="form-control" />
                </div>
            </div>
            <div class="=row d-flex flex-row">
                <div class="form-group col-md-6">
                    <label asp-for="Input.DateOfBirth"></label>
                    <input asp-for="Input.DateOfBirth" class="form-control" />
                </div>
                <div class="form-group col-md-6">
                    <label asp-for="Input.PhoneNumber"></label>
                    <input asp-for="Input.PhoneNumber" class="form-control" />
                    <span asp-validation-for="Input.PhoneNumber" class="text-danger"></span>
                </div>
             </div>
             <div class="=row d-flex flex-row">
                <div class="form-group col-md-6">
                        <label asp-for="Input.BuildingNo"></label>
                        <input asp-for="Input.BuildingNo" class="form-control" />
                </div>
             </div>
            <div class="=row d-flex flex-row">
                <div class="do-md-6">
                    <button id="update-profile-button" type="submit" class="btn btn-primary">Save</button>
                </div>
            </div>
         </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

And in the Index.cshtml.cs file, I tried to save the building number in the UserAddress table as follows but it fails to enter the data into the table.

Index.cshtml.cs

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using WebApp.Models;

namespace WebApp.Areas.Identity.Pages.Account.Manage
{
    public partial class IndexModel : PageModel
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;

        public IndexModel(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }

        public string BuildingNo { get; set; }
        public string Username { get; set; }

        [TempData]
        public string StatusMessage { get; set; }

        [BindProperty]
        public InputModel Input { get; set; }

        public class InputModel
        {

            [DataType(DataType.Text)]
            [Display(Name = "User Name")]
            public string UserName { get; set; }

            [DataType(DataType.Text)]
            [Display(Name = "First name")]
            public string FirstName { get; set; }


            [DataType(DataType.Text)]
            [Display(Name = "Middle name")]
            public string MiddleName { get; set; }


            [DataType(DataType.Text)]
            [Display(Name = "Last name")]
            public string LastNam { get; set; }


            [Display(Name = "Date of Birth")]
            [DataType(DataType.Date)]
            public DateTime DateOfBirth { get; set; }

            [Phone]
            [Display(Name = "Phone number")]
            public string PhoneNumber { get; set; }

            [Display(Name = "Building No:")]
            [DataType(DataType.Text)]
            public string BuildingNo { get; set; }
        }

        private async Task LoadAsync(ApplicationUser user)
        {
            var userName = await _userManager.GetUserNameAsync(user);
            var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
            Username = userName;
            Input = new InputModel
            {
                UserName = user.UserName,
                FirstName = user.FirstName,
                MiddleName = user.MiddleName,
                LastNam = user.LastNam,
                PhoneNumber = phoneNumber, 
            };
            
        }

        public async Task<IActionResult> OnGetAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
            }

            await LoadAsync(user);
            return Page();
        }

        public async Task<IActionResult> OnPostAsync()
        {
            var user = await _userManager.GetUserAsync(User);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
            }

            if (!ModelState.IsValid)
            {
                await LoadAsync(user);
                return Page();
            }

            var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
            if (Input.PhoneNumber != phoneNumber)
            {
                var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
                if (!setPhoneResult.Succeeded)
                {
                    StatusMessage = "Unexpected error when trying to set phone number.";
                    return RedirectToPage();
                }
            }
            if(Input.FirstName != user.FirstName)
            {
                user.FirstName = Input.FirstName;
            }

            if (Input.MiddleName != user.MiddleName)
            {
                user.MiddleName = Input.MiddleName;
            }
            if (Input.LastNam != user.LastNam)
            {
                user.LastNam = Input.LastNam;
            }
            if (Input.DateOfBirth != user.DateOfBirth)
            {
                user.DateOfBirth = Input.DateOfBirth;
            }
            if (Input.UserName != user.UserName)
            {
                user.UserName = Input.UserName;
            }
            
            user.UserAddress.BuildingNo = Input.BuildingNo; // I tried to enter the building address to the UserAddress table by using this code

            await _userManager.UpdateAsync(user);

            await _signInManager.RefreshSignInAsync(user);
            StatusMessage = "Your profile has been updated";
            return RedirectToPage();
        }
    }
}

Please ignore the above lengthy Index.cshtml.cs code I have provided, I have commented near the only code that I used to insert the input building number to the UserAddress table. which is:
user.UserAddress.BuildingNo = Input.BuildingNo;

This is the part of view of the entry: The entry view
And this is the error I am getting when above code is run: The error message

For the record: all the fields in ApplicationUser table is updated. but this error occurs when I am trying to insert data into UserAddress table.

I am pretty user this is a very simple question for a person who knows ASP.NET core identity user very well.

I kindly request if somebody can please help me to save the input building number in another table named User Address?

Thanks in advance !!!


Solution

  • You can change your code like below:

    First use code get current user include UserAddress:

     var user = await _userManager.Users
                             .Include(x => x.UserAddress)
                             .SingleAsync(x => x.UserName== Input.UserName);
    

    Then determine whether UserAddress exists and update it.

     if (user.UserAddress == null)
                    {
                        user.UserAddress = new Models.UserAddress
                        {
                            BuildingNo = Input.BuildingNo
                        };
                    }
                    else
                    {
                        user.UserAddress.BuildingNo = Input.BuildingNo;
                    }
    

    The whole code is like below:

    public async Task<IActionResult> OnPostAsync()
        {
            //get the current user
            var user = await _userManager.Users
                             .Include(x => x.UserAddress)
                             .SingleAsync(x => x.UserName== Input.UserName);
            if (user == null)
            {
                return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
            }
    
            if (!ModelState.IsValid)
            {
                await LoadAsync(user);
                return Page();
            }
    
            var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
            if (Input.PhoneNumber != phoneNumber)
            {
                var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
                if (!setPhoneResult.Succeeded)
                {
                    StatusMessage = "Unexpected error when trying to set phone number.";
                    return RedirectToPage();
                }
            }
            if(Input.FirstName != user.FirstName)
            {
                user.FirstName = Input.FirstName;
            }
    
            if (Input.MiddleName != user.MiddleName)
            {
                user.MiddleName = Input.MiddleName;
            }
            if (Input.LastNam != user.LastNam)
            {
                user.LastNam = Input.LastNam;
            }
            if (Input.DateOfBirth != user.DateOfBirth)
            {
                user.DateOfBirth = Input.DateOfBirth;
            }
            if (Input.UserName != user.UserName)
            {
                user.UserName = Input.UserName;
            }
            //insert the BuildingNo
            if (user.UserAddress == null)
                    {
                        user.UserAddress = new Models.UserAddress
                        {
                            BuildingNo = Input.BuildingNo
                        };
                    }
                    else
                    {
                        user.UserAddress.BuildingNo = Input.BuildingNo;
                    }
    
            await _userManager.UpdateAsync(user);
    
            await _signInManager.RefreshSignInAsync(user);
            StatusMessage = "Your profile has been updated";
            return RedirectToPage();
        }