如何使用.NET Core 2.0和Entity Framework编程式保存对象到SQL Server
刚上手.NET Core 2.0 MVC的时候,我要做一个自定义事件日志功能——既要能编程式记录事件/对象,还要支持管理员查看,踩了好几个坑才搞定。下面是我亲测可行的完整方案,分享给同阶段的朋友:
1. 项目初始化
首先创建带独立用户账户的ASP.NET Core Web应用(MVC模板),这个模板自带Identity身份验证体系,刚好能帮我们快速实现管理员权限控制,省了不少重复造轮子的工作。
2. 创建日志数据模型
在Models文件夹下新建CustomErrorLogModel.cs,用来存储日志的核心信息,字段可以根据你的需求调整:
using System; using System.ComponentModel.DataAnnotations; namespace YourProjectName.Models { public class CustomErrorLogModel { [Key] public int LogId { get; set; } // 日志级别:Error/Warning/Info,用字符串或枚举都行 [Required] public string LogLevel { get; set; } // 日志简短标题,方便快速识别 [Required] public string Title { get; set; } // 日志详细内容,比如异常堆栈、操作详情 public string Details { get; set; } // 日志生成时间,默认取UTC时间 public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // 关联操作人ID(可选,需要记录谁触发的事件时用) public string UserId { get; set; } // 关联Identity用户表,方便查询操作人信息 public virtual ApplicationUser User { get; set; } } }
3. 配置EF Core数据库上下文
要让EF Core识别这个日志模型,需要在ApplicationDbContext.cs里添加对应的DbSet:
public DbSet<CustomErrorLogModel> CustomErrorLogs { get; set; }
然后打开Package Manager Console执行迁移命令,把日志表同步到数据库:
Add-Migration AddCustomErrorLogsTable Update-Database
4. 封装日志服务(核心步骤)
为了方便在项目各处调用日志功能,最好封装成独立服务,避免重复代码。
第一步:定义服务接口
在Services文件夹下新建ICustomLogService.cs:
using YourProjectName.Models; namespace YourProjectName.Services { public interface ICustomLogService { // 同步方法,也可以改成异步提升性能 void LogEvent(string logLevel, string title, string details = null, string userId = null); } }
第二步:实现服务逻辑
接着新建CustomLogService.cs,实现接口的日志保存逻辑:
using Microsoft.EntityFrameworkCore; using YourProjectName.Data; using YourProjectName.Models; namespace YourProjectName.Services { public class CustomLogService : ICustomLogService { private readonly ApplicationDbContext _dbContext; // 构造函数注入DbContext public CustomLogService(ApplicationDbContext dbContext) { _dbContext = dbContext; } public void LogEvent(string logLevel, string title, string details = null, string userId = null) { var logEntry = new CustomErrorLogModel { LogLevel = logLevel, Title = title, Details = details, UserId = userId }; _dbContext.CustomErrorLogs.Add(logEntry); _dbContext.SaveChanges(); } } }
第三步:注册服务到DI容器
在Startup.cs的ConfigureServices方法里添加服务注册:
services.AddScoped<ICustomLogService, CustomLogService>();
5. 实现管理员日志查看功能
新建日志控制器
在Controllers文件夹下创建LogsController.cs,用[Authorize(Roles = "Admin")]限制只有管理员角色能访问:
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using YourProjectName.Data; using YourProjectName.Models; namespace YourProjectName.Controllers { [Authorize(Roles = "Admin")] public class LogsController : Controller { private readonly ApplicationDbContext _dbContext; public LogsController(ApplicationDbContext dbContext) { _dbContext = dbContext; } // 日志列表页 public async Task<IActionResult> Index() { // 按时间倒序查询,关联用户表获取操作人名称 var logs = await _dbContext.CustomErrorLogs .Include(l => l.User) .OrderByDescending(l => l.CreatedAt) .ToListAsync(); return View(logs); } // 日志详情页 public async Task<IActionResult> Details(int? id) { if (id == null) return NotFound(); var log = await _dbContext.CustomErrorLogs .Include(l => l.User) .FirstOrDefaultAsync(m => m.LogId == id); if (log == null) return NotFound(); return View(log); } } }
创建对应的视图
在Views文件夹下新建Logs目录,然后创建两个视图:
Index.cshtml(日志列表)
@model IEnumerable<YourProjectName.Models.CustomErrorLogModel> @{ ViewData["Title"] = "系统事件日志"; } <h1>系统事件日志</h1> <table class="table table-striped"> <thead> <tr> <th>日志级别</th> <th>标题</th> <th>发生时间</th> <th>操作人</th> <th>操作</th> </tr> </thead> <tbody> @foreach (var log in Model) { <tr> <td>@log.LogLevel</td> <td>@log.Title</td> <td>@log.CreatedAt.ToLocalTime()</td> <td>@log.User?.UserName</td> <td><a asp-action="Details" asp-route-id="@log.LogId">查看详情</a></td> </tr> } </tbody> </table>
Details.cshtml(日志详情)
@model YourProjectName.Models.CustomErrorLogModel @{ ViewData["Title"] = "日志详情"; } <h1>日志详情</h1> <div class="card"> <div class="card-body"> <dl class="row"> <dt class="col-sm-3">日志级别</dt> <dd class="col-sm-9">@Model.LogLevel</dd> <dt class="col-sm-3">标题</dt> <dd class="col-sm-9">@Model.Title</dd> <dt class="col-sm-3">发生时间</dt> <dd class="col-sm-9">@Model.CreatedAt.ToLocalTime()</dd> <dt class="col-sm-3">操作人</dt> <dd class="col-sm-9">@Model.User?.UserName</dd> <dt class="col-sm-3">详细内容</dt> <dd class="col-sm-9">@Model.Details</dd> </dl> </div> </div> <a asp-action="Index" class="btn btn-secondary mt-3">返回列表</a>
6. 编程式调用日志服务
现在可以在任何需要记录日志的地方,通过依赖注入调用ICustomLogService,比如在控制器里:
using Microsoft.AspNetCore.Mvc; using YourProjectName.Services; namespace YourProjectName.Controllers { public class HomeController : Controller { private readonly ICustomLogService _logService; public HomeController(ICustomLogService logService) { _logService = logService; } public IActionResult Index() { // 记录普通操作日志 _logService.LogEvent("Info", "用户访问首页", $"访问IP:{HttpContext.Connection.RemoteIpAddress}", User.Identity.Name); // 异常场景日志记录 try { // 你的业务逻辑代码 } catch (Exception ex) { _logService.LogEvent("Error", "首页加载失败", $"异常信息:{ex.Message}\n堆栈:{ex.StackTrace}", User.Identity.Name); } return View(); } } }
额外优化建议
- 异步保存日志:把
LogEvent改成异步方法async Task LogEventAsync(...),避免阻塞主线程; - 使用枚举定义日志级别:代替字符串,减少拼写错误;
- 添加分页与筛选:日志多了之后,在列表页添加分页、按级别/时间范围筛选功能;
- 管理员角色配置:确保你已经通过Identity创建了Admin角色,并分配给对应的用户。
内容的提问来源于stack exchange,提问作者user6383418

