.NET 9.0 的 Blazor Web App 项目、Bootstrap Blazor 组件库、自定义日志 TLog 使用备忘

一、设计目标:通用、容易修改、使用简单,所有代码保存在一个文件中,方便移植到其他项目使用。

注:示例使用 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 });}}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/68133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

单片机基础模块学习——数码管(二)

一、数码管模块代码 这部分包括将数码管想要显示的字符转换成对应段码的函数&#xff0c;另外还包括数码管显示函数 值得注意的是对于小数点和不显示部分的处理方式 由于小数点没有单独占一位&#xff0c;所以这里用到了两个变量i,j用于跳过小数点导致的占据其他字符显示在数…

uniapp——App 监听下载文件状态,打开文件(三)

5 实现下载文件并打开 这里演示&#xff0c;导出Excel 表格 文章目录 5 实现下载文件并打开DEMO监听下载进度效果图为什么 totalSize 一直为0&#xff1f; 相关Api&#xff1a; downloader DEMO 提示&#xff1a; 请求方式支持&#xff1a;GET、POST&#xff1b;POST 方式需要…

MyBatis进阶

1. 动态SQL 1.1 <if>标签的使用(xml版本) 动态 SQL 是Mybatis的强⼤特性之⼀&#xff0c;能够完成不同条件下不同的 sql 拼接。 现在有一个需求.注册分为两种字段&#xff1a;必填字段和⾮必填字段&#xff0c;那如果在添加用户的时候有不确定的字段传⼊&#xff0c;程…

粒子群算法 笔记 数学建模

引入: 如何找到全局最大值&#xff1a;如果只是贪心的话&#xff0c;容易被局部最大解锁定 方法有&#xff1a;盲目搜索&#xff0c;启发式搜索 盲目搜索&#xff1a;枚举法和蒙特卡洛模拟&#xff0c;但是样例太多花费巨量时间 所以启发式算法就来了&#xff0c;通过经验和规…

OpenCV相机标定与3D重建(65)对图像点进行去畸变处理函数undistortPoints()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 从观测到的点坐标计算理想点坐标。 该函数类似于 undistort 和 initUndistortRectifyMap&#xff0c;但它操作的是稀疏点集而不是光栅图像。此外…

AIGC浪潮下,图文内容社区数据指标体系构建探索

在AIGC&#xff08;人工智能生成内容&#xff09;浪潮席卷之下&#xff0c;图文内容社区迎来了新的发展机遇与挑战。为了有效监控和优化业务发展&#xff0c;构建一个科学、全面的数据指标体系显得尤为重要。本文将深入探讨如何在AIGC背景下&#xff0c;为图文内容社区构建一套…

【Unity3D】《跳舞的线》游戏的方块单方向拉伸实现案例

通过网盘分享的文件&#xff1a;CubeMoveMusic.unitypackage 链接: https://pan.baidu.com/s/1Rq-HH4H9qzVNtpQ84WXyUA?pwda7xn 提取码: a7xn 运行游戏点击空格动态创建拉伸的方块&#xff0c;由Speed控制速度&#xff0c;新方向是随机上下左右生成。 using System.Collect…

Android Studio打包APK

1.导出APK安装包 如果是首次打包&#xff0c;Create new 单击蓝色对话框右边文件夹&#x1f4c2;图标 &#xff0c;选择密钥保存路径&#xff0c;然后在下方File name对话框中填写您想要名称&#xff0c;再点击OK回到密钥创建对话框。 在此对话框中填写密码&#xff08;Passwo…

Docker 从零开始掌握容器化技术

Docker 初学者指南&#xff1a;从零开始掌握容器化技术 引言 Docker 是一个强大的工具&#xff0c;可以帮助开发者轻松地创建、部署和运行应用程序。对于初学者来说&#xff0c;Docker 可能看起来有些复杂&#xff0c;但一旦掌握了基本概念和操作&#xff0c;你会发现它非常直…

GSI快速收录服务:让你的网站内容“上架”谷歌

辛苦制作的内容无法被谷歌抓取和展示&#xff0c;导致访客无法找到你的网站&#xff0c;这是会让人丧失信心的事情。GSI快速收录服务就是为了解决这种问题而存在的。无论是新上线的页面&#xff0c;还是长期未被收录的内容&#xff0c;通过我们的技术支持&#xff0c;都能迅速被…

[ACTF2020 新生赛]Include1

题目 点击tips后&#xff1a; 使用PHP伪协议直接读取flag /?filephp://filter/readconvert.base64-encode/resourceflag.php base64解码 拿下flag flag{6cce5a3d-997a-4c8a-ba07-f6652ee462a9}

Linux-rt下卡死之hrtimer分析

Linux-rt下卡死之hrtimer分析 日志 超时读过程分析 #define readl_poll_timeout(addr, val, cond, delay_us, timeout_us) \readx_poll_timeout(readl, addr, val, cond, delay_us, timeout_us)34 #define readx_poll_timeout(op, addr, val, cond, sleep_us, timeout_us) \…

Linux的基本指令(上)

1.ls指令 语法&#xff1a;ls [选项] [目录或文件] 功能&#xff1a;对于⽬录&#xff0c;该命令列出该⽬录下的所有⼦⽬录与⽂件。对于⽂件&#xff0c;将列出⽂件名以及其他信息。 常用选项&#xff1a; -a 列出⽬录下的所有⽂件&#xff0c;包括以 . 开头的隐含⽂件。 -d 将…

基于Springboot用axiospost请求接收字符串参数为null的解决方案

问题 ​ 今天在用前端 post 请求后端时发现&#xff0c;由于是以 Json对象的形式传输的&#xff0c;后端用两个字符串形参无法获取到对应的参数值 前端代码如下&#xff1a; axios.post(http://localhost:8083/test/postParams,{a: 1, b:2} ,{Content-Type: application/jso…

ios打包:uuid与udid

ios的uuid与udid混乱的网上信息 新人开发ios&#xff0c;发现uuid和udid在网上有很多帖子里是混淆的&#xff0c;比如百度下&#xff0c;就会说&#xff1a; 在iOS中使用UUID&#xff08;通用唯一识别码&#xff09;作为永久签名&#xff0c;通常是指生成一个唯一标识&#xf…

【豆包MarsCode 蛇年编程大作战】蛇形烟花

项目体验地址&#xff1a;项目体验地址 官方活动地址&#xff1a;活动地址 目录 【豆包MarsCode 蛇年编程大作战】蛇形烟花演示 引言 豆包 MarsCode介绍 项目准备 第一步&#xff1a;安装插件 第二步&#xff1a;点击豆包图标来进行使用豆包 使用豆包 MarsCodeAI助手实…

leetcode151-反转字符串中的单词

leetcode 151 思路 时间复杂度&#xff1a;O(n) 空间复杂度&#xff1a;O(n) 首先将字符串转为数组&#xff0c;这样可以方便进行操作&#xff0c;然后定义一个新的数组来存放从后到前的单词&#xff0c;由于arr中转换以后可能会出现有些项是空格的情况&#xff0c;所以需要判…

Precharge和Self-refresh的区别

一、区别说明 操作目标&#xff1a; Precharge&#xff08;预充电&#xff09;&#xff1a;此操作的主要目标是关闭存储器中某个或所有Bank中现有的工作行&#xff08;active row&#xff09;&#xff0c;并准备打开新的工作行。这是为了确保存储器的连续访问能够高效、可靠地进…

理解C++运行时类型识别符: typeid

1. 格式 typeid (type-id) typeid (expression) typeid 运算符允许在运行时确定对象的类型。 typeid 的结果是一个 const type_info&。该值是对 type_info 对象的引用&#xff0c;该对象表示 type-id 或表达式的类型&#xff0c;具体取决于使用哪种形式的 typeid。有关…

miniconda学习笔记

文章主要内容&#xff1a;演示miniconda切换不同python环境&#xff0c;安装python库&#xff0c;使用pycharm配置不同的conda建的python环境 目录 一、miniconda 1. 是什么&#xff1f; 2.安装miniconda 3.基本操作 一、miniconda 1. 是什么&#xff1f; miniconda是一个anac…