求ASP.Net MVC模式下记录用户ID并过滤数据的示例代码
Hey there! Let's walk through how to implement this user-specific sales tracking feature in ASP.NET MVC step by step. I'll cover everything from setting up your data model to securing access to only the current user's records.
First, create your SalesRecord entity with the required fields, including SalesOfficer to store the logged-in user's ID. We'll use ASP.NET Identity for user management (assuming it's already set up in your project).
using System; using System.ComponentModel.DataAnnotations; using Microsoft.AspNetCore.Identity; public class SalesRecord { public int Id { get; set; } [Required] public DateTime SalesDate { get; set; } [Required] [Range(0.01, double.MaxValue, ErrorMessage = "Sales amount must be greater than 0")] public decimal SalesAmount { get; set; } [Required] [StringLength(100)] public string SalesLocation { get; set; } // Stores the logged-in user's unique ID [Required] public string SalesOfficer { get; set; } // Optional: Navigation property to link to the User entity public IdentityUser User { get; set; } }
Next, set up your database context to handle the sales records:
using Microsoft.EntityFrameworkCore; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; public class AppDbContext : IdentityDbContext<IdentityUser> { public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { } public DbSet<SalesRecord> SalesRecords { get; set; } }
SalesOfficer on Record Creation You have two clean ways to auto-set the user ID:
Option A: Handle It in the Controller
Inject UserManager<IdentityUser> into your controller to get the current user's ID when creating a new record:
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Identity; using System.Linq; using System.Threading.Tasks; public class SalesController : Controller { private readonly AppDbContext _context; private readonly UserManager<IdentityUser> _userManager; public SalesController(AppDbContext context, UserManager<IdentityUser> userManager) { _context = context; _userManager = userManager; } // POST: Sales/Create [HttpPost] [ValidateAntiForgeryToken] public async Task<IActionResult> Create([Bind("SalesAmount,SalesLocation")] SalesRecord salesRecord) { if (ModelState.IsValid) { // Get current user's ID var currentUserId = await _userManager.GetUserIdAsync(User); // Auto-set required fields salesRecord.SalesOfficer = currentUserId; salesRecord.SalesDate = DateTime.Now; _context.Add(salesRecord); await _context.SaveChangesAsync(); return RedirectToAction(nameof(Index)); } return View(salesRecord); } }
Option B: Auto-Set via SaveChanges Override
For a more centralized approach, override SaveChanges in your AppDbContext to set the user ID for all new SalesRecord entries:
using System.Security.Claims; using Microsoft.EntityFrameworkCore; public override int SaveChanges() { // Get current user ID from the request context var currentUserId = HttpContext?.User.FindFirstValue(ClaimTypes.NameIdentifier); foreach (var entry in ChangeTracker.Entries<SalesRecord>()) { if (entry.State == EntityState.Added) { entry.Entity.SalesOfficer = currentUserId; entry.Entity.SalesDate = DateTime.Now; } } return base.SaveChanges(); }
Note: You'll need to inject IHttpContextAccessor into your AppDbContext to access the current user.
Modify your controller actions to return only records where SalesOfficer matches the current user's ID. Add checks to prevent users from accessing other people's records:
// GET: Sales (Show only current user's records) public async Task<IActionResult> Index() { var currentUserId = await _userManager.GetUserIdAsync(User); var userSales = _context.SalesRecords.Where(s => s.SalesOfficer == currentUserId).ToList(); return View(userSales); } // GET: Sales/Details/5 (Prevent access to other users' records) public async Task<IActionResult> Details(int? id) { if (id == null) return NotFound(); var salesRecord = await _context.SalesRecords.FindAsync(id); if (salesRecord == null) return NotFound(); var currentUserId = await _userManager.GetUserIdAsync(User); var isAdmin = await _userManager.IsInRoleAsync(await _userManager.GetUserAsync(User), "Admin"); // Allow access only if user owns the record or is an admin if (salesRecord.SalesOfficer != currentUserId && !isAdmin) { return Forbid(); } return View(salesRecord); }
Create View (Hide SalesOfficer Field)
Your create view should exclude the SalesOfficer field since it's auto-set:
@model SalesRecord @{ ViewData["Title"] = "Create New Sale"; } <h1>Create New Sale</h1> <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="SalesAmount" class="control-label"></label> <input asp-for="SalesAmount" class="form-control" /> <span asp-validation-for="SalesAmount" class="text-danger"></span> </div> <div class="form-group"> <label asp-for="SalesLocation" class="control-label"></label> <input asp-for="SalesLocation" class="form-control" /> <span asp-validation-for="SalesLocation" class="text-danger"></span> </div> <div class="form-group mt-3"> <input type="submit" value="Save Sale" class="btn btn-primary" /> </div> </form> </div> <div class="mt-3"> <a asp-action="Index">Back to My Sales</a> </div> @section Scripts { @{await Html.RenderPartialAsync("_ValidationScriptsPartial");} }
Index View (Show User's Sales)
Display only the current user's sales records:
@model IEnumerable<SalesRecord> @{ ViewData["Title"] = "My Sales Records"; } <h1>My Sales Records</h1> <p> <a asp-action="Create" class="btn btn-primary">Add New Sale</a> </p> <table class="table table-striped"> <thead> <tr> <th>Date</th> <th>Amount</th> <th>Location</th> <th>Actions</th> </tr> </thead> <tbody> @foreach (var item in Model) { <tr> <td>@item.SalesDate.ToString("MM/dd/yyyy")</td> <td>@item.SalesAmount.ToString("C")</td> <td>@item.SalesLocation</td> <td> <a asp-action="Details" asp-route-id="@item.Id" class="btn btn-sm btn-info">View</a> <a asp-action="Edit" asp-route-id="@item.Id" class="btn btn-sm btn-warning">Edit</a> <a asp-action="Delete" asp-route-id="@item.Id" class="btn btn-sm btn-danger">Delete</a> </td> </tr> } </tbody> </table>
- Never Trust Client-Side Input: Even if you hide the
SalesOfficerfield in views, always validate server-side that users can only modify their own records. - Admin Access: Use role-based authorization to let admins view/edit all records (as shown in the
Detailsaction example). - Action Filters: For repetitive checks (like ownership validation), create a custom action filter to reduce code duplication.
- Audit Logs: Add fields like
CreatedDate,UpdatedDate,UpdatedByfor better traceability. - Dependency Injection: Ensure your
AppDbContextandUserManagerare registered in your startup configuration (e.g.,Program.csfor .NET 6+).
内容的提问来源于stack exchange,提问作者Faraz Ahmed Qureshi

