Skip to content
.NET 开发者指北.NET 开发者指北
CMS
.NET指北
FreeKit
Docker
关于
博客
github icon
    • FreeKit 指北
      • FreeKit 基础包
        • FreeKit Extras 扩展包
          • 一些扩展包
            • IGeekFan.FreeKit.Extras的依赖项
              • 统一注入服务
                • 审计类
                  • 简化 FreeSql 单库的配置
                    • 基于特性标签的 AOP 事务
                      • 基于接口的注入
                        • 三种配置方式
                          • CurrentUser 当前登录人信息
                            • 实体审计类
                              • CaseQuery 支持 Get 请求参数 key,大小驼峰转换
                                • 查询参数转换支持
                                  • 基于审计类的FreeSql仓储
                                    • 复合主键仓储
                                      • 登录Jwt
                                    • AspNetCore Identity FreeSql的实现
                                      • Email 邮件
                                        • Modularity 模块化
                                          • Localization 本地化

                                          FreeKit Extras 扩展包

                                          calendar icon2022年6月2日timer icon大约 10 分钟word icon约 3100 字

                                          此页内容
                                          • 一些扩展包
                                          • IGeekFan.FreeKit.Extras的依赖项
                                          • 统一注入服务
                                            • 审计类
                                            • 简化 FreeSql 单库的配置
                                            • 基于特性标签的 AOP 事务
                                            • 基于接口的注入
                                            • 三种配置方式
                                            • CurrentUser 当前登录人信息
                                            • 实体审计类
                                            • CaseQuery 支持 Get 请求参数 key,大小驼峰转换
                                            • 查询参数转换支持
                                            • 基于审计类的FreeSql仓储
                                            • 复合主键仓储
                                            • 登录Jwt

                                          # FreeKit Extras 扩展包

                                          该项目是基于 FreeSql 实现的一些扩展包、AOP 事务,当前用户,简化依赖注入

                                          # 一些扩展包

                                          • 审计类
                                          • 简化 FreeSql 单库的配置:UseConnectionString 扩展方法
                                          • 基于特性标签的 AOP 事务
                                          • 基于接口的注入
                                          • ICurrentUser 当前登录人信息
                                          • 批量注入以 Service 为后缀接口的服务,根据所在的程序集
                                          • CaseQuery 支持 Get 请求参数 key,大小驼峰转换
                                          • 基于审计类的FreeSql仓储
                                          • 复合主键仓储

                                          # IGeekFan.FreeKit.Extras的依赖项

                                          • FreeSql.DbContext
                                          • Autofac.Extensions.DependencyInjection
                                          • Autofac.Extras.DynamicProxy
                                          • Castle.Core.AsyncInterceptor

                                          根据自己访问数据库的不同,安装FreeSql对应的Provideropen in new window

                                          dotnet add package IGeekFan.FreeKit.Extras
                                          dotnet add package FreeSql.Provider.Sqlite
                                          
                                          1
                                          2

                                          # 统一注入服务

                                          • 1.注入controller UnitOfWorkActionFilter
                                          • 2.IHttpContextAccessor、及当前登录人(ICurrentUser)信息
                                          • 3.当前登录人上下文的accessor,方便中间件中获取当前登录人(ICurrentUser)信息
                                          • 4.审计仓储 IAuditBaseRepository
                                          • 5.复合主键仓储 IBaseRepository<Entiy,TKey,UKey>
                                          • 6 FreeSql中的IBaseRepository、IBaseRepository<,>、UnitOfWorkManager

                                          1.统一注入服务

                                          可指定用户主键类型,默认为Guid,支持TKey为int,long,Guid。比如:typeof(long)

                                          services.AddFreeKitCore();
                                          
                                          1

                                          2.给controller 配置一个filtert,来支持controller级别的 [Transactional]特性事务

                                          services.AddControllers(options =>
                                          {
                                              options.Filters.AddService(typeof(UnitOfWorkActionFilter));
                                          });
                                          
                                          1
                                          2
                                          3
                                          4

                                          3.UseCurrentUserAccessor给ICurrentUserAccessor中的CurrentUser赋值,比如中间件租户Id的全局过滤器设置,在UseAuthentication后设置此中间件

                                          app.UseAuthorization();
                                          app.UseAuthentication();
                                          app.UseCurrentUserAccessor();
                                          
                                          1
                                          2
                                          3

                                          4 Autofac 配置

                                          • UnitOfWorkModule主要功能:自动注入以Service后缀的类,支持接口,类,并支持[Transactional]特性事务
                                          • FreeKitModule主要功能:继承三大接口IScopedDependency (范围)、ISingletonDependency (单例)、ITransientDependency (瞬时) 中任一接口,即可自动到容器中,支持接口,类

                                          IGeekFan.FreeKit.Web,Module1,Module2为类库的名称

                                          builder.Host
                                              .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                                              .ConfigureContainer<ContainerBuilder>((webBuilder, containerBuilder) =>
                                              {
                                                     Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(r =>
                                          r.FullName.Contains("IGeekFan.FreeKit.Web") 
                                          || r.FullName.Contains("Module1")
                                          || r.FullName.Contains("Module2")
                                          ).ToArray();
                                                  containerBuilder.RegisterModule(new UnitOfWorkModule(currentAssemblies));
                                                  containerBuilder.RegisterModule(new FreeKitModule(currentAssemblies));
                                              });
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12

                                          # 审计类

                                          • Entity<T>、Entity,仅主键的实体类型,其中T为主键类型
                                          • FullAuditEntity<T, U> 包含审计实体基类,包含创建、修改、删除加主键等10个字段,其实T为当前主键类型,U为用户表主键类型

                                          # 简化 FreeSql 单库的配置

                                          UseConnectionString 扩展方法,DefaultDB 配置 4 代表使用配置串 Sqlite。需要安装FreeSql.Provider.Sqlite

                                          • DefaultDB配置的值实际为FreeSql.DataType的枚举值,即0代表MySql,1代表SqlServer

                                          • ProviderType:同时安装同一种数据库provider时,通过设置ProviderType,指定具体要求的provider

                                          • appsettings.json

                                          "ConnectionStrings": {
                                              //"ProviderType": "FreeSql.MySql.MySqlProvider`1,FreeSql.Provider.MySql",
                                              //"ProviderType": "FreeSql.MySql.MySqlProvider`1,FreeSql.Provider.MySqlConnector",
                                              //"ProviderType": "FreeSql.Odbc.MySql.OdbcMySqlProvider`1,FreeSql.Provider.Odbc",
                                              //"ProviderType": "FreeSql.SqlServer.SqlServerProvider`1,FreeSql.Provider.SqlServer",
                                              //"ProviderType": "FreeSql.SqlServer.SqlServerProvider`1,FreeSql.Provider.SqlServerForSystem",
                                              //"ProviderType": "FreeSql.Oracle.OracleProvider`1,FreeSql.Provider.Oracle",
                                              //"ProviderType": "FreeSql.Oracle.OracleProvider`1,FreeSql.Provider.OracleOledb",
                                              //"ProviderType": "FreeSql.Odbc.Oracle.OdbcOracleProvider`1,FreeSql.Provider.Odbc",
                                              "DefaultDB": "4",
                                              "DataType": {
                                                  "MySql": 0,
                                                  "SqlServer": 1,
                                                  "PostgreSQL": 2,
                                                  "Oracle": 3,
                                                  "Sqlite": 4
                                               },
                                              "MySql": "Data Source=localhost;Port=3306;User ID=root;Password=root;Initial Catalog=freekit;Charset=utf8mb4;SslMode=none;Max pool size=1;Connection LifeTime=20",
                                              "SqlServer": "Data Source=.;User ID=sa;Password=123456;Integrated Security=True;Initial Catalog=LinCMS;Pooling=true;Min Pool Size=1",
                                              "PostgreSQL": "Host=localhost;Port=5432;Username=postgres;Password=123456; Database=lincms;Pooling=true;Minimum Pool Size=1",
                                              "Oracle": "user id=user1;password=123456; data source=//127.0.0.1:1521/ORCL;Pooling=true;Min Pool Size=1",
                                              "Sqlite": "Data Source=|DataDirectory|/freekit.db; Attachs=freekit.db; Pooling=true;Min Pool Size=1"
                                              }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17
                                          18
                                          19
                                          20
                                          21
                                          22
                                          23
                                          • 扩展方法配置 FreeSql,并设置 ICurrentUserAccessor 获取租户Id设置全局过滤器
                                          public static class ServiceCollectionExtensions
                                          {
                                              public static IServiceCollection AddFreeSql(this IServiceCollection services, IConfiguration c)
                                              {
                                                  Func<IServiceProvider, IFreeSql> fsql = r =>
                                                  {
                                                      var currentAccessor = r.GetRequiredService<ICurrentUserAccessor>();
                                                      IFreeSql fsql = new FreeSqlBuilder()
                                                              .UseConnectionString(c)
                                                              .UseNameConvert(NameConvertType.PascalCaseToUnderscoreWithLower)
                                                              .UseAutoSyncStructure(true) //自动同步实体结构到数据库,FreeSql不会扫描程序集,只有CRUD时才会生成表。
                                                              .UseGenerateCommandParameterWithLambda(true)//默认false,针对 lambda 表达式解析,设置成true时方便查看SQL
                                                              .UseNoneCommandParameter(true) //默认true,针对insert/update/delete是否参数化
                                                              .UseMonitorCommand(cmd =>
                                                              {
                                                                  Console.WriteLine("\r\n线程" + Thread.CurrentThread.ManagedThreadId + ": " + cmd.CommandText)
                                                              })
                                                              .Build();
                                          
                                                      fsql.GlobalFilter.ApplyOnly<ISoftDelete>("IsDeleted", a => a.IsDeleted == false);
                                                      fsql.GlobalFilter.ApplyOnlyIf<ITenant>("TenantId", () => currentAccessor.CurrentUser?.TenantId != null, a => a.TenantId == currentAccessor.CurrentUser.TenantId);
                                                      // 不使用IAuditBaseRepository的审计仓储 操作CRUD时,可使用此方式进行审计类的自动赋值
                                                      fsql.Aop.AuditValue += (_, e) => { e.AuditValue<Guid>(currentAccessor.CurrentUser); };
                                          
                                                      return fsql;
                                                  };
                                                  services.AddSingleton<IFreeSql>(fsql);
                                                  services.AddFreeKitCore();
                                                  using (IServiceScope scope = services.BuildServiceProvider().CreateScope())
                                                  {
                                                      var freeSql = scope.ServiceProvider.GetRequiredService<IFreeSql>();
                                                      //freeSql.CodeFirst.SyncStructure(ReflexHelper.GetTypesByTableAttribute(typeof(Program)));
                                                      freeSql.CodeFirst.SyncStructure(typeof(Song));
                                                  }
                                          
                                                  return services;
                                              }
                                          }
                                          //Program.cs
                                          var c = builder.Configuration;
                                          builder.Services.AddFreeSql(c);
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17
                                          18
                                          19
                                          20
                                          21
                                          22
                                          23
                                          24
                                          25
                                          26
                                          27
                                          28
                                          29
                                          30
                                          31
                                          32
                                          33
                                          34
                                          35
                                          36
                                          37
                                          38
                                          39
                                          40
                                          41

                                          # 基于特性标签的 AOP 事务

                                          该特性支持以Service为后缀的方法,并且需要继承接口

                                          • 特性标签 [Transactional]

                                          • Propagation 事务传播方式

                                            • Required 如果当前没有事务,就新建一个事务,如果已存在一个事务中,加入到这个事务中,默认的选择。
                                            • Supports 支持当前事务,如果没有当前事务,就以非事务方法执行
                                            • Mandatory 使用当前事务,如果没有当前事务,就抛出异常。
                                            • NotSupported 以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
                                            • Never 以非事务方式执行操作,如果当前事务存在则抛出异常。
                                            • Nested 以嵌套事务方式执行
                                          • IsolationLevel 事务隔离级别(默认为ReadCommitted)

                                            • ReadUncommitted 该事务可以读取还未被别的事务提交的数据(脏读)
                                            • ReadCommitted (sql server的默认隔离) 事务只可读取到别的事务中已经被提交的(Committed)数据,避免了"脏读"
                                            • RepeatableRead (InnoDB 的默认隔离级别) 为了保证多次读取数据的一致性,解决不可重复读(non-repeatable reads)
                                            • Serializable 为了解决"幻读"(Phantom reads)问题
                                          • 配置默认的事务级别(可不配置)

                                          builder.Services.Configure<UnitOfWorkDefualtOptions>(c =>
                                          {
                                              c.IsolationLevel=System.Data.IsolationLevel.ReadCommitted;//(默认为null时未指定时,依旧为null,根据数据库的事务隔离级别)
                                              c.Propagation = Propagation.Required;//(默认为null时未指定时,则指定Required)
                                          });
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          数据库默认隔离级别
                                          Oracleread committed
                                          SqlServerread committed
                                          MySQL(InnoDB)Read-Repeatable

                                          通过 Autofac 配置哪些类需要基于特性标签的 AOP 事务

                                          public interface IGroupService
                                          {
                                              Task DeleteAsync(long id);
                                          }
                                          public class GroupService : IGroupService
                                          {
                                              private readonly IBaseRepository<LinGroup, long> _groupRepository;
                                              private readonly IBaseRepository<LinGroupPermission, long> _groupPermissionRepository;
                                          
                                              public GroupService(IBaseRepository<LinGroup, long> groupRepository,IBaseRepository<LinGroupPermission, long> groupPermissionRepository)
                                              {
                                                  _groupRepository = groupRepository;
                                                  _groupPermissionRepository = groupPermissionRepository;
                                              }
                                              /// <summary>
                                              /// 删除group拥有的权限、删除group表的数据
                                              /// </summary>
                                              /// <param name="id"></param>
                                              /// <returns></returns>
                                              [Transactional]
                                              public async Task DeleteAsync(long id)
                                              {
                                                  await _groupRepository.DeleteAsync(id);
                                                  await _groupPermissionRepository.DeleteAsync(r => r.GroupId == id);
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17
                                          18
                                          19
                                          20
                                          21
                                          22
                                          23
                                          24
                                          25
                                          26

                                          或使用以Service为后缀的类,方法使用 virtual 关键字

                                          public class GroupService 
                                          {
                                              [Transactional]
                                              public virtual async Task DeleteAsync(long id)
                                              {
                                                  //事务操作:仓储从依赖注入中获取
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8

                                          如果依旧是 Startup 的模式,可通过 ConfigureContainer 配置服务,其中ServiceModule是一个Autofac的Module,此外为Demo

                                          • Program.cs 配置
                                              Host.CreateDefaultBuilder(args)
                                                          .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                                                          .ConfigureWebHostDefaults(webBuilder =>
                                                          {
                                                              webBuilder.UseStartup<Startup>();
                                                          });
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          • Startup.cs 配置
                                              public void ConfigureContainer(ContainerBuilder builder)
                                              {
                                                     Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(r =>
                                          r.FullName.Contains("IGeekFan.FreeKit.Web") 
                                          || r.FullName.Contains("Module1")
                                          || r.FullName.Contains("Module2")
                                          ).ToArray();
                                                  builder.RegisterModule(new UnitOfWorkModule(currentAssemblies));
                                                  builder.RegisterModule(new FreeKitModule(currentAssemblies));
                                              }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10

                                          .NET6 配置Autofac服务

                                          builder.Host
                                              .UseServiceProviderFactory(new AutofacServiceProviderFactory())
                                              .ConfigureContainer<ContainerBuilder>((webBuilder, containerBuilder) =>
                                              {
                                                     Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(r =>
                                          r.FullName.Contains("IGeekFan.FreeKit.Web") 
                                          || r.FullName.Contains("Module1")
                                          || r.FullName.Contains("Module2")
                                          ).ToArray();
                                                  containerBuilder.RegisterModule(new UnitOfWorkModule(currentAssemblies));
                                                  containerBuilder.RegisterModule(new FreeKitModule(currentAssemblies));
                                              });
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12

                                          # 基于接口的注入

                                          只需要继承如下接口,会自动按照对应的生命周期注入到 DI 中。

                                          • IScopedDependency 范围
                                          • ISingletonDependency 单例
                                          • ITransientDependency 瞬时
                                          namespace Module1
                                          {
                                              public interface ITestService : ITransientDependency
                                              {
                                                  bool ExecuteConnectTest();
                                              }
                                          }
                                          
                                          namespace Module1
                                          {
                                              public class TestService : ITestService
                                              {
                                                  private readonly IFreeSql _fsql;
                                                  public TestService(IFreeSql fsql)
                                                  {
                                                      _fsql = fsql;
                                                  }
                                          
                                                  public bool ExecuteConnectTest()
                                                  {
                                                      return _fsql.Ado.ExecuteConnectTest();
                                                  }
                                              }
                                          }
                                          
                                          public class TestController : Controller
                                          {
                                              ILogger<TestController> logger;
                                              private readonly ITestService testService;
                                          
                                              public TestController(ILogger<TestController> logger, ITestService testService)
                                              {
                                                  this.logger = logger;
                                                  this.testService = testService;
                                              }
                                          
                                              [HttpGet("ExecuteConnectTest")]
                                              public ActionResult<bool> ExecuteConnectTest()
                                              {
                                                  return testService.ExecuteConnectTest();
                                              }
                                          }
                                          
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17
                                          18
                                          19
                                          20
                                          21
                                          22
                                          23
                                          24
                                          25
                                          26
                                          27
                                          28
                                          29
                                          30
                                          31
                                          32
                                          33
                                          34
                                          35
                                          36
                                          37
                                          38
                                          39
                                          40
                                          41
                                          42
                                          43

                                          # 三种配置方式

                                          1.获取所有的程序集合,然后根据 FullName,一般为项目名,过滤具体的程序集

                                                  Assembly[] currentAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(r =>
                                          r.FullName.Contains("IGeekFan.FreeKit.Web") 
                                          || r.FullName.Contains("Module1")
                                          || r.FullName.Contains("Module2")
                                          ).ToArray();
                                          
                                                  containerBuilder.RegisterModule(new UnitOfWorkModule(currentAssemblies));
                                                  containerBuilder.RegisterModule(new FreeKitModule(currentAssemblies));
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8

                                          其中FreeKitModule的参数支持params Type[]types或params Assembly[]assemblies,即哪些程序集open in new window中的类需要注入到依赖注入的集合中。

                                          2.根据程序集中的某个类获取程序集,直接使用params Assembly[]

                                          Assembly[] currentAssemblies2 = new Assembly[] { typeof(Program).Assembly, typeof(Module1.Module1Startup).Assembly };
                                          containerBuilder.RegisterModule(new UnitOfWorkModule(currentAssemblies2));
                                          containerBuilder.RegisterModule(new FreeKitModule(currentAssemblies2));
                                          
                                          1
                                          2
                                          3

                                          3.params Type[],内部解析 Assembly。

                                          containerBuilder.RegisterModule(new UnitOfWorkModule(typeof(Program), typeof(Module1.Module1Startup)))
                                          containerBuilder.RegisterModule(new FreeKitModule(typeof(Program), typeof(Module1.Module1Startup)))
                                          
                                          1
                                          2

                                          其中,此程序集中的类 如果继承了IScopedDependency,ISingletonDependency、ITransientDependency这些接口, 都会按照对应的生命周期注入到依赖注入的集合中 ,可直接使用。

                                          # CurrentUser 当前登录人信息

                                          如何使用

                                          因为我们无法确定用户 Id 的类型,可能是long,也可能是Guid,ICurrentUser<T>是泛型的,默认有一个实现ICurrentUser:ICurrentUser<string>,所以通过 ICurrentUser,默认Id为string?类型,如果想改变类型,可使用ICurrentUser接口FindUserIdToLong扩展方法,获取long?类型的用户Id,或使用ICurrentUser接口FindUserIdToGuid的扩展方法

                                          此接口定义如下继承了ITransientDependency,所以他是瞬时

                                          public interface ICurrentUser<T> : ITransientDependency
                                          {
                                              /// <summary>
                                              /// 是否登录
                                              /// </summary>
                                              bool IsAuthenticated { get; }
                                          
                                              /// <summary>
                                              /// 用户Id
                                              /// </summary>
                                              T? Id { get; }
                                          
                                              /// <summary>
                                              /// 登录名,用户名,唯一值
                                              /// </summary>
                                              string UserName { get; }
                                          
                                              /// <summary>
                                              /// 邮件
                                              /// </summary>
                                              string? Email { get; }
                                          
                                              /// <summary>
                                              /// 租户Id
                                              /// </summary>
                                              Guid? TenantId { get; }
                                              
                                              /// <summary>
                                              /// 租户名
                                              /// </summary>
                                              string? TenantName { get; }
                                          
                                              /// <summary>
                                              /// 角色
                                              /// </summary>
                                              string[] Roles { get; }
                                          
                                              Claim FindClaim(string claimType);
                                          
                                              Claim[] FindClaims(string claimType);
                                          
                                              Claim[] GetAllClaims();
                                          
                                              bool IsInRole(string roleId);
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17
                                          18
                                          19
                                          20
                                          21
                                          22
                                          23
                                          24
                                          25
                                          26
                                          27
                                          28
                                          29
                                          30
                                          31
                                          32
                                          33
                                          34
                                          35
                                          36
                                          37
                                          38
                                          39
                                          40
                                          41
                                          42
                                          43
                                          44
                                          45

                                          我们需要增加一个扩展方法,更改用户Id类型,如果想更改用户Id类型,只需更改此方法即可,比如如果用户Id类型是long类型

                                          namespace IGeekFan.FreeKit.Extras.Security
                                          {
                                              public static class CurrentUserExtensions
                                              {
                                                  public static long? FindUserId(this ICurrentUser currentUser)
                                                  {
                                                      return currentUser.FindUserIdToLong();
                                                  }
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10

                                          然后在自己的服务类中注入·ICurrentUser接口,如,就可以获取用户的Id,及相关信息

                                          public interface IAccountService
                                          {
                                              long? GetUserId(string roleId);
                                          }
                                          public class AccountService : IAccountService
                                          {
                                              private readonly ICurrentUser _currentUser;
                                              public AccountService(ICurrentUser currentUser)
                                              {
                                                  _currentUser = currentUser;
                                              }
                                              public long? GetUserId(string roleId)
                                              {
                                                  string userId=_currentUser.Id;
                                                  return  _currentUser.FindUserId();
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17

                                          # 实体审计类

                                          • FullAuditEntity

                                          # CaseQuery 支持 Get 请求参数 key,大小驼峰转换

                                          HttpGet请求时,参数的 key 和实体相同,比如创建如下类。

                                          public class QueryModel
                                          {
                                              public string Title { get; set; }
                                              public string UserName { get; set; }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          [HttpGet]
                                          public IEnumerable<WeatherForecast> Get([FromQuery] QueryModel queryModel)
                                          {
                                              return null;
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5

                                          在 swagger 下就会生成如下内容

                                          DefaultQueryValue 如果实现,GET 请求参数的 key 转换呢。

                                          # 查询参数转换支持

                                          • SnakeCase(下划线写法)

                                          • LowerCase(小写)

                                          • CamelCase(首字母小写)

                                          • 使用方式

                                          在 AddControllers 中注入实现

                                              services.AddControllers(options =>
                                              {
                                                  options.ValueProviderFactories.Add(new CamelCaseValueProviderFactory());
                                              });
                                          
                                          1
                                          2
                                          3
                                          4

                                          swagger 渲染需要替换 provider

                                              services.TryAddEnumerable(ServiceDescriptor.Transient<IApiDescriptionProvider, CamelCaseApiDescriptionProvider>());
                                          
                                          1

                                          CamelCaseValueProviderFactory

                                          其中支持的 Factory 如下

                                          • SnakeCaseValueProviderFactory(下划线写法)
                                          • LowerCaseValueProviderFactory(小写)
                                          • CamelCaseValueProviderFactory(首字母小写)

                                          Provider 支持如下

                                          • SnakeApiDescriptionProvider(下划线写法)
                                          • LowerApiDescriptionProvider(小写)
                                          • CamelCaseApiDescriptionProvider(首字母小写)

                                          # 基于审计类的FreeSql仓储

                                          IAuditBaseRepository<TEntity, TKey>、IAuditBaseRepository<TEntity>

                                          什么是实体审计:记录修改实体的时间,修改实体的用户,创建人,创建的时间,删除人,删除时间等

                                          (AddFreeKitCore已包含此服务)

                                          services.AddCurrentUser().AddAuditRepostiory();
                                          
                                          1

                                          AddAuditRepostiory支持配置用户表的主键类型,默认为Guid,可指定类型,比如AddAuditRepostiory(typeof(Long)),

                                          用户表主键类型支持情况

                                          • Guid

                                          • Long

                                          • Int

                                          • 定义实体类

                                          public class Todo : FullAuditEntity
                                          {
                                              public string Message { get; set; }
                                              public DateTime? NotifictionTime { get; set; }
                                              public bool IsDone { get; set; }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          • AuditRepositoryTest
                                          public class AuditRepositoryTest
                                          {
                                              private readonly IAuditBaseRepository<Todo> _repository;
                                          
                                              public AuditRepositoryTest(IAuditBaseRepository<Todo> repository)
                                              {
                                                  _repository = repository;
                                              }
                                          
                                              [Fact]
                                              public void InsertEntityListTest()
                                              {
                                                  var list = new List<Todo>()
                                                  {
                                                      new Todo {Message = "这是一个要完成的TODO______1", NotifictionTime = null, IsDone = false},
                                                      new Todo {Message = "这是一个要完成的TODO______2", NotifictionTime = null, IsDone = false}
                                                  };
                                                  _repository.Insert(list);
                                                  _repository.Delete(list);
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          17
                                          18
                                          19
                                          20
                                          21
                                          INSERT INTO "Todo"("Id", "CreateUserId", "CreateUserName", "CreateTime", "UpdateUserId", "UpdateUserName", "UpdateTime", "DeleteUserId", "DeleteUserName", "DeleteTime", "IsDeleted", "Message", "NotifictionTime", "IsDone") VALUES('62eeeb97-ab46-67ec-00be-3ffb646bebab', 'f56b95fa-3f6c-4b75-a597-b1a7dd032516', 'Name', '2022-08-06 22:30:45', 'f56b95fa-3f6c-4b75-a597-b1a7dd032516', 'Name', '2022-08-06 22:30:45', NULL, NULL, NULL, 0, '这是一个要完成的TODO______1', NULL, 0), ('62eeeb97-ab46-67ec-00be-3ffc4461ef3c', 'f56b95fa-3f6c-4b75-a597-b1a7dd032516', 'Name', '2022-08-06 22:30:47', 'f56b95fa-3f6c-4b75-a597-b1a7dd032516', 'Name', '2022-08-06 22:30:47', NULL, NULL, NULL, 0, '这是一个要完成的TODO______2', NULL, 0)
                                          
                                          UPDATE "Todo" SET "DeleteUserId" = CASE "Id" 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffb646bebab' THEN 'f56b95fa-3f6c-4b75-a597-b1a7dd032516' 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffc4461ef3c' THEN 'f56b95fa-3f6c-4b75-a597-b1a7dd032516' END, "DeleteUserName" = CASE "Id" 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffb646bebab' THEN 'Name' 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffc4461ef3c' THEN 'Name' END, "DeleteTime" = CASE "Id" 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffb646bebab' THEN '2022-08-06 22:30:47' 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffc4461ef3c' THEN '2022-08-06 22:30:47' END, "IsDeleted" = CASE "Id" 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffb646bebab' THEN 1 
                                          WHEN '62eeeb97-ab46-67ec-00be-3ffc4461ef3c' THEN 1 END 
                                          WHERE ("Id" IN ('62eeeb97-ab46-67ec-00be-3ffb646bebab','62eeeb97-ab46-67ec-00be-3ffc4461ef3c')) AND ("IsDeleted" = 0)
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12

                                          # 复合主键仓储

                                          • 配置服务(AddFreeKitCore已包含此服务)
                                          services.AddCompositeRepostiory();
                                          
                                          1
                                          • 定义复合主键的类
                                          public class UserRole
                                          {
                                              [Column(IsPrimary = true)]
                                              public int UserId { get; set; }
                                              [Column(IsPrimary = true)]
                                              public int RoleId { get; set; }
                                              public DateTime CreateTime { get; set; }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          • 调用实例
                                          public class BaseRepositoryTest
                                          {
                                              private readonly IBaseRepository<UserRole, int, int> _repository;
                                              public BaseRepositoryTest(IBaseRepository<UserRole, int, int> repository)
                                              {
                                                  _repository = repository;
                                              }
                                          
                                              [Fact]
                                              public void GetTest()
                                              {
                                                  _repository.Insert(new UserRole() { UserId = 1, RoleId = 1, CreateTime = DateTime.Now });
                                                  UserRole userRole = _repository.Get(1, 1);
                                                  _repository.Delete(1, 1);
                                              }
                                          }
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          16
                                          INSERT INTO "UserRole"("UserId", "RoleId", "CreateTime") VALUES(1, 1, '2022-08-06 22:33:02')
                                          
                                          SELECT a."UserId", a."RoleId", a."CreateTime" 
                                          FROM "UserRole" a 
                                          WHERE (a."UserId" = 1 AND a."RoleId" = 1) 
                                          limit 0,1
                                          
                                          DELETE FROM "UserRole" WHERE ("UserId" = 1 AND "RoleId" = 1)
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8

                                          # 登录Jwt

                                          其中生成Jwt的Claim的类型如下。JWT+ASP.NET Core集成方案open in new window

                                              List<Claim> claims = new()
                                              {
                                                  new Claim (FreeKitClaimTypes.NameIdentifier, user.Id.ToString()),
                                                  new Claim (FreeKitClaimTypes.UserName, user.UserName),
                                                  new Claim (FreeKitClaimTypes.Email, user.Email?? ""),
                                                  new Claim (FreeKitClaimTypes.Name, user.Name)
                                              };
                                              if (user.TenantId.HasValue)
                                              {
                                                  claims.Add(new Claim(FreeKitClaimTypes.TenantId, user.TenantId.ToString() ?? string.Empty));
                                              }
                                              user.Roles?.ToList()?.ForEach(r =>
                                              {
                                                  claims.Add(new Claim(FreeKitClaimTypes.Role, r.Name));
                                              });
                                          
                                          1
                                          2
                                          3
                                          4
                                          5
                                          6
                                          7
                                          8
                                          9
                                          10
                                          11
                                          12
                                          13
                                          14
                                          15
                                          edit icon在 GitHub 上编辑此页open in new window
                                          上次编辑于: 2022/10/30 15:36:06
                                          贡献者: igeekfan,IGeekFan
                                          上一页
                                          FreeKit 基础包
                                          下一页
                                          AspNetCore Identity FreeSql的实现
                                          MIT Licensed | Copyright © 2021-present luoyunchong
                                          苏ICP备16046457号-1

                                          该应用可以安装在你的 PC 或移动设备上。这将使该 Web 应用程序外观和行为与其他应用程序相同。它将在出现在应用程序列表中,并可以固定到主屏幕,开始菜单或任务栏。此 Web 应用程序还将能够与其他应用程序和你的操作系统安全地进行交互。

                                          详情