skip to Main Content

I am working on a Data Entry system for storing users financial data. Each user will enter his Revenues and Expenses each in a table.
The tables were designed as follows:

  • Primary Key: Rev/Exp ID
  • Foreign Key: Organization ID

This is a sample for my models:

public class Revenue
{
    [Key]
    public int RevenueId { get; set; }
    public int Year { get; set; }
    public double Source1 { get; set; } = 0;
    public double Source2 { get; set; } = 0;
    public double Source3 { get; set; } = 0;
    public double Source4 { get; set; } = 0;

    // Foreign Key Relationship
    public string OrganizationId{ get; set; }
    public virtual Organization Organization{ get; set; }
}

public class Organization
{
    public virtual ICollection<Revenue> Revenues { get; set; }
    public virtual ICollection<Expense> Expenses { get; set; }
}

This is the DBContext:

public class AppDbContext : IdentityDbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    // Create tables in DB
    public DbSet<Organization > Organization { get; set; }
    public DbSet<Revenue> Revenue { get; set; }
    public DbSet<Expense> Expense { get; set; }
}

Here is the Create Action in the Controller:

    // GET: Revenue/Create
    public IActionResult Create()
    {
        return View();
    }

    // POST: Revenue/Create
    // To protect from overposting attacks, enable the specific properties you want to bind to.
    // For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
    [HttpPost]
    [ValidateAntiForgeryToken]
    public async Task<IActionResult> Create([Bind("RevenueId,Year,Source1,Source2,...,OrganizationId")] Revenue revenue)
    {
        if (ModelState.IsValid)
        {
            _context.Add(revenue);
            await _context.SaveChangesAsync();
            return RedirectToAction(nameof(Index));
        }
        ViewData["OrganizationId"] = new SelectList(_context.OrganizationId, "Id", "Id", revenue.OrganizationId);
        return View(revenue);
    }

Finally, Create View:

@using Microsoft.AspNetCore.Identity

@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager
    @{
        ViewData["Title"] = "Create";
    }
    
    <h1>Create</h1>
    
    <h4>Revenue</h4>
    <hr />
    <div class="row">
        <div class="col-md-4">
            <form asp-action="Create">
                <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                <div class="form-group">
                    <label asp-for="Year" class="control-label"></label>
                    <input asp-for="Year" class="form-control" />
                    <span asp-validation-for="Year" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Source1" class="control-label"></label>
                    <input asp-for="Source1" class="form-control" />
                    <span asp-validation-for="Source1" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Source2" class="control-label"></label>
                    <input asp-for="Source2" class="form-control" />
                    <span asp-validation-for="Source2" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Source3" class="control-label"></label>
                    <input asp-for="Source3" class="form-control" />
                    <span asp-validation-for="Source3" class="text-danger"></span>
                </div>
                <div class="form-group">
                    <label asp-for="Source4" class="control-label"></label>
                    <input asp-for="Source4" class="form-control" />
                    <span asp-validation-for="Source4" class="text-danger"></span>
                </div>
            <div class="form-group">
                <label asp-for="OrganizationId" class="control-label"></label>
                <input asp-for="OrganizationId" class="form-control" value="@UserManager.GetUserId(User)"/>
                <span asp-validation-for="OrganizationId" class="text-danger"></span>
            </div>
                </div>
                <div class="form-group">
                    <input type="submit" value="Create" class="btn btn-primary" />
                </div>
            </form>
        </div>
    </div>
    
    <div>
        <a asp-action="Index">Back to List</a>
    </div>
    
    @section Scripts {
        @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
    }

So, after a lot of search I was able to capture user ID with UserManager and assigning it to a hidden field, then sending it with the form. However, that did not work, the form is not submitting and no error messages are displayed neither.

Is this is a correct way of capturing user ID as a Foreign Key and how to fix the Create Action ?

2

Answers


  1. Chosen as BEST ANSWER

    As from .NET 6, in order to assign an attribute in a model to be Nullable the ? should be added after the name of the attribute, otherwise it is required.

    The problem was that the UserId is passed but the User object is null (which should be because it is just a reference).

    So the model should be:

    public class Revenue
    {
        [Key]
        public int RevenueId { get; set; }
        public int Year { get; set; }
        public double Source1 { get; set; } = 0;
        public double Source2 { get; set; } = 0;
        public double Source3 { get; set; } = 0;
        public double Source4 { get; set; } = 0;
    
        // Foreign Key Relationship
        public string OrganizationId{ get; set; }
        public Organization? Organization{ get; set; }
    }
    

    And the view will be as is by passing user ID in a hidden field that we got from UserManager.


  2. You didn’t really specify anything about your authentication. If you are using typical ASP.Net authentication, you can probably use User.Identity.Name, like this:

            if (ModelState.IsValid)
            {
                revenue.UserId = User.Identity.Name
                _context.Add(revenue);
                ...
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search