Foreign Key Reference to IdentityUser Shows NULL Values (EF6/ASP.NET MVC 5)

asp.net-mvc-5 c# entity-framework-6

Question

I am trying to figure out why my model table's UserId column which references the primary key, "Id" of my AspNetUsers table (IdentityUser class in IdentityModel) is showing only NULL values when I 'Create()' an entry.

Here is the code for my two Create(), ActionResult methods in my controller class:

[Authorize]
    public ActionResult Create()
    {
        ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname");
        return View();
    }

    // POST: Expenses/Create

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize]
    public ActionResult Create([Bind(Include = "ID,Category,Description,GrossAmount,TaxAmount,NetAmount,Mileage,MileageRate,DateSubmitted,ExpenseDate,UserId")] Expense expense)
    {
        if (ModelState.IsValid)
        {
            expense.UserId = HttpContext.Current.User.Identity.Name;
            db.Expenses.Add(expense);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname", expense.UserId);
        return View(expense);
    }

Here is the code for my Create view:

    @{
    ViewBag.Title = "Create";
    Layout = "~/Views/Shared/_Layout.cshtml";

    DateTime today = DateTime.Today;
    string formattedDate = today.ToString("MM/dd/yyyy");
}

<h2>Create</h2>

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

    <div class="form-horizontal">
        <h4>Expense</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })

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

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

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

        <div class="form-group">
            @Html.LabelFor(model => model.Category, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownListFor(model => model.Category, new SelectList(
                  new List<String>{
                       "Meals & Entertainment",
                       "Home Office",
                       "Travel",
                       "Phone",
                       "Auto - Mileage",
                       "Auto - Gas",
                       "Auto - Lease",
                       "Association Dues",
                       "Insurance Premium",
                       "Capital Assets",
                       "Trade Show & Promo",
                       "Pan Experience",
                       "Other"
                    }), new { @class = "form-control" })

                @Html.ValidationMessageFor(model => model.Category, "", new { @class = "text-danger" })
            </div>
        </div>

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

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

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

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

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

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


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

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section scripts {

    <script type="text/javascript">
        var province = 'bc';
        var grossAmount = document.getElementById('GrossAmount').value;

        $(function () {

            $('#ExpenseDate').datetimepicker({

                defaultDate: '@formattedDate',

                format: 'L',

                showClose: true,

                showClear: true,

                toolbarPlacement: 'top'

            });

        });

        $('#DateSubmitted').prop('readonly', true);
        $('#Mileage').prop('disabled', true);
        $('#MileageRate').prop('disabled', true);

        $(function ()
        {
            $('#Category').on('change',function()
            {
                if ($(this).val() == 'Auto - Mileage')
                {
                    $('#Mileage').prop('disabled', false);
                    $('#MileageRate').prop('disabled', false);
                }
                else
                {
                    $('#Mileage').prop('disabled', true);
                    $('#MileageRate').prop('disabled', true);
                }

            }

            )
        })


    </script>
}

If you would like to take a look at my model classes, you can go this post:


UPDATE:

Thanks to Steve Greene for putting me on the right track and for helping me to update my Create() method to this:

public ActionResult Create()
    {
        ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname");
        return View();
    }

    // POST: Expenses/Create

    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize]
    public ActionResult Create([Bind(Include = "ExpenseId,Category,Description,GrossAmount,TaxAmount,NetAmount,Mileage,MileageRate,DateSubmitted,ExpenseDate,UserId")] Expense expense)
    {
        if (ModelState.IsValid)
        {
            expense.UserId = System.Web.HttpContext.Current.User.Identity.Name;
            db.Expenses.Add(expense);
            db.SaveChanges();
            return RedirectToAction("Index");
        }

        ViewBag.UserId = new SelectList(db.Users, "Id", "Fullname", expense.UserId);

        foreach (ModelState modelState in ViewData.ModelState.Values)
        {
            foreach (ModelError error in modelState.Errors)
            {
                Response.Write(error);
            }
        }
        Response.End();
        return View(expense);

    }

I don't get any major errors now, however, now ModelState.IsValid is returning False and the data I enter into Create.cshtml isn't being submitted.

I added a piece of code in the Create() method to catch the ModelState.Errors and it prints the error: System.Web.Mvc.ModelError.

I've also set a breakpoint before Create() and when I check the value of UserId, I get "null."


LAST UPDATE:

I've added a field for UserId to the Create.cshtml view and now I get the error: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Expenses_dbo.AspNetUsers_ApplicationUser_Id". The conflict occurred in database "PacificPetExpenses", table "dbo.AspNetUsers", column 'Id'.

To fix this, I modified something in my controller (please see my answer below).

Thank you.

1
0
5/23/2017 11:52:11 AM

Accepted Answer

Inside of the Create() method inside of my controller, I had the line:

expense.UserId = HttpContext.Current.User.Identity.Name;

I set up a break point and as breakpoint was on the line, it showed the correct UserId; however, after the line had executed, it showed the user's email address.

To fix this I tried changing the line above to:

expense.UserId = System.Web.HttpContext.Current.User.Identity.GetUserId();

and expenses were both being submitted with no errors and displaying in the view where it was supposed to show the list of expenses submitted by the user!

0
9/9/2015 8:22:27 PM

Popular Answer

If you are not using the UserId in the view, just set it before you add:

    if (ModelState.IsValid)
    {
        expense.UserId = HttpContext.Current.User.Identity.Name;  // or whatever
        db.Expenses.Add(expense);
        db.SaveChanges();
        return RedirectToAction("Index");
    }

Another common pattern is to add a hidden field for the UserId:

@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
    @Html.HiddenFor(model => model.UserId)  <-- now it will post back
    ...

If you want to have a drop down list of users, do this:

[Authorize]
public ActionResult Create()
{
    ViewBag.UserList = new SelectList(db.Users, "Id", "Fullname");
    return View();
}

Then in your view add a drop down list of users:

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


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow