一、设计目标:通用、容易修改、使用简单,所有代码保存在一个文件中,方便移植到其他项目使用。
注:示例使用 Bootstrap Blazor 组件库和 EF Core 、Sqlite,需要先使用 Nuget包管理器 添加对应的包。
namespace BlazorWebAppNet9Shared.Services;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using System.ComponentModel.DataAnnotations;
/// <summary>
/// 日志记录服务。<br/><br/>
/// 使用示例,第1步:builder.Services.AddTLog("Data Source=SQLiteFileLog.db");<br/>
/// 使用示例,第2步:TLog.Page(UserName, DisplayName, NavigationManager.ToBaseRelativePath(NavigationManager.Uri));
/// </summary>
public static class TLog
{
public static TLogDbContext TLogDb { get; set; } = default!;
/// <summary>
/// 添加 TLog 服务。<br/>
/// 示例:builder.Services.AddTLog("Data Source=SQLiteFileLog.db");
/// </summary>
/// <param name="services"></param>
/// <param name="ConnectionString"></param>
/// <returns></returns>
public static IServiceCollection AddTLog(this IServiceCollection services, string ConnectionString)
{
TLogDb = new TLogDbContext(ConnectionString);
// 自动创建数据库和数据表:修改实体定义后,删除原有的数据库自动重新建立;或者根据实体定义手动修改数据库和数据表。
TLogDb.Database.EnsureCreated();
return services;
}
public static void Page(string 用户名, string 姓名, string 操作对象)
{
if (TLogDb != null)
{
TLogDb.Add(new TLogEntity() { 操作类型 = TLogOpStyle.浏览, 用户名 = 用户名, 姓名 = 姓名, 操作对象 = 操作对象 });
TLogDb.SaveChanges();
}
}
public static void Create(string 用户名, string 姓名, string 操作对象, string? 操作说明, bool 操作结果)
{
if (TLogDb != null)
{
TLogDb.Add(new TLogEntity() { 操作类型 = TLogOpStyle.新建, 用户名 = 用户名, 姓名 = 姓名, 操作对象 = 操作对象, 操作说明 = 操作说明, 操作结果 = 操作结果 });
TLogDb.SaveChanges();
}
}
public static void Delete(string 用户名, string 姓名, string 操作对象, string? 操作说明, bool 操作结果)
{
if (TLogDb != null)
{
TLogDb.Add(new TLogEntity() { 操作类型 = TLogOpStyle.删除, 用户名 = 用户名, 姓名 = 姓名, 操作对象 = 操作对象, 操作说明 = 操作说明, 操作结果 = 操作结果 });
TLogDb.SaveChanges();
}
}
public static void Update(string 用户名, string 姓名, string 操作对象, string? 操作说明, bool 操作结果)
{
if (TLogDb != null)
{
TLogDb.Add(new TLogEntity() { 操作类型 = TLogOpStyle.编辑, 用户名 = 用户名, 姓名 = 姓名, 操作对象 = 操作对象, 操作说明 = 操作说明, 操作结果 = 操作结果 });
TLogDb.SaveChanges();
}
}
public static void Read(string 用户名, string 姓名, string 操作对象, string? 操作说明, bool 操作结果)
{
if (TLogDb != null)
{
TLogDb.Add(new TLogEntity() { 操作类型 = TLogOpStyle.查询, 用户名 = 用户名, 姓名 = 姓名, 操作对象 = 操作对象, 操作说明 = 操作说明, 操作结果 = 操作结果 });
TLogDb.SaveChanges();
}
}
}
/// <summary>
/// 日志数据库上下文:建立使用独立数据库,与业务数据分开存放。
/// </summary>
/// <param name="ConnectionString"></param>
public class TLogDbContext(string ConnectionString) : DbContext
{
public DbSet<TLogEntity> TLogEntitys { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);
optionsBuilder.UseSqlite(ConnectionString);
}
/* 建立索引:建立在实体定义时使用 Index 注解 建立,更方便。
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TLogEntity>()
.HasIndex(t => new { t.用户名, t.姓名, t.操作类型, t.操作对象 });
modelBuilder.Entity<TLogEntity>()
.HasIndex(t => new { t.用户名 });
}*/
}
/// <summary>
/// 日志实体:后续可以根据需要增加,注意不要编辑、删除已有属性。
/// </summary>
[Index(nameof(Id))]
[Index(nameof(时间))]
[Index(nameof(用户名))]
[Index(nameof(姓名))]
[Index(nameof(操作类型))]
[Index(nameof(操作对象))]
[Index(nameof(姓名), nameof(操作对象))]
public class TLogEntity
{
[Key]
public long Id { get; set; }
public DateTime 时间 { get; set; } = DateTime.Now;
public required string 用户名 { get; set; }
public required string 姓名 { get; set; }
public TLogOpStyle 操作类型 { get; set; } = TLogOpStyle.浏览;
public required string 操作对象 { get; set; }
public string? 操作说明 { get; set; }
public bool 操作结果 { get; set; } = true;
}
/// <summary>
/// 日志类型:后续可以根据需要增加,注意不要编辑、删除已有类型。
/// </summary>
public enum TLogOpStyle
{
/// <summary>
/// 用于记录访问路径:Page
/// </summary>
浏览,
/// <summary>
/// 增删改查CRUD:Create
/// </summary>
新建,
/// <summary>
/// 增删改查CRUD:Read
/// </summary>
查询,
/// <summary>
/// 增删改查CRUD:Update
/// </summary>
编辑,
/// <summary>
/// 增删改查CRUD:Delete
/// </summary>
删除,
}
代码文件:TLog.cs
二、使用步骤
1. 在 Program.cs 中添加 TLog 服务,同时指定保存日志的数据库文件名。
............
builder.Services.AddTLog("Data Source=SQLiteFileLog.db");
var app = builder.Build();
............
2. 在需要记录日志的位置,直接使用 TLog.Page 、TLog.Create 等静态方法进行记录,不需要进行注入、New等操作,简化代码输入。
@inject NavigationManager NavigationManager;
protected override void OnInitialized()
{
base.OnInitialized();
// 记录日志
TLog.Page(UserName, DisplayName, NavigationManager.ToBaseRelativePath(NavigationManager.Uri));
}
3. 使用 TLogManager.razor 组件浏览日志
@page "/Log/TLogManager"
<Table TItem="TLogEntity" OnQueryAsync="@OnQueryAsync"
AutoGenerateColumns=true HeaderStyle="TableHeaderStyle.Light"
ClickToSelect="true" ShowLoading="true" AllowResizing="true"
IsPagination="true" PageItemsSource="new int[] { 10, 20, 30, 60, 100 }"
ShowToolbar="true" ShowDefaultButtons="false">
</Table>
@code {
[CascadingParameter]
public LayoutBB.MainLayout? mainLayout { get; set; }
@inject NavigationManager NavigationManager;
protected override void OnInitialized()
{
base.OnInitialized();
// 记录日志
TLog.Page(mainLayout?.UserName ?? "", mainLayout?.DisplayName ?? "", NavigationManager.ToBaseRelativePath(NavigationManager.Uri));
}
private async Task<QueryData<TLogEntity>> OnQueryAsync(QueryPageOptions options)
{
IEnumerable<TLogEntity> items = TLog.TLogDb.TLogEntitys.OrderByDescending(t => t.时间).ToList();
var total = items.Count();
items = items.Skip((options.PageIndex - 1) * options.PageItems).Take(options.PageItems).ToList();
return await Task.FromResult(new QueryData<TLogEntity>() { Items = items, TotalCount = total, IsSorted = true, IsFiltered = true, IsSearch = true });
}
}