wip: 解决配置管理+短信功能。优化大部分功能,解决启动bug

main
NoahLan 1 year ago
parent 76219dcfc3
commit f3382f9c8e

@ -0,0 +1,28 @@
using System.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling;
namespace NPin.Framework.AspNetCore.Abp;
/// <summary>
/// NPin框架自定义 HttpStatusCode 处理器
/// 将 IBusinessException 与 IUserFriendlyException 默认返回403改为500
/// </summary>
public class NPinHttpExceptionStatusCodeFinder : DefaultHttpExceptionStatusCodeFinder
{
public NPinHttpExceptionStatusCodeFinder(IOptions<AbpExceptionHttpStatusCodeOptions> options) : base(options)
{
}
public override HttpStatusCode GetStatusCode(HttpContext httpContext, Exception exception)
{
switch (exception)
{
case IBusinessException _:
return HttpStatusCode.InternalServerError;
default:
return base.GetStatusCode(httpContext, exception);
}
}
}

@ -1,9 +1,17 @@
using NPin.Framework.Core; using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.Modularity; using Microsoft.Extensions.DependencyInjection.Extensions;
using NPin.Framework.AspNetCore.Abp;
namespace NPin.Framework.AspNetCore; using NPin.Framework.Core;
using Volo.Abp.AspNetCore.ExceptionHandling;
[DependsOn(typeof(NPinFrameworkCoreModule))]
public class NPinFrameworkAspNetCoreModule : AbpModule namespace NPin.Framework.AspNetCore;
{
[DependsOn(typeof(NPinFrameworkCoreModule))]
public class NPinFrameworkAspNetCoreModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.Replace(new ServiceDescriptor(typeof(IHttpExceptionStatusCodeFinder),
typeof(NPinHttpExceptionStatusCodeFinder), ServiceLifetime.Transient));
}
} }

@ -1,105 +1,105 @@
using SqlSugar; using SqlSugar;
namespace NPin.Framework.SqlSugarCore.Abstractions; namespace NPin.Framework.SqlSugarCore.Abstractions;
public class DbConnOptions public class DbConnOptions
{ {
/// <summary> /// <summary>
/// 连接字符串 必填 /// 连接字符串 必填
/// </summary> /// </summary>
public string? Url { get; set; } public string? Url { get; set; }
/// <summary> /// <summary>
/// 数据库类型 /// 数据库类型
/// </summary> /// </summary>
public DbType? DbType { get; set; } public DbType? DbType { get; set; }
/// <summary> /// <summary>
/// 开启种子数据 /// 开启种子数据
/// </summary> /// </summary>
public bool EnabledDbSeed { get; set; } = false; public bool EnabledDbSeed { get; set; } = false;
/// <summary> /// <summary>
/// 开启 CodeFirst 自动化表结构 /// 开启 CodeFirst 自动化表结构
/// </summary> /// </summary>
public bool EnabledCodeFirst { get; set; } = false; public bool EnabledCodeFirst { get; set; } = false;
/// <summary> /// <summary>
/// 开启sql日志 /// 开启sql日志
/// </summary> /// </summary>
public bool EnabledSqlLog { get; set; } = true; public bool EnabledSqlLog { get; set; } = true;
/// <summary> /// <summary>
/// 实体程序集 /// 实体程序集
/// </summary> /// </summary>
public List<string>? EntityAssembly { get; set; } public List<string>? EntityAssembly { get; set; }
/// <summary> /// <summary>
/// 开启读写分离 /// 开启读写分离
/// </summary> /// </summary>
public bool EnabledReadWrite { get; set; } = false; public bool EnabledReadWrite { get; set; } = false;
/// <summary> /// <summary>
/// 读写分离 /// 读写分离
/// </summary> /// </summary>
public List<string>? ReadUrl { get; set; } public List<string>? ReadUrl { get; set; }
/// <summary> /// <summary>
/// 开启Saas多租户 /// 开启Saas多租户
/// </summary> /// </summary>
public bool EnabledSaasMultiTenancy { get; set; } = false; public bool EnabledSaasMultiTenancy { get; set; } = false;
/// <summary> /// <summary>
/// 默认租户库连接,如果不填,那就是默认库的地址 /// 默认租户库连接,如果不填,那就是默认库的地址
/// </summary> /// </summary>
public string? MasterSaasMultiTenancyUrl { get; set; } public string? MasterSaasMultiTenancyUrl { get; set; }
/// <summary> /// <summary>
/// Saas租户连接 /// Saas租户连接
/// </summary> /// </summary>
public List<SaasMultiTenancyOptions>? SaasMultiTenancy { get; set; } public List<SaasMultiTenancyOptions>? SaasMultiTenancy { get; set; }
public static string MasterTenantName = "Master"; public static string MasterTenantName = "Master";
public static string DefaultTenantName = "Default"; public static string DefaultTenantName = "Default";
public SaasMultiTenancyOptions GetDefaultSaasMultiTenancy() public SaasMultiTenancyOptions GetDefaultSaasMultiTenancy()
{ {
return new SaasMultiTenancyOptions { Name = DefaultTenantName, Url = Url }; return new SaasMultiTenancyOptions { Name = DefaultTenantName, Url = Url };
} }
public SaasMultiTenancyOptions? GetDefaultMasterSaasMultiTenancy() public SaasMultiTenancyOptions? GetMasterSaasMultiTenancy()
{ {
if (EnabledSaasMultiTenancy == false) if (EnabledSaasMultiTenancy == false)
{ {
return null; return null;
} }
if (string.IsNullOrEmpty(MasterSaasMultiTenancyUrl)) if (string.IsNullOrEmpty(MasterSaasMultiTenancyUrl))
{ {
return new SaasMultiTenancyOptions { Name = MasterTenantName, Url = Url }; return new SaasMultiTenancyOptions { Name = MasterTenantName, Url = Url };
} }
else else
{ {
return new SaasMultiTenancyOptions() return new SaasMultiTenancyOptions()
{ {
Name = MasterTenantName, Name = MasterTenantName,
Url = MasterSaasMultiTenancyUrl Url = MasterSaasMultiTenancyUrl
}; };
} }
} }
} }
public class SaasMultiTenancyOptions public class SaasMultiTenancyOptions
{ {
/// <summary> /// <summary>
/// 租户名称标识 /// 租户名称标识
/// </summary> /// </summary>
public string Name { get; set; } public string Name { get; set; }
/// <summary> /// <summary>
/// 连接Url /// 连接Url
/// </summary> /// </summary>
public string Url { get; set; } public string Url { get; set; }
} }

@ -1,94 +1,126 @@
using System.Reflection; using System.Reflection;
using Microsoft.Extensions.DependencyInjection; using System.Text;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.DependencyInjection.Extensions;
using NPin.Framework.SqlSugarCore.Abstractions; using Microsoft.Extensions.Logging;
using NPin.Framework.SqlSugarCore.Repositories; using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Uow; using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar; using NPin.Framework.SqlSugarCore.Repositories;
using Volo.Abp; using NPin.Framework.SqlSugarCore.Uow;
using Volo.Abp.Data; using SqlSugar;
using Volo.Abp.Domain; using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain;
using Volo.Abp.Modularity; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Guids;
namespace NPin.Framework.SqlSugarCore;
namespace NPin.Framework.SqlSugarCore;
[DependsOn(typeof(AbpDddDomainModule))]
public class NPinFrameworkSqlSugarCoreModule : AbpModule [DependsOn(typeof(AbpDddDomainModule))]
{ public class NPinFrameworkSqlSugarCoreModule : AbpModule
public override Task ConfigureServicesAsync(ServiceConfigurationContext context) {
{ public override Task ConfigureServicesAsync(ServiceConfigurationContext context)
var service = context.Services; {
var configuration = service.GetConfiguration(); var service = context.Services;
Configure<DbConnOptions>(configuration.GetSection("DbConnOptions")); var configuration = service.GetConfiguration();
Configure<DbConnOptions>(configuration.GetSection("DbConnOptions"));
// 开放 sqlSugarClient
service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContext>(); // 开放 sqlSugarClient
// 不开放 sqlSugarClient service.TryAddScoped<ISqlSugarDbContext, SqlSugarDbContext>();
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient); // 不开放 sqlSugarClient
//service.AddTransient<ISqlSugarClient>(x => x.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient);
service.AddTransient(typeof(IRepository<>), typeof(SqlSugarRepository<>));
service.AddTransient(typeof(IRepository<,>), typeof(SqlSugarRepository<,>)); service.AddTransient(typeof(IRepository<>), typeof(SqlSugarRepository<>));
service.AddTransient(typeof(ISqlSugarRepository<>), typeof(SqlSugarRepository<>)); service.AddTransient(typeof(IRepository<,>), typeof(SqlSugarRepository<,>));
service.AddTransient(typeof(ISqlSugarRepository<,>), typeof(SqlSugarRepository<,>)); service.AddTransient(typeof(ISqlSugarRepository<>), typeof(SqlSugarRepository<>));
service.AddTransient(typeof(ISqlSugarRepository<,>), typeof(SqlSugarRepository<,>));
service.AddTransient(typeof(ISugarDbContextProvider<>), typeof(UnitOfWorkSqlSugarDbContextProvider<>));
service.AddTransient(typeof(ISugarDbContextProvider<>), typeof(UnitOfWorkSqlSugarDbContextProvider<>));
return Task.CompletedTask;
} return Task.CompletedTask;
}
public override async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
{ public override async Task OnPreApplicationInitializationAsync(ApplicationInitializationContext context)
// CodeFirst & DataSeed {
var service = context.ServiceProvider; // CodeFirst & DataSeed
var options = service.GetRequiredService<IOptions<DbConnOptions>>().Value; var service = context.ServiceProvider;
var options = service.GetRequiredService<IOptions<DbConnOptions>>().Value;
if (options.EnabledCodeFirst)
{ Configure<AbpSequentialGuidGeneratorOptions>(opt =>
CodeFirst(service); {
} switch (options.DbType)
{
if (options.EnabledDbSeed) case DbType.PostgreSQL:
{ case DbType.MySql:
await DataSeedAsync(service); opt.DefaultSequentialGuidType = SequentialGuidType.SequentialAsString;
} break;
} case DbType.Oracle:
opt.DefaultSequentialGuidType = SequentialGuidType.SequentialAsBinary;
/// <summary> break;
/// CodeFirst 建库建表 default:
/// </summary> opt.DefaultSequentialGuidType = SequentialGuidType.SequentialAtEnd;
/// <param name="service"></param> break;
private void CodeFirst(IServiceProvider service) }
{ });
var moduleContainer = service.GetRequiredService<IModuleContainer>();
var db = service.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient; var logger = service.GetRequiredService<ILogger<NPinFrameworkSqlSugarCoreModule>>();
// 尝试创建数据库 StringBuilder sb = new StringBuilder();
db.DbMaintenance.CreateDatabase(); sb.AppendLine();
sb.AppendLine("==========NPin-SQL配置:==========");
var types = new List<Type>(); sb.AppendLine($"数据库连接字符串:{options.Url}");
foreach (var module in moduleContainer.Modules) sb.AppendLine($"数据库类型:{options.DbType.ToString()}");
{ sb.AppendLine($"是否开启种子数据:{options.EnabledDbSeed}");
types.AddRange(module.Assembly.GetTypes() sb.AppendLine($"是否开启CodeFirst{options.EnabledCodeFirst}");
.Where(x => x.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null) sb.AppendLine($"是否开启Saas多租户{options.EnabledSaasMultiTenancy}");
.Where(x => x.GetCustomAttribute<SugarTable>() != null) sb.AppendLine("===============================");
.Where(x => x.GetCustomAttribute<SplitTableAttribute>() is null));
} logger.LogInformation(sb.ToString());
if (types.Count > 0) if (options.EnabledCodeFirst)
{ {
db.CopyNew().CodeFirst.InitTables(types.ToArray()); CodeFirst(service);
} }
}
if (options.EnabledDbSeed)
/// <summary> {
/// 同步种子数据 await DataSeedAsync(service);
/// </summary> }
/// <param name="service"></param> }
private async Task DataSeedAsync(IServiceProvider service)
{ /// <summary>
var dataSeeder = service.GetRequiredService<IDataSeeder>(); /// CodeFirst 建库建表
await dataSeeder.SeedAsync(); /// </summary>
} /// <param name="service"></param>
private void CodeFirst(IServiceProvider service)
{
var moduleContainer = service.GetRequiredService<IModuleContainer>();
var db = service.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient;
// 尝试创建数据库
db.DbMaintenance.CreateDatabase();
var types = new List<Type>();
foreach (var module in moduleContainer.Modules)
{
types.AddRange(module.Assembly.GetTypes()
.Where(x => x.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null)
.Where(x => x.GetCustomAttribute<SugarTable>() != null)
.Where(x => x.GetCustomAttribute<SplitTableAttribute>() is null));
}
if (types.Count > 0)
{
db.CopyNew().CodeFirst.InitTables(types.ToArray());
}
}
/// <summary>
/// 同步种子数据
/// </summary>
/// <param name="service"></param>
private async Task DataSeedAsync(IServiceProvider service)
{
var dataSeeder = service.GetRequiredService<IDataSeeder>();
await dataSeeder.SeedAsync();
}
} }

@ -1,430 +1,431 @@
using System.Linq.Expressions; using System.Linq.Expressions;
using NPin.Framework.Core.Helper; using NPin.Framework.Core.Helper;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar; using SqlSugar;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Linq; using Volo.Abp.Linq;
namespace NPin.Framework.SqlSugarCore.Repositories; namespace NPin.Framework.SqlSugarCore.Repositories;
public class SqlSugarRepository<TEntity> : ISqlSugarRepository<TEntity>, IRepository<TEntity> public class SqlSugarRepository<TEntity> : ISqlSugarRepository<TEntity>, IRepository<TEntity>
where TEntity : class, IEntity, new() where TEntity : class, IEntity, new()
{ {
public ISqlSugarClient Db => GetDbContextAsync().Result; public ISqlSugarClient Db => GetDbContextAsync().Result;
public ISugarQueryable<TEntity> DbQueryable => GetDbContextAsync().Result.Queryable<TEntity>(); public ISugarQueryable<TEntity> DbQueryable => GetDbContextAsync().Result.Queryable<TEntity>();
private ISugarDbContextProvider<ISqlSugarDbContext> _sugarDbContextProvider; private ISugarDbContextProvider<ISqlSugarDbContext> _sugarDbContextProvider;
public IAsyncQueryableExecuter AsyncExecuter { get; } public IAsyncQueryableExecuter AsyncExecuter { get; }
public bool? IsChangeTrackingEnabled => false; public bool? IsChangeTrackingEnabled => false;
public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider)
{ {
_sugarDbContextProvider = sugarDbContextProvider; _sugarDbContextProvider = sugarDbContextProvider;
} }
public virtual async Task<ISqlSugarClient> GetDbContextAsync() public virtual async Task<ISqlSugarClient> GetDbContextAsync()
{ {
var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient; var db = (await _sugarDbContextProvider.GetDbContextAsync()).SqlSugarClient;
return db; // await Console.Out.WriteLineAsync("获取的id" + db.ContextID);
} return db;
}
public virtual async Task<SimpleClient<TEntity>> GetDbSimpleClientAsync()
{ public virtual async Task<SimpleClient<TEntity>> GetDbSimpleClientAsync()
var db = await GetDbContextAsync(); {
return new SimpleClient<TEntity>(db); var db = await GetDbContextAsync();
} return new SimpleClient<TEntity>(db);
}
#region Abp模块
#region Abp模块
public virtual async Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true,
CancellationToken cancellationToken = default) public virtual async Task<TEntity?> FindAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true,
{ CancellationToken cancellationToken = default)
return await GetFirstAsync(predicate); {
} return await GetFirstAsync(predicate);
}
public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true,
CancellationToken cancellationToken = default) public virtual async Task<TEntity> GetAsync(Expression<Func<TEntity, bool>> predicate, bool includeDetails = true,
{ CancellationToken cancellationToken = default)
return await GetFirstAsync(predicate); {
} return await GetFirstAsync(predicate);
}
public virtual async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task DeleteAsync(Expression<Func<TEntity, bool>> predicate, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await this.DeleteAsync(predicate); {
} await this.DeleteAsync(predicate);
}
public virtual async Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate,
CancellationToken cancellationToken = default) public virtual async Task DeleteDirectAsync(Expression<Func<TEntity, bool>> predicate,
{ CancellationToken cancellationToken = default)
await this.DeleteAsync(predicate); {
} await this.DeleteAsync(predicate);
}
public IQueryable<TEntity> WithDetails()
{ public IQueryable<TEntity> WithDetails()
throw new NotImplementedException(); {
} throw new NotImplementedException();
}
public IQueryable<TEntity> WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors)
{ public IQueryable<TEntity> WithDetails(params Expression<Func<TEntity, object>>[] propertySelectors)
throw new NotImplementedException(); {
} throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync()
{ public Task<IQueryable<TEntity>> WithDetailsAsync()
throw new NotImplementedException(); {
} throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors)
{ public Task<IQueryable<TEntity>> WithDetailsAsync(params Expression<Func<TEntity, object>>[] propertySelectors)
throw new NotImplementedException(); {
} throw new NotImplementedException();
}
public Task<IQueryable<TEntity>> GetQueryableAsync()
{ public Task<IQueryable<TEntity>> GetQueryableAsync()
throw new NotImplementedException(); {
} throw new NotImplementedException();
}
public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate,
bool includeDetails = false, CancellationToken cancellationToken = default) public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> predicate,
{ bool includeDetails = false, CancellationToken cancellationToken = default)
return await GetListAsync(predicate); {
} return await GetListAsync(predicate);
}
public virtual async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task<TEntity> InsertAsync(TEntity entity, bool autoSave = false,
{ CancellationToken cancellationToken = default)
return await InsertReturnEntityAsync(entity); {
} return await InsertReturnEntityAsync(entity);
}
public virtual async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task InsertManyAsync(IEnumerable<TEntity> entities, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await InsertRangeAsync(entities.ToList()); {
} await InsertRangeAsync(entities.ToList());
}
public virtual async Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task<TEntity> UpdateAsync(TEntity entity, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await UpdateAsync(entity); {
return entity; await UpdateAsync(entity);
} return entity;
}
public virtual async Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task UpdateManyAsync(IEnumerable<TEntity> entities, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await UpdateRangeAsync(entities.ToList()); {
} await UpdateRangeAsync(entities.ToList());
}
public virtual async Task DeleteAsync(TEntity entity, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task DeleteAsync(TEntity entity, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await DeleteAsync(entity); {
} await DeleteAsync(entity);
}
public virtual async Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task DeleteManyAsync(IEnumerable<TEntity> entities, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await DeleteAsync(entities.ToList()); {
} await DeleteAsync(entities.ToList());
}
public virtual async Task<List<TEntity>> GetListAsync(bool includeDetails = false,
CancellationToken cancellationToken = default) public virtual async Task<List<TEntity>> GetListAsync(bool includeDetails = false,
{ CancellationToken cancellationToken = default)
return await GetListAsync(); {
} return await GetListAsync();
}
public virtual async Task<long> GetCountAsync(CancellationToken cancellationToken = default)
{ public virtual async Task<long> GetCountAsync(CancellationToken cancellationToken = default)
return await this.CountAsync(); {
} return await this.CountAsync();
}
public virtual async Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting,
bool includeDetails = false, CancellationToken cancellationToken = default) public virtual async Task<List<TEntity>> GetPagedListAsync(int skipCount, int maxResultCount, string sorting,
{ bool includeDetails = false, CancellationToken cancellationToken = default)
return await GetPageListAsync(_ => true, skipCount, maxResultCount); {
} return await GetPageListAsync(_ => true, skipCount, maxResultCount);
}
#endregion
#endregion
#region 内置DB快捷操作
#region 内置DB快捷操作
public virtual async Task<IDeleteable<TEntity>> AsDeleteable()
{ public virtual async Task<IDeleteable<TEntity>> AsDeleteable()
return (await GetDbSimpleClientAsync()).AsDeleteable(); {
} return (await GetDbSimpleClientAsync()).AsDeleteable();
}
public virtual async Task<IInsertable<TEntity>> AsInsertable(List<TEntity> insertObjs)
{ public virtual async Task<IInsertable<TEntity>> AsInsertable(List<TEntity> insertObjs)
return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs); {
} return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs);
}
public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity insertObj)
{ public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity insertObj)
return (await GetDbSimpleClientAsync()).AsInsertable(insertObj); {
} return (await GetDbSimpleClientAsync()).AsInsertable(insertObj);
}
public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity[] insertObjs)
{ public virtual async Task<IInsertable<TEntity>> AsInsertable(TEntity[] insertObjs)
return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs); {
} return (await GetDbSimpleClientAsync()).AsInsertable(insertObjs);
}
public virtual async Task<ISugarQueryable<TEntity>> AsQueryable()
{ public virtual async Task<ISugarQueryable<TEntity>> AsQueryable()
return (await GetDbSimpleClientAsync()).AsQueryable(); {
} return (await GetDbSimpleClientAsync()).AsQueryable();
}
public virtual async Task<ISqlSugarClient> AsSugarClient()
{ public virtual async Task<ISqlSugarClient> AsSugarClient()
return (await GetDbSimpleClientAsync()).AsSugarClient(); {
} return (await GetDbSimpleClientAsync()).AsSugarClient();
}
public virtual async Task<ITenant> AsTenant()
{ public virtual async Task<ITenant> AsTenant()
return (await GetDbSimpleClientAsync()).AsTenant(); {
} return (await GetDbSimpleClientAsync()).AsTenant();
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable(List<TEntity> updateObjs)
{ public virtual async Task<IUpdateable<TEntity>> AsUpdateable(List<TEntity> updateObjs)
return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs); {
} return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs);
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable(TEntity updateObj)
{ public virtual async Task<IUpdateable<TEntity>> AsUpdateable(TEntity updateObj)
return (await GetDbSimpleClientAsync()).AsUpdateable(updateObj); {
} return (await GetDbSimpleClientAsync()).AsUpdateable(updateObj);
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable()
{ public virtual async Task<IUpdateable<TEntity>> AsUpdateable()
return (await GetDbSimpleClientAsync()).AsUpdateable(); {
} return (await GetDbSimpleClientAsync()).AsUpdateable();
}
public virtual async Task<IUpdateable<TEntity>> AsUpdateable(TEntity[] updateObjs)
{ public virtual async Task<IUpdateable<TEntity>> AsUpdateable(TEntity[] updateObjs)
return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs); {
} return (await GetDbSimpleClientAsync()).AsUpdateable(updateObjs);
}
#endregion
#endregion
#region SimpleClient模块
#region SimpleClient模块
public virtual async Task<int> CountAsync(Expression<Func<TEntity, bool>> whereExpression)
{ public virtual async Task<int> CountAsync(Expression<Func<TEntity, bool>> whereExpression)
return await (await GetDbSimpleClientAsync()).CountAsync(whereExpression); {
} return await (await GetDbSimpleClientAsync()).CountAsync(whereExpression);
}
public virtual async Task<bool> DeleteAsync(TEntity deleteObj)
{ public virtual async Task<bool> DeleteAsync(TEntity deleteObj)
if (deleteObj is ISoftDelete) {
{ if (deleteObj is ISoftDelete)
ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, deleteObj); {
return await (await GetDbSimpleClientAsync()).UpdateAsync(deleteObj); ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, deleteObj);
} return await (await GetDbSimpleClientAsync()).UpdateAsync(deleteObj);
else }
{ else
return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObj); {
} return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObj);
} }
}
public virtual async Task<bool> DeleteAsync(List<TEntity> deleteObjs)
{ public virtual async Task<bool> DeleteAsync(List<TEntity> deleteObjs)
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) {
{ if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
deleteObjs.ForEach(e => ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e)); {
return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(deleteObjs); deleteObjs.ForEach(e => ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e));
} return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(deleteObjs);
else }
{ else
return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObjs); {
} return await (await GetDbSimpleClientAsync()).DeleteAsync(deleteObjs);
} }
}
public virtual async Task<bool> DeleteAsync(Expression<Func<TEntity, bool>> whereExpression)
{ public virtual async Task<bool> DeleteAsync(Expression<Func<TEntity, bool>> whereExpression)
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) {
{ if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
return await (await GetDbSimpleClientAsync()).AsUpdateable().SetColumns(nameof(ISoftDelete), true) {
.Where(whereExpression).ExecuteCommandAsync() > 0; return await (await GetDbSimpleClientAsync()).AsUpdateable().SetColumns(nameof(ISoftDelete), true)
} .Where(whereExpression).ExecuteCommandAsync() > 0;
else }
{ else
return await (await GetDbSimpleClientAsync()).DeleteAsync(whereExpression); {
} return await (await GetDbSimpleClientAsync()).DeleteAsync(whereExpression);
} }
}
public virtual async Task<bool> DeleteByIdAsync(dynamic id)
{ public virtual async Task<bool> DeleteByIdAsync(dynamic id)
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) {
{ if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
var entity = await GetByIdAsync(id); {
//反射赋值 var entity = await GetByIdAsync(id);
ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, entity); //反射赋值
return await UpdateAsync(entity); ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, entity);
} return await UpdateAsync(entity);
else }
{ else
return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(id); {
} return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(id);
} }
}
public virtual async Task<bool> DeleteByIdsAsync(dynamic[] ids)
{ public virtual async Task<bool> DeleteByIdsAsync(dynamic[] ids)
if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity))) {
{ if (typeof(ISoftDelete).IsAssignableFrom(typeof(TEntity)))
var simpleClient = (await GetDbSimpleClientAsync()); {
var entities = await simpleClient.AsQueryable().In(ids).ToListAsync(); var simpleClient = (await GetDbSimpleClientAsync());
if (entities.Count == 0) var entities = await simpleClient.AsQueryable().In(ids).ToListAsync();
{ if (entities.Count == 0)
return false; {
} return false;
}
// 反射赋值
entities.ForEach(e => ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e)); // 反射赋值
return await UpdateRangeAsync(entities); entities.ForEach(e => ReflectHelper.SetModelValue(nameof(ISoftDelete.IsDeleted), true, e));
} return await UpdateRangeAsync(entities);
else }
{ else
return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(ids); {
} return await (await GetDbSimpleClientAsync()).DeleteByIdAsync(ids);
} }
}
public virtual async Task<TEntity> GetByIdAsync(dynamic id)
{ public virtual async Task<TEntity> GetByIdAsync(dynamic id)
return await (await GetDbSimpleClientAsync()).GetByIdAsync(id); {
} return await (await GetDbSimpleClientAsync()).GetByIdAsync(id);
}
public virtual async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> whereExpression)
{ public virtual async Task<TEntity> GetFirstAsync(Expression<Func<TEntity, bool>> whereExpression)
return await (await GetDbSimpleClientAsync()).GetFirstAsync(whereExpression); {
} return await (await GetDbSimpleClientAsync()).GetFirstAsync(whereExpression);
}
public virtual async Task<List<TEntity>> GetListAsync()
{ public virtual async Task<List<TEntity>> GetListAsync()
return await (await GetDbSimpleClientAsync()).GetListAsync(); {
} return await (await GetDbSimpleClientAsync()).GetListAsync();
}
public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> whereExpression)
{ public virtual async Task<List<TEntity>> GetListAsync(Expression<Func<TEntity, bool>> whereExpression)
return await (await GetDbSimpleClientAsync()).GetListAsync(whereExpression); {
} return await (await GetDbSimpleClientAsync()).GetListAsync(whereExpression);
}
public virtual async Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression,
int pageNum, int pageSize) public virtual async Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression,
{ int pageNum, int pageSize)
return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, {
new PageModel() { PageIndex = pageNum, PageSize = pageSize }); return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression,
} new PageModel() { PageIndex = pageNum, PageSize = pageSize });
}
public virtual async Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression,
int pageNum, int pageSize, public virtual async Task<List<TEntity>> GetPageListAsync(Expression<Func<TEntity, bool>> whereExpression,
Expression<Func<TEntity, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Asc) int pageNum, int pageSize,
{ Expression<Func<TEntity, object>>? orderByExpression = null, OrderByType orderByType = OrderByType.Asc)
return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression, {
new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType); return await (await GetDbSimpleClientAsync()).GetPageListAsync(whereExpression,
} new PageModel { PageIndex = pageNum, PageSize = pageSize }, orderByExpression, orderByType);
}
public virtual async Task<TEntity> GetSingleAsync(Expression<Func<TEntity, bool>> whereExpression)
{ public virtual async Task<TEntity> GetSingleAsync(Expression<Func<TEntity, bool>> whereExpression)
return await (await GetDbSimpleClientAsync()).GetSingleAsync(whereExpression); {
} return await (await GetDbSimpleClientAsync()).GetSingleAsync(whereExpression);
}
public virtual async Task<bool> InsertAsync(TEntity insertObj)
{ public virtual async Task<bool> InsertAsync(TEntity insertObj)
return await (await GetDbSimpleClientAsync()).InsertAsync(insertObj); {
} return await (await GetDbSimpleClientAsync()).InsertAsync(insertObj);
}
public virtual async Task<bool> InsertOrUpdateAsync(TEntity data)
{ public virtual async Task<bool> InsertOrUpdateAsync(TEntity data)
return await (await GetDbSimpleClientAsync()).InsertOrUpdateAsync(data); {
} return await (await GetDbSimpleClientAsync()).InsertOrUpdateAsync(data);
}
public virtual async Task<bool> InsertOrUpdateAsync(List<TEntity> datas)
{ public virtual async Task<bool> InsertOrUpdateAsync(List<TEntity> datas)
return await (await GetDbSimpleClientAsync()).InsertOrUpdateAsync(datas); {
} return await (await GetDbSimpleClientAsync()).InsertOrUpdateAsync(datas);
}
public virtual async Task<bool> InsertRangeAsync(List<TEntity> insertObjs)
{ public virtual async Task<bool> InsertRangeAsync(List<TEntity> insertObjs)
return await (await GetDbSimpleClientAsync()).InsertRangeAsync(insertObjs); {
} return await (await GetDbSimpleClientAsync()).InsertRangeAsync(insertObjs);
}
public virtual async Task<long> InsertReturnBigIdentityAsync(TEntity insertObj)
{ public virtual async Task<long> InsertReturnBigIdentityAsync(TEntity insertObj)
return await (await GetDbSimpleClientAsync()).InsertReturnBigIdentityAsync(insertObj); {
} return await (await GetDbSimpleClientAsync()).InsertReturnBigIdentityAsync(insertObj);
}
public virtual async Task<TEntity> InsertReturnEntityAsync(TEntity insertObj)
{ public virtual async Task<TEntity> InsertReturnEntityAsync(TEntity insertObj)
return await (await GetDbSimpleClientAsync()).InsertReturnEntityAsync(insertObj); {
} return await (await GetDbSimpleClientAsync()).InsertReturnEntityAsync(insertObj);
}
public virtual async Task<int> InsertReturnIdentityAsync(TEntity insertObj)
{ public virtual async Task<int> InsertReturnIdentityAsync(TEntity insertObj)
return await (await GetDbSimpleClientAsync()).InsertReturnIdentityAsync(insertObj); {
} return await (await GetDbSimpleClientAsync()).InsertReturnIdentityAsync(insertObj);
}
public virtual async Task<long> InsertReturnSnowflakeIdAsync(TEntity insertObj)
{ public virtual async Task<long> InsertReturnSnowflakeIdAsync(TEntity insertObj)
return await (await GetDbSimpleClientAsync()).InsertReturnSnowflakeIdAsync(insertObj); {
} return await (await GetDbSimpleClientAsync()).InsertReturnSnowflakeIdAsync(insertObj);
}
public virtual async Task<bool> IsAnyAsync(Expression<Func<TEntity, bool>> whereExpression)
{ public virtual async Task<bool> IsAnyAsync(Expression<Func<TEntity, bool>> whereExpression)
return await (await GetDbSimpleClientAsync()).IsAnyAsync(whereExpression); {
} return await (await GetDbSimpleClientAsync()).IsAnyAsync(whereExpression);
}
public virtual async Task<bool> UpdateAsync(TEntity updateObj)
{ public virtual async Task<bool> UpdateAsync(TEntity updateObj)
return await (await GetDbSimpleClientAsync()).UpdateAsync(updateObj); {
} return await (await GetDbSimpleClientAsync()).UpdateAsync(updateObj);
}
public virtual async Task<bool> UpdateAsync(Expression<Func<TEntity, TEntity>> columns,
Expression<Func<TEntity, bool>> whereExpression) public virtual async Task<bool> UpdateAsync(Expression<Func<TEntity, TEntity>> columns,
{ Expression<Func<TEntity, bool>> whereExpression)
return await (await GetDbSimpleClientAsync()).UpdateAsync(columns, whereExpression); {
} return await (await GetDbSimpleClientAsync()).UpdateAsync(columns, whereExpression);
}
public virtual async Task<bool> UpdateRangeAsync(List<TEntity> updateObjs)
{ public virtual async Task<bool> UpdateRangeAsync(List<TEntity> updateObjs)
return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(updateObjs); {
} return await (await GetDbSimpleClientAsync()).UpdateRangeAsync(updateObjs);
}
#endregion
} #endregion
}
public class SqlSugarRepository<TEntity, TKey> : SqlSugarRepository<TEntity>, ISqlSugarRepository<TEntity, TKey>,
IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey>, new() public class SqlSugarRepository<TEntity, TKey> : SqlSugarRepository<TEntity>, ISqlSugarRepository<TEntity, TKey>,
{ IRepository<TEntity, TKey> where TEntity : class, IEntity<TKey>, new()
public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base( {
sugarDbContextProvider) public SqlSugarRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base(
{ sugarDbContextProvider)
} {
}
public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
{ public virtual async Task DeleteAsync(TKey id, bool autoSave = false, CancellationToken cancellationToken = default)
await DeleteByIdAsync(id); {
} await DeleteByIdAsync(id);
}
public virtual async Task DeleteManyAsync(IEnumerable<TKey> ids, bool autoSave = false,
CancellationToken cancellationToken = default) public virtual async Task DeleteManyAsync(IEnumerable<TKey> ids, bool autoSave = false,
{ CancellationToken cancellationToken = default)
await DeleteByIdsAsync(ids.Select(x => (object)x).ToArray()); {
} await DeleteByIdsAsync(ids.Select(x => (object)x).ToArray());
}
public virtual async Task<TEntity?> FindAsync(TKey id, bool includeDetails = true,
CancellationToken cancellationToken = default) public virtual async Task<TEntity?> FindAsync(TKey id, bool includeDetails = true,
{ CancellationToken cancellationToken = default)
return await GetByIdAsync(id); {
} return await GetByIdAsync(id);
}
public virtual async Task<TEntity> GetAsync(TKey id, bool includeDetails = true,
CancellationToken cancellationToken = default) public virtual async Task<TEntity> GetAsync(TKey id, bool includeDetails = true,
{ CancellationToken cancellationToken = default)
return await GetByIdAsync(id); {
} return await GetByIdAsync(id);
}
} }

@ -1,117 +1,124 @@
using System.Reflection; using System.Reflection;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar; using SqlSugar;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace NPin.Framework.SqlSugarCore; namespace NPin.Framework.SqlSugarCore;
public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransientDependency public class SqlSugarDbConnectionCreator : ISqlSugarDbConnectionCreator, ITransientDependency
{ {
[DisablePropertyInjection] public Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; } [DisablePropertyInjection] public Action<ISqlSugarClient> OnSqlSugarClientConfig { get; set; }
[DisablePropertyInjection] public Action<object, DataAfterModel> DataExecuted { get; set; } [DisablePropertyInjection] public Action<object, DataAfterModel> DataExecuted { get; set; }
[DisablePropertyInjection] public Action<object, DataFilterModel> DataExecuting { get; set; } [DisablePropertyInjection] public Action<object, DataFilterModel> DataExecuting { get; set; }
[DisablePropertyInjection] public Action<string, SugarParameter[]> OnLogExecuting { get; set; } [DisablePropertyInjection] public Action<string, SugarParameter[]> OnLogExecuting { get; set; }
[DisablePropertyInjection] public Action<string, SugarParameter[]> OnLogExecuted { get; set; } [DisablePropertyInjection] public Action<string, SugarParameter[]> OnLogExecuted { get; set; }
[DisablePropertyInjection] public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; } [DisablePropertyInjection] public Action<PropertyInfo, EntityColumnInfo> EntityService { get; set; }
[DisablePropertyInjection] public Action<Type, EntityInfo> EntityNameService { get; set; } [DisablePropertyInjection] public Action<Type, EntityInfo> EntityNameService { get; set; }
public DbConnOptions Options { get; } public DbConnOptions Options { get; }
public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options) public SqlSugarDbConnectionCreator(IOptions<DbConnOptions> options)
{ {
Options = options.Value; Options = options.Value;
} }
public void SetDbAop(ISqlSugarClient currentDb) public void SetDbAop(ISqlSugarClient currentDb)
{ {
currentDb.Aop.OnLogExecuting = this.OnLogExecuting; currentDb.Aop.OnLogExecuting = this.OnLogExecuting;
currentDb.Aop.OnLogExecuted = this.OnLogExecuted; currentDb.Aop.OnLogExecuted = this.OnLogExecuted;
currentDb.Aop.DataExecuting = this.DataExecuting; currentDb.Aop.DataExecuting = this.DataExecuting;
currentDb.Aop.DataExecuted = this.DataExecuted; currentDb.Aop.DataExecuted = this.DataExecuted;
OnSqlSugarClientConfig(currentDb); OnSqlSugarClientConfig(currentDb);
} }
public ConnectionConfig Build(Action<ConnectionConfig>? action = null) public ConnectionConfig Build(Action<ConnectionConfig>? action = null)
{ {
var dbConnOptions = Options; var dbConnOptions = Options;
#region 组装Options #region 组装Options
if (dbConnOptions.DbType is null) if (dbConnOptions.DbType is null)
{ {
throw new ArgumentException("DbType配置为空"); throw new ArgumentException("DbType配置为空");
} }
// 读写分离 slave模式 // 读写分离 slave模式
var slaveConfigs = new List<SlaveConnectionConfig>(); var slaveConfigs = new List<SlaveConnectionConfig>();
if (dbConnOptions.EnabledReadWrite) if (dbConnOptions.EnabledReadWrite)
{ {
if (dbConnOptions.ReadUrl is null) if (dbConnOptions.ReadUrl is null)
{ {
throw new ArgumentException("读写分离开启,但读库配置为空"); throw new ArgumentException("读写分离开启,但读库配置为空");
} }
var readConn = dbConnOptions.ReadUrl; var readConn = dbConnOptions.ReadUrl;
readConn.ForEach(s => readConn.ForEach(s =>
{ {
// 如果是动态分库,连接串不能写死,需要动态添加,所以此处只配置共享库的连接 // 如果是动态分库,连接串不能写死,需要动态添加,所以此处只配置共享库的连接
slaveConfigs.Add(new SlaveConnectionConfig { ConnectionString = s }); slaveConfigs.Add(new SlaveConnectionConfig { ConnectionString = s });
}); });
} }
#endregion #endregion
#region 组装连接配置 #region 组装连接配置
var connectionConfig = new ConnectionConfig var connectionConfig = new ConnectionConfig
{ {
ConfigId = ConnectionStrings.DefaultConnectionStringName, ConfigId = ConnectionStrings.DefaultConnectionStringName,
DbType = dbConnOptions.DbType ?? DbType.Sqlite, DbType = dbConnOptions.DbType ?? DbType.Sqlite,
ConnectionString = dbConnOptions.Url, ConnectionString = dbConnOptions.Url,
IsAutoCloseConnection = true, IsAutoCloseConnection = true,
SlaveConnectionConfigs = slaveConfigs, SlaveConnectionConfigs = slaveConfigs,
// CodeFirst 非空值判断 LanguageType = LanguageType.Chinese,
ConfigureExternalServices = new ConfigureExternalServices MoreSettings = new ConnMoreSettings
{ {
EntityService = (c, p) => SqliteCodeFirstEnableDescription = true,
{ PgSqlIsAutoToLower = true,
if (new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable) PgSqlIsAutoToLowerCodeFirst = true,
{ },
p.IsNullable = true; // CodeFirst 非空值判断
} ConfigureExternalServices = new ConfigureExternalServices
{
EntityService(c, p); EntityService = (c, p) =>
}, {
EntityNameService = (t, e) => if (new NullabilityInfoContext().Create(c).WriteState is NullabilityState.Nullable)
{ {
EntityNameService(t, e); p.IsNullable = true;
} }
},
// Aop EntityService(c, p);
AopEvents = new AopEvents },
{ EntityNameService = (t, e) =>
DataExecuted = DataExecuted, {
DataExecuting = DataExecuting, EntityNameService(t, e);
OnLogExecuted = OnLogExecuted, }
OnLogExecuting = OnLogExecuting },
} // Aop
}; AopEvents = new AopEvents
{
if (action is not null) DataExecuted = DataExecuted,
{ DataExecuting = DataExecuting,
action.Invoke(connectionConfig); OnLogExecuted = OnLogExecuted,
} OnLogExecuting = OnLogExecuting
}
#endregion };
return connectionConfig; if (action is not null)
} {
action.Invoke(connectionConfig);
}
#endregion
return connectionConfig;
}
} }

@ -1,269 +1,306 @@
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Domain.Entities.Events; using Volo.Abp.Domain.Entities.Events;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Users; using Volo.Abp.Users;
namespace NPin.Framework.SqlSugarCore; namespace NPin.Framework.SqlSugarCore;
public class SqlSugarDbContext : ISqlSugarDbContext public class SqlSugarDbContext : ISqlSugarDbContext
{ {
private IAbpLazyServiceProvider LazyServiceProvider { get; } private IAbpLazyServiceProvider LazyServiceProvider { get; }
public ISqlSugarClient SqlSugarClient { get; private set; } public ISqlSugarClient SqlSugarClient { get; private set; }
public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value; public DbConnOptions Options => LazyServiceProvider.LazyGetRequiredService<IOptions<DbConnOptions>>().Value;
public ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>(); public ICurrentUser CurrentUser => LazyServiceProvider.GetRequiredService<ICurrentUser>();
public ICurrentTenant? CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>(); public ICurrentTenant CurrentTenant => LazyServiceProvider.LazyGetRequiredService<ICurrentTenant>();
public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>(); public IDataFilter DataFilter => LazyServiceProvider.LazyGetRequiredService<IDataFilter>();
private IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>(); private IGuidGenerator GuidGenerator => LazyServiceProvider.LazyGetRequiredService<IGuidGenerator>();
protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>(); protected ILoggerFactory Logger => LazyServiceProvider.LazyGetRequiredService<ILoggerFactory>();
protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false; protected virtual bool IsMultiTenantFilterEnabled => DataFilter?.IsEnabled<IMultiTenant>() ?? false;
protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false; protected virtual bool IsSoftDeleteFilterEnabled => DataFilter?.IsEnabled<ISoftDelete>() ?? false;
public IEntityChangeEventHelper EntityChangeEventHelper => public IEntityChangeEventHelper EntityChangeEventHelper =>
LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance); LazyServiceProvider.LazyGetService<IEntityChangeEventHelper>(NullEntityChangeEventHelper.Instance);
public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient) public void SetSqlSugarClient(ISqlSugarClient sqlSugarClient)
{ {
SqlSugarClient = sqlSugarClient; SqlSugarClient = sqlSugarClient;
} }
public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider) public SqlSugarDbContext(IAbpLazyServiceProvider lazyServiceProvider)
{ {
LazyServiceProvider = lazyServiceProvider; LazyServiceProvider = lazyServiceProvider;
var connectionCreator = LazyServiceProvider.LazyGetRequiredService<ISqlSugarDbConnectionCreator>(); var connectionCreator = LazyServiceProvider.LazyGetRequiredService<ISqlSugarDbConnectionCreator>();
connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig; connectionCreator.OnSqlSugarClientConfig = OnSqlSugarClientConfig;
connectionCreator.EntityService = EntityService; connectionCreator.EntityService = EntityService;
connectionCreator.EntityNameService = EntityNameService; connectionCreator.EntityNameService = EntityNameService;
connectionCreator.DataExecuting = DataExecuting; connectionCreator.DataExecuting = DataExecuting;
connectionCreator.DataExecuted = DataExecuted; connectionCreator.DataExecuted = DataExecuted;
connectionCreator.OnLogExecuting = OnLogExecuting; connectionCreator.OnLogExecuting = OnLogExecuting;
connectionCreator.OnLogExecuted = OnLogExecuted; connectionCreator.OnLogExecuted = OnLogExecuted;
SqlSugarClient = new SqlSugarClient(connectionCreator.Build()); var connStr = GetCurrentConnectionString();
connectionCreator.SetDbAop(SqlSugarClient);
} SqlSugarClient = new SqlSugarClient(connectionCreator.Build(action: opt =>
{
/// <summary> opt.ConnectionString = connStr;
/// 上下文对象扩展 }));
/// </summary> connectionCreator.SetDbAop(SqlSugarClient);
/// <param name="sqlSugarClient"></param> }
protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
{ /// <summary>
//需自定义扩展 /// db切换多库支持
if (IsSoftDeleteFilterEnabled) /// </summary>
{ /// <returns></returns>
sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false); protected virtual string GetCurrentConnectionString()
} {
var connectionStringResolver = LazyServiceProvider.LazyGetRequiredService<IConnectionStringResolver>();
if (IsMultiTenantFilterEnabled) var connectionString = connectionStringResolver.ResolveAsync().Result;
{
sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == GuidGenerator.Create()); //没有检测到使用多租户功能,默认使用默认库即可
} if (string.IsNullOrWhiteSpace(connectionString))
{
// 自定义其它Filter Volo.Abp.Check.NotNull(Options.Url, "租户默认库Default未找到");
CustomDataFilter(sqlSugarClient); connectionString = Options.Url;
} }
protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient) //如果当前租户是主库,单独使用主要库
{ if (CurrentTenant.Name == DbConnOptions.MasterTenantName)
} {
var conStrOrNull = Options.GetMasterSaasMultiTenancy();
protected virtual void DataExecuted(object oldValue, DataAfterModel entityInfo) Volo.Abp.Check.NotNull(conStrOrNull, "租户主库Master未找到");
{ connectionString = conStrOrNull.Url;
} }
protected virtual void DataExecuting(object? oldValue, DataFilterModel entityInfo) return connectionString!;
{ }
// 审计日志
switch (entityInfo.OperationType) /// <summary>
{ /// 上下文对象扩展
case DataFilterType.UpdateByObject: /// </summary>
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime))) /// <param name="sqlSugarClient"></param>
{ protected virtual void OnSqlSugarClientConfig(ISqlSugarClient sqlSugarClient)
if (!DateTime.MinValue.Equals(oldValue)) {
{ //需自定义扩展
entityInfo.SetValue(DateTime.Now); if (IsSoftDeleteFilterEnabled)
} {
} sqlSugarClient.QueryFilter.AddTableFilter<ISoftDelete>(u => u.IsDeleted == false);
}
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
{ if (IsMultiTenantFilterEnabled)
if (CurrentUser.Id != null) {
{ sqlSugarClient.QueryFilter.AddTableFilter<IMultiTenant>(u => u.TenantId == CurrentTenant.Id);
entityInfo.SetValue(CurrentUser.Id); }
}
} // 自定义其它Filter
CustomDataFilter(sqlSugarClient);
break; }
case DataFilterType.InsertByObject:
if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id))) protected virtual void CustomDataFilter(ISqlSugarClient sqlSugarClient)
{ {
//主键为空或者为默认最小值 }
if (Guid.Empty.Equals(oldValue))
{ protected virtual void DataExecuted(object oldValue, DataAfterModel entityInfo)
entityInfo.SetValue(GuidGenerator.Create()); {
} }
}
protected virtual void DataExecuting(object? oldValue, DataFilterModel entityInfo)
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime))) {
{ // 审计日志
//为空或者为默认最小值 switch (entityInfo.OperationType)
if (oldValue is null || DateTime.MinValue.Equals(oldValue)) {
{ case DataFilterType.UpdateByObject:
entityInfo.SetValue(DateTime.Now); if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModificationTime)))
} {
} if (!DateTime.MinValue.Equals(oldValue))
{
if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId))) entityInfo.SetValue(DateTime.Now);
{ }
if (CurrentUser.Id != null) }
{
entityInfo.SetValue(CurrentUser.Id); if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.LastModifierId)))
} {
} if (CurrentUser.Id != null)
{
//插入时需要租户id,先预留 entityInfo.SetValue(CurrentUser.Id);
if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId))) }
{ }
if (CurrentTenant is not null)
{ break;
entityInfo.SetValue(CurrentTenant.Id); case DataFilterType.InsertByObject:
} if (entityInfo.PropertyName.Equals(nameof(IEntity<Guid>.Id)))
} {
//主键为空或者为默认最小值
break; if (Guid.Empty.Equals(oldValue))
} {
entityInfo.SetValue(GuidGenerator.Create());
}
//领域事件 }
switch (entityInfo.OperationType)
{ if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreationTime)))
case DataFilterType.InsertByObject: {
if (entityInfo.PropertyName == nameof(IEntity<object>.Id)) //为空或者为默认最小值
{ if (oldValue is null || DateTime.MinValue.Equals(oldValue))
EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue); {
} entityInfo.SetValue(DateTime.Now);
}
break; }
case DataFilterType.UpdateByObject:
if (entityInfo.PropertyName == nameof(IEntity<object>.Id)) if (entityInfo.PropertyName.Equals(nameof(IAuditedObject.CreatorId)))
{ {
//软删除,发布的是删除事件 if (CurrentUser.Id != null)
if (entityInfo.EntityValue is ISoftDelete softDelete) {
{ entityInfo.SetValue(CurrentUser.Id);
if (softDelete.IsDeleted) }
{ }
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
} //插入时需要租户id,先预留
} if (entityInfo.PropertyName.Equals(nameof(IMultiTenant.TenantId)))
else {
{ if (CurrentTenant is not null)
EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue); {
} entityInfo.SetValue(CurrentTenant.Id);
} }
}
break;
case DataFilterType.DeleteByObject: break;
if (entityInfo.PropertyName == nameof(IEntity<object>.Id)) }
{
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
} //领域事件
switch (entityInfo.OperationType)
break; {
} case DataFilterType.InsertByObject:
} if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
{
protected virtual void OnLogExecuting(string sql, SugarParameter[] pars) EntityChangeEventHelper.PublishEntityCreatedEvent(entityInfo.EntityValue);
{ }
if (Options.EnabledSqlLog)
{ break;
StringBuilder sb = new StringBuilder(); case DataFilterType.UpdateByObject:
sb.AppendLine(); if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
sb.AppendLine("==========NPin-SQL=========="); {
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars)); //软删除,发布的是删除事件
sb.AppendLine("============================"); if (entityInfo.EntityValue is ISoftDelete softDelete)
Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sb.ToString()); {
} if (softDelete.IsDeleted)
} {
EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
protected virtual void OnLogExecuted(string sql, SugarParameter[] pars) }
{ }
} else
{
/// <summary> EntityChangeEventHelper.PublishEntityUpdatedEvent(entityInfo.EntityValue);
/// 实体配置 }
/// 自动主键 }
/// 自动Ignore关联配置导航
/// 开启下划线 break;
/// </summary> case DataFilterType.DeleteByObject:
/// <param name="property"></param> if (entityInfo.PropertyName == nameof(IEntity<object>.Id))
/// <param name="column"></param> {
protected virtual void EntityService(PropertyInfo property, EntityColumnInfo column) EntityChangeEventHelper.PublishEntityDeletedEvent(entityInfo.EntityValue);
{ }
if (property.PropertyType == typeof(ExtraPropertyDictionary))
{ break;
column.IsIgnore = true; }
} }
if (property.Name == nameof(Entity<object>.Id)) protected virtual void OnLogExecuting(string sql, SugarParameter[] pars)
{ {
column.IsPrimarykey = true; if (Options.EnabledSqlLog)
} {
StringBuilder sb = new StringBuilder();
column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName); sb.AppendLine();
} sb.AppendLine("==========NPin-SQL==========");
sb.AppendLine(UtilMethods.GetSqlString(DbType.SqlServer, sql, pars));
/// <summary> sb.AppendLine("============================");
/// EntityName 配置 Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sb.ToString());
/// 开启下划线 }
/// </summary> }
/// <param name="type"></param>
/// <param name="entity"></param> protected virtual void OnLogExecuted(string sql, SugarParameter[] pars)
protected virtual void EntityNameService(Type type, EntityInfo entity) {
{ if (Options.EnabledSqlLog)
// 开启下划线 {
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName); var sqllog = $"=========NPin-SQL耗时{SqlSugarClient.Ado.SqlExecutionTime.TotalMilliseconds}毫秒=====";
} Logger.CreateLogger<SqlSugarDbContext>().LogDebug(sqllog);
}
public void Backup() }
{
string directoryName = "database_backup"; /// <summary>
string fileName = $"{SqlSugarClient.Ado.Connection.Database}_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"); /// 实体配置
if (!Directory.Exists(directoryName)) /// 自动主键
{ /// 自动Ignore关联配置导航
Directory.CreateDirectory(directoryName); /// 开启下划线
} /// </summary>
/// <param name="property"></param>
switch (Options.DbType) /// <param name="column"></param>
{ protected virtual void EntityService(PropertyInfo property, EntityColumnInfo column)
case DbType.MySql: {
// mysql 只支持.net core if (property.PropertyType == typeof(ExtraPropertyDictionary))
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, {
$"{Path.Combine(directoryName, fileName)}.sql"); column.IsIgnore = true;
break; }
case DbType.Sqlite:
// sqlite 只支持.net core if (property.Name == nameof(Entity<object>.Id))
SqlSugarClient.DbMaintenance.BackupDataBase(null, $"{fileName}.db"); {
break; column.IsPrimarykey = true;
case DbType.SqlServer: }
// 第一个参数库名
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database, column.DbColumnName = UtilMethods.ToUnderLine(column.DbColumnName);
$"{Path.Combine(directoryName, fileName)}.bak"); }
break;
default: /// <summary>
throw new NotImplementedException("其他数据库备份未实现"); /// EntityName 配置
} /// 开启下划线
} /// </summary>
/// <param name="type"></param>
/// <param name="entity"></param>
protected virtual void EntityNameService(Type type, EntityInfo entity)
{
// 开启下划线
entity.DbTableName = UtilMethods.ToUnderLine(entity.DbTableName);
}
public void Backup()
{
string directoryName = "database_backup";
string fileName = $"{SqlSugarClient.Ado.Connection.Database}_" + DateTime.Now.ToString("yyyyMMdd_HHmmss");
if (!Directory.Exists(directoryName))
{
Directory.CreateDirectory(directoryName);
}
switch (Options.DbType)
{
case DbType.MySql:
// mysql 只支持.net core
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
$"{Path.Combine(directoryName, fileName)}.sql");
break;
case DbType.Sqlite:
// sqlite 只支持.net core
SqlSugarClient.DbMaintenance.BackupDataBase(null, $"{fileName}.db");
break;
case DbType.SqlServer:
// 第一个参数库名
SqlSugarClient.DbMaintenance.BackupDataBase(SqlSugarClient.Ado.Connection.Database,
$"{Path.Combine(directoryName, fileName)}.bak");
break;
default:
throw new NotImplementedException("其他数据库备份未实现");
}
}
} }

@ -1,135 +1,140 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Abstractions; using Microsoft.Extensions.Logging.Abstractions;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Threading; using Volo.Abp.Threading;
using Volo.Abp.Uow; using Volo.Abp.Uow;
namespace NPin.Framework.SqlSugarCore.Uow; namespace NPin.Framework.SqlSugarCore.Uow;
public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextProvider<TDbContext> public class UnitOfWorkSqlSugarDbContextProvider<TDbContext> : ISugarDbContextProvider<TDbContext>
where TDbContext : ISqlSugarDbContext where TDbContext : ISqlSugarDbContext
{ {
private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator; private readonly ISqlSugarDbConnectionCreator _dbConnectionCreator;
private ILogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>> Logger { get; set; } private ILogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>> Logger { get; set; }
private IServiceProvider ServiceProvider { get; set; } public IServiceProvider ServiceProvider { get; set; }
private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance; private static AsyncLocalDbContextAccessor ContextInstance => AsyncLocalDbContextAccessor.Instance;
protected readonly IUnitOfWorkManager UnitOfWorkManager; protected readonly IUnitOfWorkManager UnitOfWorkManager;
protected readonly IConnectionStringResolver ConnectionStringResolver; protected readonly IConnectionStringResolver ConnectionStringResolver;
protected readonly ICancellationTokenProvider CancellationTokenProvider; protected readonly ICancellationTokenProvider CancellationTokenProvider;
protected readonly ICurrentTenant CurrentTenant; protected readonly ICurrentTenant CurrentTenant;
public UnitOfWorkSqlSugarDbContextProvider( public UnitOfWorkSqlSugarDbContextProvider(
IUnitOfWorkManager unitOfWorkManager, IUnitOfWorkManager unitOfWorkManager,
IConnectionStringResolver connectionStringResolver, IConnectionStringResolver connectionStringResolver,
ICancellationTokenProvider cancellationTokenProvider, ICancellationTokenProvider cancellationTokenProvider,
ICurrentTenant currentTenant, ICurrentTenant currentTenant,
ISqlSugarDbConnectionCreator dbConnectionCreator ISqlSugarDbConnectionCreator dbConnectionCreator
) )
{ {
UnitOfWorkManager = unitOfWorkManager; UnitOfWorkManager = unitOfWorkManager;
ConnectionStringResolver = connectionStringResolver; ConnectionStringResolver = connectionStringResolver;
CancellationTokenProvider = cancellationTokenProvider; CancellationTokenProvider = cancellationTokenProvider;
CurrentTenant = currentTenant; CurrentTenant = currentTenant;
Logger = NullLogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>>.Instance; Logger = NullLogger<UnitOfWorkSqlSugarDbContextProvider<TDbContext>>.Instance;
_dbConnectionCreator = dbConnectionCreator; _dbConnectionCreator = dbConnectionCreator;
} }
public virtual async Task<TDbContext> GetDbContextAsync() public virtual async Task<TDbContext> GetDbContextAsync()
{ {
var connectionStringName = ConnectionStrings.DefaultConnectionStringName; var connectionStringName = ConnectionStrings.DefaultConnectionStringName;
// 获取当前的连接字符串,未开启多租户时为空 // 获取当前的连接字符串,未开启多租户时为空
var connectionString = await ResolveConnectionStringAsync(connectionStringName); var connectionString = await ResolveConnectionStringAsync(connectionStringName);
var dbContextKey = $"{GetType().FullName}_{connectionString}"; var dbContextKey = $"{GetType().FullName}_{connectionString}";
var unitOfWork = UnitOfWorkManager.Current; var unitOfWork = UnitOfWorkManager.Current;
if (unitOfWork == null || !unitOfWork.Options.IsTransactional) if (unitOfWork == null || !unitOfWork.Options.IsTransactional)
{ {
// set if is null // set if is null
ContextInstance.Current ??= (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>(); if (ContextInstance.Current is null)
{
var dbContext = (TDbContext)ContextInstance.Current; ContextInstance.Current = (TDbContext)ServiceProvider.GetRequiredService<ISqlSugarDbContext>();
// 提高体验取消uow的强制性 }
// 若不启用uow创建新db不开启事务
return dbContext; var dbContext = (TDbContext)ContextInstance.Current;
} // 提高体验取消uow的强制性
// 若不启用uow创建新db不开启事务
// 尝试当前工作单元获取db return dbContext;
var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey); }
if (databaseApi == null)
{ // 尝试当前工作单元获取db
databaseApi = var databaseApi = unitOfWork.FindDatabaseApi(dbContextKey);
new SqlSugarDatabaseApi(CreateDbContextAsync(unitOfWork, connectionStringName, connectionString) if (databaseApi == null)
.Result); {
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi); // db根据连接字符串来创建
} databaseApi = new SqlSugarDatabaseApi(
CreateDbContextAsync(unitOfWork, connectionStringName, connectionString).Result
return (TDbContext)((SqlSugarDatabaseApi)databaseApi).DbContext; );
} // 创建的db加入到当前工作单元中
unitOfWork.AddDatabaseApi(dbContextKey, databaseApi);
/// <summary> }
/// 解析连接字符串
/// </summary> return (TDbContext)((SqlSugarDatabaseApi)databaseApi).DbContext;
/// <param name="connectionStringName"></param> }
/// <returns></returns>
protected virtual async Task<string> ResolveConnectionStringAsync(string connectionStringName) /// <summary>
{ /// 解析连接字符串
if (typeof(TDbContext).IsDefined(typeof(IgnoreMultiTenancyAttribute), false)) /// </summary>
{ /// <param name="connectionStringName"></param>
using (CurrentTenant.Change(null)) /// <returns></returns>
{ protected virtual async Task<string> ResolveConnectionStringAsync(string connectionStringName)
return await ConnectionStringResolver.ResolveAsync(connectionStringName); {
} if (typeof(TDbContext).IsDefined(typeof(IgnoreMultiTenancyAttribute), false))
} {
using (CurrentTenant.Change(null))
return await ConnectionStringResolver.ResolveAsync(connectionStringName); {
} return await ConnectionStringResolver.ResolveAsync(connectionStringName);
}
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName, }
string connectionString)
{ return await ConnectionStringResolver.ResolveAsync(connectionStringName);
var creationContext = new SqlSugarDbContextCreationContext(connectionStringName, connectionString); }
//将连接key进行传值
using (SqlSugarDbContextCreationContext.Use(creationContext)) protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork, string connectionStringName,
{ string connectionString)
var dbContext = await CreateDbContextAsync(unitOfWork); {
return dbContext; var creationContext = new SqlSugarDbContextCreationContext(connectionStringName, connectionString);
} //将连接key进行传值
} using (SqlSugarDbContextCreationContext.Use(creationContext))
{
protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork) var dbContext = await CreateDbContextAsync(unitOfWork);
{ return dbContext;
return unitOfWork.Options.IsTransactional }
? await CreateDbContextWithTransactionAsync(unitOfWork) }
: unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
} protected virtual async Task<TDbContext> CreateDbContextAsync(IUnitOfWork unitOfWork)
{
protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork) return unitOfWork.Options.IsTransactional
{ ? await CreateDbContextWithTransactionAsync(unitOfWork)
//事务key : unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
var transactionApiKey = $"SqlSugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}"; }
//尝试查找事务 protected virtual async Task<TDbContext> CreateDbContextWithTransactionAsync(IUnitOfWork unitOfWork)
var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi; {
//事务key
//该db还没有进行开启事务 var transactionApiKey = $"SqlSugarCore_{SqlSugarDbContextCreationContext.Current.ConnectionString}";
if (activeTransaction == null)
{ //尝试查找事务
//获取到db添加事务即可 var activeTransaction = unitOfWork.FindTransactionApi(transactionApiKey) as SqlSugarTransactionApi;
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
var transaction = new SqlSugarTransactionApi( //该db还没有进行开启事务
dbContext if (activeTransaction == null)
); {
unitOfWork.AddTransactionApi(transactionApiKey, transaction); //获取到db添加事务即可
var dbContext = unitOfWork.ServiceProvider.GetRequiredService<TDbContext>();
// await dbContext.SqlSugarClient.Ado.BeginTranAsync(); var transaction = new SqlSugarTransactionApi(
return dbContext; dbContext
} );
unitOfWork.AddTransactionApi(transactionApiKey, transaction);
return (TDbContext)activeTransaction.GetDbContext();
} await dbContext.SqlSugarClient.Ado.BeginTranAsync();
return dbContext;
}
return (TDbContext)activeTransaction.GetDbContext();
}
} }

@ -1,88 +1,89 @@
using NPin.Framework.AuditLogging.Domain.Entities; using Microsoft.Extensions.Options;
using Volo.Abp.AspNetCore.ExceptionHandling; using NPin.Framework.AuditLogging.Domain.Entities;
using Volo.Abp.Auditing; using Volo.Abp.AspNetCore.ExceptionHandling;
using Volo.Abp.Data; using Volo.Abp.Auditing;
using Volo.Abp.DependencyInjection; using Volo.Abp.Data;
using Volo.Abp.Guids; using Volo.Abp.DependencyInjection;
using Volo.Abp.Json; using Volo.Abp.Guids;
using Volo.Abp.Json;
namespace NPin.Framework.AuditLogging.Domain;
namespace NPin.Framework.AuditLogging.Domain;
public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter, ITransientDependency
{ public class AuditLogInfoToAuditLogConverter : IAuditLogInfoToAuditLogConverter, ITransientDependency
protected IGuidGenerator GuidGenerator { get; } {
protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; } protected IGuidGenerator GuidGenerator { get; }
protected IJsonSerializer JsonSerializer { get; } protected IExceptionToErrorInfoConverter ExceptionToErrorInfoConverter { get; }
protected AbpExceptionHandlingOptions ExceptionHandlingOptions { get; } protected IJsonSerializer JsonSerializer { get; }
protected AbpExceptionHandlingOptions ExceptionHandlingOptions { get; }
public AuditLogInfoToAuditLogConverter(IGuidGenerator guidGenerator,
IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, IJsonSerializer jsonSerializer, public AuditLogInfoToAuditLogConverter(IGuidGenerator guidGenerator,
AbpExceptionHandlingOptions exceptionHandlingOptions) IExceptionToErrorInfoConverter exceptionToErrorInfoConverter, IJsonSerializer jsonSerializer,
{ IOptions<AbpExceptionHandlingOptions> exceptionHandlingOptions)
GuidGenerator = guidGenerator; {
ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter; GuidGenerator = guidGenerator;
JsonSerializer = jsonSerializer; ExceptionToErrorInfoConverter = exceptionToErrorInfoConverter;
ExceptionHandlingOptions = exceptionHandlingOptions; JsonSerializer = jsonSerializer;
} ExceptionHandlingOptions = exceptionHandlingOptions.Value;
}
public virtual Task<AuditLogAggregateRoot> ConvertAsync(AuditLogInfo auditLogInfo)
{ public virtual Task<AuditLogAggregateRoot> ConvertAsync(AuditLogInfo auditLogInfo)
var auditLogId = GuidGenerator.Create(); {
var auditLogId = GuidGenerator.Create();
var extraProperties = new ExtraPropertyDictionary();
foreach (var pair in auditLogInfo.ExtraProperties) var extraProperties = new ExtraPropertyDictionary();
{ foreach (var pair in auditLogInfo.ExtraProperties)
extraProperties.Add(pair.Key, pair.Value); {
} extraProperties.Add(pair.Key, pair.Value);
}
var entityChanges = auditLogInfo.EntityChanges?
.Select(info => new EntityChangeEntity(GuidGenerator, auditLogId, info, auditLogInfo.TenantId)) var entityChanges = auditLogInfo.EntityChanges?
.ToList() ?? []; .Select(info => new EntityChangeEntity(GuidGenerator, auditLogId, info, auditLogInfo.TenantId))
var actions = auditLogInfo.Actions? .ToList() ?? [];
.Select(info => new AuditLogActionEntity(GuidGenerator.Create(), auditLogId, info, auditLogInfo.TenantId)) var actions = auditLogInfo.Actions?
.ToList() ?? []; .Select(info => new AuditLogActionEntity(GuidGenerator.Create(), auditLogId, info, auditLogInfo.TenantId))
var remoteServiceErrorInfos = auditLogInfo.Exceptions? .ToList() ?? [];
.Select(ex => ExceptionToErrorInfoConverter.Convert(ex, options => var remoteServiceErrorInfos = auditLogInfo.Exceptions?
{ .Select(ex => ExceptionToErrorInfoConverter.Convert(ex, options =>
options.SendExceptionsDetailsToClients = ExceptionHandlingOptions.SendExceptionsDetailsToClients; {
options.SendStackTraceToClients = ExceptionHandlingOptions.SendStackTraceToClients; options.SendExceptionsDetailsToClients = ExceptionHandlingOptions.SendExceptionsDetailsToClients;
})) ?? []; options.SendStackTraceToClients = ExceptionHandlingOptions.SendStackTraceToClients;
})) ?? [];
var exceptions = remoteServiceErrorInfos.Any()
? JsonSerializer.Serialize(remoteServiceErrorInfos, indented: true) var exceptions = remoteServiceErrorInfos.Any()
: null; ? JsonSerializer.Serialize(remoteServiceErrorInfos, indented: true)
: null;
var comments = auditLogInfo.Comments?
.JoinAsString(Environment.NewLine); var comments = auditLogInfo.Comments?
.JoinAsString(Environment.NewLine);
var auditLog = new AuditLogAggregateRoot(
auditLogId, var auditLog = new AuditLogAggregateRoot(
auditLogInfo.ApplicationName, auditLogId,
auditLogInfo.UserId, auditLogInfo.ApplicationName,
auditLogInfo.UserName, auditLogInfo.UserId,
auditLogInfo.TenantName, auditLogInfo.UserName,
auditLogInfo.ImpersonatorUserId, auditLogInfo.TenantName,
auditLogInfo.ImpersonatorUserName, auditLogInfo.ImpersonatorUserId,
auditLogInfo.ImpersonatorTenantId, auditLogInfo.ImpersonatorUserName,
auditLogInfo.ImpersonatorTenantName, auditLogInfo.ImpersonatorTenantId,
auditLogInfo.ExecutionTime, auditLogInfo.ImpersonatorTenantName,
auditLogInfo.ExecutionDuration, auditLogInfo.ExecutionTime,
auditLogInfo.ClientIpAddress, auditLogInfo.ExecutionDuration,
auditLogInfo.ClientName, auditLogInfo.ClientIpAddress,
auditLogInfo.ClientId, auditLogInfo.ClientName,
auditLogInfo.CorrelationId, auditLogInfo.ClientId,
auditLogInfo.BrowserInfo, auditLogInfo.CorrelationId,
auditLogInfo.HttpMethod, auditLogInfo.BrowserInfo,
auditLogInfo.Url, auditLogInfo.HttpMethod,
exceptions, auditLogInfo.Url,
comments, exceptions,
auditLogInfo.HttpStatusCode, comments,
auditLogInfo.TenantId, auditLogInfo.HttpStatusCode,
entityChanges, auditLogInfo.TenantId,
actions, entityChanges,
extraProperties actions,
); extraProperties
);
return Task.FromResult(auditLog);
} return Task.FromResult(auditLog);
}
} }

@ -1,60 +1,61 @@
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Newtonsoft.Json; using Microsoft.Extensions.Options;
using Newtonsoft.Json.Converters; using Newtonsoft.Json;
using NPin.Framework.AuditLogging.Domain.Repositories; using Newtonsoft.Json.Converters;
using Volo.Abp.Auditing; using NPin.Framework.AuditLogging.Domain.Repositories;
using Volo.Abp.DependencyInjection; using Volo.Abp.Auditing;
using Volo.Abp.Uow; using Volo.Abp.DependencyInjection;
using Volo.Abp.Uow;
namespace NPin.Framework.AuditLogging.Domain;
namespace NPin.Framework.AuditLogging.Domain;
public class AuditingStore : IAuditingStore, ITransientDependency
{ public class AuditingStore : IAuditingStore, ITransientDependency
public ILogger<AuditingStore> Logger { get; set; } {
protected IAuditLogRepository AuditLogRepository { get; } public ILogger<AuditingStore> Logger { get; set; }
protected IUnitOfWorkManager UnitOfWorkManager { get; } protected IAuditLogRepository AuditLogRepository { get; }
protected AbpAuditingOptions Options { get; } protected IUnitOfWorkManager UnitOfWorkManager { get; }
protected IAuditLogInfoToAuditLogConverter Converter { get; } protected AbpAuditingOptions Options { get; }
protected IAuditLogInfoToAuditLogConverter Converter { get; }
public AuditingStore(ILogger<AuditingStore> logger, IAuditLogRepository auditLogRepository,
IUnitOfWorkManager unitOfWorkManager, AbpAuditingOptions options, IAuditLogInfoToAuditLogConverter converter) public AuditingStore(ILogger<AuditingStore> logger, IAuditLogRepository auditLogRepository,
{ IUnitOfWorkManager unitOfWorkManager, IOptions<AbpAuditingOptions> options, IAuditLogInfoToAuditLogConverter converter)
Logger = logger; {
AuditLogRepository = auditLogRepository; Logger = logger;
UnitOfWorkManager = unitOfWorkManager; AuditLogRepository = auditLogRepository;
Options = options; UnitOfWorkManager = unitOfWorkManager;
Converter = converter; Options = options.Value;
} Converter = converter;
}
public virtual async Task SaveAsync(AuditLogInfo auditInfo)
{ public virtual async Task SaveAsync(AuditLogInfo auditInfo)
if (!Options.HideErrors) {
{ if (!Options.HideErrors)
await SaveLogAsync(auditInfo); {
return; await SaveLogAsync(auditInfo);
} return;
}
try
{ try
await SaveLogAsync(auditInfo); {
} await SaveLogAsync(auditInfo);
catch (Exception ex) }
{ catch (Exception ex)
Logger.LogWarning($"无法保存审计日志: {Environment.NewLine}{auditInfo}"); {
Logger.LogException(ex, LogLevel.Error); Logger.LogWarning($"无法保存审计日志: {Environment.NewLine}{auditInfo}");
} Logger.LogException(ex, LogLevel.Error);
} }
}
protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
{ protected virtual async Task SaveLogAsync(AuditLogInfo auditInfo)
var timeConverter = new IsoDateTimeConverter {
{ var timeConverter = new IsoDateTimeConverter
DateTimeFormat = "yyyy-MM-dd HH:mm:ss" {
}; DateTimeFormat = "yyyy-MM-dd HH:mm:ss"
Logger.LogDebug($"NPin-请求日志:{JsonConvert.SerializeObject(auditInfo, Formatting.Indented, timeConverter)}"); };
Logger.LogDebug($"NPin-请求日志:{JsonConvert.SerializeObject(auditInfo, Formatting.Indented, timeConverter)}");
using var uow = UnitOfWorkManager.Begin(true);
await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo)); using var uow = UnitOfWorkManager.Begin(true);
await uow.CompleteAsync(); await AuditLogRepository.InsertAsync(await Converter.ConvertAsync(auditInfo));
} await uow.CompleteAsync();
}
} }

@ -1,51 +1,51 @@
using NPin.Framework.AuditLogging.Domain.Shared.Consts; using NPin.Framework.AuditLogging.Domain.Shared.Consts;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities; namespace NPin.Framework.AuditLogging.Domain.Entities;
[DisableAuditing] [DisableAuditing]
[SugarTable("NPinAuditLogAction", "审计日志操作表")] [SugarTable("SysAuditLogAction", "审计日志操作表")]
[SugarIndex($"index_{nameof(AuditLogId)}", nameof(AuditLogId), OrderByType.Asc)] [SugarIndex($"index_{nameof(AuditLogId)}", nameof(AuditLogId), OrderByType.Asc)]
[SugarIndex($"index_{nameof(TenantId)}_{nameof(ExecutionTime)}", nameof(TenantId), OrderByType.Asc, nameof(ServiceName), [SugarIndex($"index_{nameof(TenantId)}_{nameof(ExecutionTime)}", nameof(TenantId), OrderByType.Asc, nameof(ServiceName),
OrderByType.Asc, nameof(MethodName), OrderByType.Asc, nameof(ExecutionTime), OrderByType.Asc)] OrderByType.Asc, nameof(MethodName), OrderByType.Asc, nameof(ExecutionTime), OrderByType.Asc)]
public class AuditLogActionEntity : Entity<Guid>, IMultiTenant public class AuditLogActionEntity : Entity<Guid>, IMultiTenant
{ {
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public virtual Guid AuditLogId { get; protected set; } public virtual Guid AuditLogId { get; protected set; }
public virtual string? ServiceName { get; protected set; } public virtual string? ServiceName { get; protected set; }
public virtual string? MethodName { get; protected set; } public virtual string? MethodName { get; protected set; }
public virtual string? Parameters { get; protected set; } public virtual string? Parameters { get; protected set; }
public virtual DateTime? ExecutionTime { get; protected set; } public virtual DateTime? ExecutionTime { get; protected set; }
public virtual int? ExecutionDuration { get; protected set; } public virtual int? ExecutionDuration { get; protected set; }
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
public AuditLogActionEntity() public AuditLogActionEntity()
{ {
} }
public AuditLogActionEntity(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo, Guid? tenantId = null) public AuditLogActionEntity(Guid id, Guid auditLogId, AuditLogActionInfo actionInfo, Guid? tenantId = null)
{ {
Id = id; Id = id;
TenantId = tenantId; TenantId = tenantId;
AuditLogId = auditLogId; AuditLogId = auditLogId;
ExecutionTime = actionInfo.ExecutionTime; ExecutionTime = actionInfo.ExecutionTime;
ExecutionDuration = actionInfo.ExecutionDuration; ExecutionDuration = actionInfo.ExecutionDuration;
ServiceName = actionInfo.ServiceName.TruncateFromBeginning(AuditLogActionConsts.MaxServiceNameLength); ServiceName = actionInfo.ServiceName.TruncateFromBeginning(AuditLogActionConsts.MaxServiceNameLength);
MethodName = actionInfo.MethodName.TruncateFromBeginning(AuditLogActionConsts.MaxMethodNameLength); MethodName = actionInfo.MethodName.TruncateFromBeginning(AuditLogActionConsts.MaxMethodNameLength);
Parameters = actionInfo.Parameters.Length > AuditLogActionConsts.MaxParametersLength Parameters = actionInfo.Parameters.Length > AuditLogActionConsts.MaxParametersLength
? "" ? ""
: actionInfo.Parameters; : actionInfo.Parameters;
} }
} }

@ -1,111 +1,111 @@
using NPin.Framework.AuditLogging.Domain.Shared.Consts; using NPin.Framework.AuditLogging.Domain.Shared.Consts;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities; namespace NPin.Framework.AuditLogging.Domain.Entities;
[DisableAuditing] [DisableAuditing]
[SugarTable("NPinAuditLog", "审计日志")] [SugarTable("SysAuditLog", "审计日志")]
[SugarIndex($"index_{nameof(ExecutionTime)}", nameof(TenantId), OrderByType.Asc, nameof(ExecutionTime), [SugarIndex($"index_{nameof(ExecutionTime)}", nameof(TenantId), OrderByType.Asc, nameof(ExecutionTime),
OrderByType.Asc)] OrderByType.Asc)]
[SugarIndex($"index_{nameof(ExecutionTime)}_{nameof(UserId)}", nameof(TenantId), OrderByType.Asc, nameof(UserId), [SugarIndex($"index_{nameof(ExecutionTime)}_{nameof(UserId)}", nameof(TenantId), OrderByType.Asc, nameof(UserId),
OrderByType.Asc, nameof(ExecutionTime), OrderByType.Asc)] OrderByType.Asc, nameof(ExecutionTime), OrderByType.Asc)]
public class AuditLogAggregateRoot : AggregateRoot<Guid>, IMultiTenant public class AuditLogAggregateRoot : AggregateRoot<Guid>, IMultiTenant
{ {
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
public virtual string? ApplicationName { get; set; } public virtual string? ApplicationName { get; set; }
public virtual Guid? UserId { get; protected set; } public virtual Guid? UserId { get; protected set; }
public virtual string? UserName { get; protected set; } public virtual string? UserName { get; protected set; }
public virtual string? TenantName { get; protected set; } public virtual string? TenantName { get; protected set; }
public virtual Guid? ImpersonatorUserId { get; protected set; } public virtual Guid? ImpersonatorUserId { get; protected set; }
public virtual string? ImpersonatorUserName { get; protected set; } public virtual string? ImpersonatorUserName { get; protected set; }
public virtual Guid? ImpersonatorTenantId { get; protected set; } public virtual Guid? ImpersonatorTenantId { get; protected set; }
public virtual string? ImpersonatorTenantName { get; protected set; } public virtual string? ImpersonatorTenantName { get; protected set; }
public virtual DateTime? ExecutionTime { get; protected set; } public virtual DateTime? ExecutionTime { get; protected set; }
public virtual int? ExecutionDuration { get; protected set; } public virtual int? ExecutionDuration { get; protected set; }
public virtual string? ClientIpAddress { get; protected set; } public virtual string? ClientIpAddress { get; protected set; }
public virtual string? ClientName { get; protected set; } public virtual string? ClientName { get; protected set; }
public virtual string? ClientId { get; set; } public virtual string? ClientId { get; set; }
public virtual string? CorrelationId { get; set; } public virtual string? CorrelationId { get; set; }
public virtual string? BrowserInfo { get; protected set; } public virtual string? BrowserInfo { get; protected set; }
public virtual string? HttpMethod { get; protected set; } public virtual string? HttpMethod { get; protected set; }
public virtual string? Url { get; protected set; } public virtual string? Url { get; protected set; }
public virtual string? Exceptions { get; protected set; } public virtual string? Exceptions { get; protected set; }
public virtual string? Comments { get; protected set; } public virtual string? Comments { get; protected set; }
public virtual int? HttpStatusCode { get; set; } public virtual int? HttpStatusCode { get; set; }
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
// 导航属性 // 导航属性
[Navigate(NavigateType.OneToMany, nameof(EntityChangeEntity.AuditLogId))] [Navigate(NavigateType.OneToMany, nameof(EntityChangeEntity.AuditLogId))]
public virtual List<EntityChangeEntity> EntityChanges { get; protected set; } public virtual List<EntityChangeEntity> EntityChanges { get; protected set; }
// 导航属性 // 导航属性
[Navigate(NavigateType.OneToMany, nameof(AuditLogActionEntity.AuditLogId))] [Navigate(NavigateType.OneToMany, nameof(AuditLogActionEntity.AuditLogId))]
public virtual List<AuditLogActionEntity> Actions { get; protected set; } public virtual List<AuditLogActionEntity> Actions { get; protected set; }
[SugarColumn(IsIgnore = true)] public override ExtraPropertyDictionary ExtraProperties { get; protected set; } [SugarColumn(IsIgnore = true)] public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
public AuditLogAggregateRoot() public AuditLogAggregateRoot()
{ {
} }
public AuditLogAggregateRoot(Guid id, string? applicationName, Guid? userId, string? userName, string? tenantName, public AuditLogAggregateRoot(Guid id, string? applicationName, Guid? userId, string? userName, string? tenantName,
Guid? impersonatorUserId, string? impersonatorUserName, Guid? impersonatorTenantId, Guid? impersonatorUserId, string? impersonatorUserName, Guid? impersonatorTenantId,
string? impersonatorTenantName, DateTime? executionTime, int? executionDuration, string? clientIpAddress, string? impersonatorTenantName, DateTime? executionTime, int? executionDuration, string? clientIpAddress,
string? clientName, string? clientId, string? correlationId, string? browserInfo, string? httpMethod, string? clientName, string? clientId, string? correlationId, string? browserInfo, string? httpMethod,
string? url, string? exceptions, string? comments, int? httpStatusCode, Guid? tenantId, string? url, string? exceptions, string? comments, int? httpStatusCode, Guid? tenantId,
List<EntityChangeEntity> entityChanges, List<AuditLogActionEntity> actions, List<EntityChangeEntity> entityChanges, List<AuditLogActionEntity> actions,
ExtraPropertyDictionary extraProperties) : base(id) ExtraPropertyDictionary extraProperties) : base(id)
{ {
ApplicationName = applicationName.Truncate(AuditLogConsts.MaxApplicationNameLength); ApplicationName = applicationName.Truncate(AuditLogConsts.MaxApplicationNameLength);
UserId = userId; UserId = userId;
UserName = userName.Truncate(AuditLogConsts.MaxUserNameLength); UserName = userName.Truncate(AuditLogConsts.MaxUserNameLength);
TenantName = tenantName.Truncate(AuditLogConsts.MaxTenantNameLength); TenantName = tenantName.Truncate(AuditLogConsts.MaxTenantNameLength);
ImpersonatorUserId = impersonatorUserId; ImpersonatorUserId = impersonatorUserId;
ImpersonatorUserName = impersonatorUserName.Truncate(AuditLogConsts.MaxUserNameLength); ImpersonatorUserName = impersonatorUserName.Truncate(AuditLogConsts.MaxUserNameLength);
ImpersonatorTenantId = impersonatorTenantId; ImpersonatorTenantId = impersonatorTenantId;
ImpersonatorTenantName = impersonatorTenantName.Truncate(AuditLogConsts.MaxTenantNameLength); ImpersonatorTenantName = impersonatorTenantName.Truncate(AuditLogConsts.MaxTenantNameLength);
ExecutionTime = executionTime; ExecutionTime = executionTime;
ExecutionDuration = executionDuration; ExecutionDuration = executionDuration;
ClientIpAddress = clientIpAddress.Truncate(AuditLogConsts.MaxClientIpAddressLength); ClientIpAddress = clientIpAddress.Truncate(AuditLogConsts.MaxClientIpAddressLength);
ClientName = clientName.Truncate(AuditLogConsts.MaxClientNameLength); ClientName = clientName.Truncate(AuditLogConsts.MaxClientNameLength);
ClientId = clientId.Truncate(AuditLogConsts.MaxClientIdLength); ClientId = clientId.Truncate(AuditLogConsts.MaxClientIdLength);
CorrelationId = correlationId.Truncate(AuditLogConsts.MaxCorrelationIdLength); CorrelationId = correlationId.Truncate(AuditLogConsts.MaxCorrelationIdLength);
BrowserInfo = browserInfo.Truncate(AuditLogConsts.MaxBrowserInfoLength); BrowserInfo = browserInfo.Truncate(AuditLogConsts.MaxBrowserInfoLength);
HttpMethod = httpMethod.Truncate(AuditLogConsts.MaxHttpMethodLength); HttpMethod = httpMethod.Truncate(AuditLogConsts.MaxHttpMethodLength);
Url = url.Truncate(AuditLogConsts.MaxUrlLength); Url = url.Truncate(AuditLogConsts.MaxUrlLength);
Exceptions = exceptions; Exceptions = exceptions;
Comments = comments.Truncate(AuditLogConsts.MaxCommentsLength); Comments = comments.Truncate(AuditLogConsts.MaxCommentsLength);
HttpStatusCode = httpStatusCode; HttpStatusCode = httpStatusCode;
TenantId = tenantId; TenantId = tenantId;
EntityChanges = entityChanges; EntityChanges = entityChanges;
Actions = actions; Actions = actions;
ExtraProperties = extraProperties; ExtraProperties = extraProperties;
} }
} }

@ -1,63 +1,63 @@
using NPin.Framework.AuditLogging.Domain.Shared.Consts; using NPin.Framework.AuditLogging.Domain.Shared.Consts;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities; namespace NPin.Framework.AuditLogging.Domain.Entities;
[SugarTable("NPinEntityChange")] [SugarTable("SysEntityChange")]
[SugarIndex($"index_{nameof(AuditLogId)}", nameof(AuditLogId), OrderByType.Asc)] [SugarIndex($"index_{nameof(AuditLogId)}", nameof(AuditLogId), OrderByType.Asc)]
[SugarIndex($"index_{nameof(TenantId)}_{nameof(EntityId)}", nameof(TenantId), OrderByType.Asc, [SugarIndex($"index_{nameof(TenantId)}_{nameof(EntityId)}", nameof(TenantId), OrderByType.Asc,
nameof(EntityTypeFullName), OrderByType.Asc, nameof(EntityId), OrderByType.Asc)] nameof(EntityTypeFullName), OrderByType.Asc, nameof(EntityId), OrderByType.Asc)]
public class EntityChangeEntity : Entity<Guid>, IMultiTenant public class EntityChangeEntity : Entity<Guid>, IMultiTenant
{ {
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
public virtual Guid AuditLogId { get; protected set; } public virtual Guid AuditLogId { get; protected set; }
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public virtual DateTime? ChangeTime { get; protected set; } public virtual DateTime? ChangeTime { get; protected set; }
public virtual EntityChangeType? ChangeType { get; protected set; } public virtual EntityChangeType? ChangeType { get; protected set; }
public virtual Guid? EntityTenantId { get; protected set; } public virtual Guid? EntityTenantId { get; protected set; }
public virtual string? EntityId { get; protected set; } public virtual string? EntityId { get; protected set; }
public virtual string? EntityTypeFullName { get; protected set; } public virtual string? EntityTypeFullName { get; protected set; }
// 关联 // 关联
[Navigate(NavigateType.OneToMany, nameof(EntityPropertyChangeEntity.EntityChangeId))] [Navigate(NavigateType.OneToMany, nameof(EntityPropertyChangeEntity.EntityChangeId))]
public virtual List<EntityPropertyChangeEntity> PropertyChanges { get; protected set; } public virtual List<EntityPropertyChangeEntity> PropertyChanges { get; protected set; }
public EntityChangeEntity() public EntityChangeEntity()
{ {
} }
public EntityChangeEntity( public EntityChangeEntity(
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
Guid auditLogId, Guid auditLogId,
EntityChangeInfo entityChangeInfo, EntityChangeInfo entityChangeInfo,
Guid? tenantId = null) Guid? tenantId = null)
{ {
Id = guidGenerator.Create(); Id = guidGenerator.Create();
AuditLogId = auditLogId; AuditLogId = auditLogId;
TenantId = tenantId; TenantId = tenantId;
ChangeTime = entityChangeInfo.ChangeTime; ChangeTime = entityChangeInfo.ChangeTime;
ChangeType = entityChangeInfo.ChangeType; ChangeType = entityChangeInfo.ChangeType;
EntityTenantId = entityChangeInfo.EntityTenantId; EntityTenantId = entityChangeInfo.EntityTenantId;
EntityId = entityChangeInfo.EntityId.Truncate(EntityChangeConsts.MaxEntityTypeFullNameLength); EntityId = entityChangeInfo.EntityId.Truncate(EntityChangeConsts.MaxEntityTypeFullNameLength);
EntityTypeFullName = EntityTypeFullName =
entityChangeInfo.EntityTypeFullName.TruncateFromBeginning(EntityChangeConsts.MaxEntityTypeFullNameLength); entityChangeInfo.EntityTypeFullName.TruncateFromBeginning(EntityChangeConsts.MaxEntityTypeFullNameLength);
PropertyChanges = entityChangeInfo PropertyChanges = entityChangeInfo
.PropertyChanges? .PropertyChanges?
.Select(p => new EntityPropertyChangeEntity(guidGenerator, Id, p, tenantId)) .Select(p => new EntityPropertyChangeEntity(guidGenerator, Id, p, tenantId))
.ToList() .ToList()
?? new List<EntityPropertyChangeEntity>(); ?? new List<EntityPropertyChangeEntity>();
} }
} }

@ -1,50 +1,50 @@
using NPin.Framework.AuditLogging.Domain.Shared.Consts; using NPin.Framework.AuditLogging.Domain.Shared.Consts;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Volo.Abp.Guids; using Volo.Abp.Guids;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
namespace NPin.Framework.AuditLogging.Domain.Entities; namespace NPin.Framework.AuditLogging.Domain.Entities;
[SugarTable("NPinEntityPropertyChange")] [SugarTable("SysEntityPropertyChange")]
[SugarIndex($"index_{nameof(EntityChangeId)}", nameof(EntityChangeId), OrderByType.Asc)] [SugarIndex($"index_{nameof(EntityChangeId)}", nameof(EntityChangeId), OrderByType.Asc)]
public class EntityPropertyChangeEntity : Entity<Guid>, IMultiTenant public class EntityPropertyChangeEntity : Entity<Guid>, IMultiTenant
{ {
[SugarColumn(ColumnName = "Id", IsPrimaryKey = true)] [SugarColumn(ColumnName = "Id", IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
public virtual Guid? TenantId { get; protected set; } public virtual Guid? TenantId { get; protected set; }
public virtual Guid? EntityChangeId { get; protected set; } public virtual Guid? EntityChangeId { get; protected set; }
public virtual string? NewValue { get; protected set; } public virtual string? NewValue { get; protected set; }
public virtual string? OriginalValue { get; protected set; } public virtual string? OriginalValue { get; protected set; }
public virtual string? PropertyName { get; protected set; } public virtual string? PropertyName { get; protected set; }
public virtual string? PropertyTypeFullName { get; protected set; } public virtual string? PropertyTypeFullName { get; protected set; }
public EntityPropertyChangeEntity() public EntityPropertyChangeEntity()
{ {
} }
public EntityPropertyChangeEntity( public EntityPropertyChangeEntity(
IGuidGenerator guidGenerator, IGuidGenerator guidGenerator,
Guid entityChangeId, Guid entityChangeId,
EntityPropertyChangeInfo entityChangeInfo, EntityPropertyChangeInfo entityChangeInfo,
Guid? tenantId = null) Guid? tenantId = null)
{ {
Id = guidGenerator.Create(); Id = guidGenerator.Create();
TenantId = tenantId; TenantId = tenantId;
EntityChangeId = entityChangeId; EntityChangeId = entityChangeId;
NewValue = entityChangeInfo.NewValue.Truncate(EntityPropertyChangeConsts.MaxNewValueLength); NewValue = entityChangeInfo.NewValue.Truncate(EntityPropertyChangeConsts.MaxNewValueLength);
OriginalValue = entityChangeInfo.OriginalValue.Truncate(EntityPropertyChangeConsts.MaxOriginalValueLength); OriginalValue = entityChangeInfo.OriginalValue.Truncate(EntityPropertyChangeConsts.MaxOriginalValueLength);
PropertyName = PropertyName =
entityChangeInfo.PropertyName.TruncateFromBeginning(EntityPropertyChangeConsts.MaxPropertyNameLength); entityChangeInfo.PropertyName.TruncateFromBeginning(EntityPropertyChangeConsts.MaxPropertyNameLength);
PropertyTypeFullName = PropertyTypeFullName =
entityChangeInfo.PropertyTypeFullName.TruncateFromBeginning(EntityPropertyChangeConsts entityChangeInfo.PropertyTypeFullName.TruncateFromBeginning(EntityPropertyChangeConsts
.MaxPropertyTypeFullNameLength); .MaxPropertyTypeFullNameLength);
} }
} }

@ -1,38 +1,40 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using SqlSugar;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
using Check = Volo.Abp.Check;
namespace NPin.Framework.SettingManagement.Domain.Entities; namespace NPin.Framework.SettingManagement.Domain.Entities;
public class SettingEntity: Entity<Guid>, IAggregateRoot<Guid> [SugarTable("SysSetting", "系统配置表")]
public class SettingEntity : Entity<Guid>, IAggregateRoot<Guid>
{ {
[NotNull] [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
public virtual string Name { get; protected set; }
[NotNull] [SugarColumn(ColumnDescription = "配置名称")]
public virtual string Value { get; internal set; } public string Name { get; protected set; }
[CanBeNull] [SugarColumn(ColumnDescription = "配置值", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public virtual string ProviderName { get; protected set; } public string Value { get; internal set; }
[CanBeNull] [SugarColumn(ColumnDescription = "配置提供者")]
public virtual string ProviderKey { get; protected set; } public string? ProviderName { get; protected set; }
[SugarColumn(ColumnDescription = "配置提供者Key")]
public string? ProviderKey { get; protected set; }
public SettingEntity() public SettingEntity()
{ {
} }
public SettingEntity( public SettingEntity(
Guid id, string name,
[NotNull] string name, string value,
[NotNull] string value, string? providerName = null,
[CanBeNull] string providerName = null, string? providerKey = null)
[CanBeNull] string providerKey = null)
{ {
Check.NotNull(name, nameof(name)); Check.NotNull(name, nameof(name));
Check.NotNull(value, nameof(value)); Check.NotNull(value, nameof(value));
Id = id;
Name = name; Name = name;
Value = value; Value = value;
ProviderName = providerName; ProviderName = providerName;
@ -41,6 +43,7 @@ public class SettingEntity: Entity<Guid>, IAggregateRoot<Guid>
public override string ToString() public override string ToString()
{ {
return $"{base.ToString()}, Name = {Name}, Value = {Value}, ProviderName = {ProviderName}, ProviderKey = {ProviderKey}"; return
$"{base.ToString()}, Name = {Name}, Value = {Value}, ProviderName = {ProviderName}, ProviderKey = {ProviderKey}";
} }
} }

@ -10,5 +10,9 @@
<PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.Ddd.Domain" Version="$(AbpVersion)" />
<PackageReference Include="Volo.Abp.SettingManagement.Domain.Shared" Version="$(AbpVersion)" /> <PackageReference Include="Volo.Abp.SettingManagement.Domain.Shared" Version="$(AbpVersion)" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" />
</ItemGroup>
</Project> </Project>

@ -10,6 +10,8 @@ namespace NPin.Framework.SettingManagement.Domain;
public class SettingManager : ISettingManager, ISingletonDependency public class SettingManager : ISettingManager, ISingletonDependency
{ {
private readonly Lazy<List<ISettingManagementProvider>> _lazyProviders; private readonly Lazy<List<ISettingManagementProvider>> _lazyProviders;
protected readonly IServiceProvider ServiceProvider;
protected ISettingDefinitionManager SettingDefinitionManager { get; } protected ISettingDefinitionManager SettingDefinitionManager { get; }
protected ISettingEncryptionService SettingEncryptionService { get; } protected ISettingEncryptionService SettingEncryptionService { get; }
protected List<ISettingManagementProvider> Providers => _lazyProviders.Value; protected List<ISettingManagementProvider> Providers => _lazyProviders.Value;
@ -21,18 +23,21 @@ public class SettingManager : ISettingManager, ISingletonDependency
ISettingEncryptionService settingEncryptionService, ISettingEncryptionService settingEncryptionService,
IOptions<SettingManagementOptions> options) IOptions<SettingManagementOptions> options)
{ {
ServiceProvider = serviceProvider;
SettingDefinitionManager = settingDefinitionManager; SettingDefinitionManager = settingDefinitionManager;
SettingEncryptionService = settingEncryptionService; SettingEncryptionService = settingEncryptionService;
Options = options.Value; Options = options.Value;
// TODO use IServiceScopeFactory and create a scope ? _lazyProviders = new Lazy<List<ISettingManagementProvider>>(CreateSettingManagementProviders, true);
_lazyProviders = new Lazy<List<ISettingManagementProvider>>( }
() => Options
.Providers protected virtual List<ISettingManagementProvider> CreateSettingManagementProviders()
.Select(c => serviceProvider.GetRequiredService(c) as ISettingManagementProvider) {
.ToList(), using var scope = ServiceProvider.CreateScope();
true
); return Options.Providers
.Select(p => (scope.ServiceProvider.GetRequiredService(p) as ISettingManagementProvider)!)
.ToList();
} }
public virtual Task<string?> GetOrNullAsync(string name, string providerName, string? providerKey, public virtual Task<string?> GetOrNullAsync(string name, string providerName, string? providerKey,

@ -13,16 +13,13 @@ public class SettingManagementStore : ISettingManagementStore, ITransientDepende
protected IDistributedCache<SettingCacheItem> Cache { get; } protected IDistributedCache<SettingCacheItem> Cache { get; }
protected ISettingDefinitionManager SettingDefinitionManager { get; } protected ISettingDefinitionManager SettingDefinitionManager { get; }
protected ISettingRepository SettingRepository { get; } protected ISettingRepository SettingRepository { get; }
protected IGuidGenerator GuidGenerator { get; }
public SettingManagementStore(IDistributedCache<SettingCacheItem> cache, public SettingManagementStore(IDistributedCache<SettingCacheItem> cache,
ISettingDefinitionManager settingDefinitionManager, ISettingRepository settingRepository, ISettingDefinitionManager settingDefinitionManager, ISettingRepository settingRepository)
IGuidGenerator guidGenerator)
{ {
Cache = cache; Cache = cache;
SettingDefinitionManager = settingDefinitionManager; SettingDefinitionManager = settingDefinitionManager;
SettingRepository = settingRepository; SettingRepository = settingRepository;
GuidGenerator = guidGenerator;
} }
[UnitOfWork] [UnitOfWork]
@ -65,7 +62,7 @@ public class SettingManagementStore : ISettingManagementStore, ITransientDepende
var setting = await SettingRepository.FindAsync(name, providerName, providerKey); var setting = await SettingRepository.FindAsync(name, providerName, providerKey);
if (setting == null) if (setting == null)
{ {
setting = new SettingEntity(GuidGenerator.Create(), name, value, providerName, providerKey); setting = new SettingEntity(name, value, providerName, providerKey);
await SettingRepository.InsertAsync(setting); await SettingRepository.InsertAsync(setting);
} }
else else

@ -1,143 +1,152 @@
using System.Reflection; using System.Reflection;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.Ddd.Application; using NPin.Framework.Ddd.Application;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using NPin.Framework.TenantManagement.Application.Contracts; using NPin.Framework.TenantManagement.Application.Contracts;
using NPin.Framework.TenantManagement.Application.Contracts.Dtos; using NPin.Framework.TenantManagement.Application.Contracts.Dtos;
using NPin.Framework.TenantManagement.Domain; using NPin.Framework.TenantManagement.Domain;
using SqlSugar; using SqlSugar;
using Volo.Abp; using Volo.Abp;
using Volo.Abp.Application.Dtos; using Volo.Abp.Application.Dtos;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.Domain.Repositories; using Volo.Abp.Domain.Repositories;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
namespace NPin.Framework.TenantManagement.Application; namespace NPin.Framework.TenantManagement.Application;
public class TenantService : NPinCrudAppService<TenantAggregateRoot, TenantGetOutputDto, TenantGetListOutputDto, Guid, public class TenantService : NPinCrudAppService<TenantAggregateRoot, TenantGetOutputDto, TenantGetListOutputDto, Guid,
TenantGetListInput, TenantCreateInput, TenantUpdateInput>, ITenantService TenantGetListInput, TenantCreateInput, TenantUpdateInput>, ITenantService
{ {
private ISqlSugarRepository<TenantAggregateRoot, Guid> _repository; private ISqlSugarRepository<TenantAggregateRoot, Guid> _repository;
private IDataSeeder _dataSeeder; private IDataSeeder _dataSeeder;
public TenantService(IRepository<TenantAggregateRoot, Guid> repository, public TenantService(IRepository<TenantAggregateRoot, Guid> repository,
ISqlSugarRepository<TenantAggregateRoot, Guid> sqlSugarRepository, IDataSeeder dataSeeder) : base(repository) ISqlSugarRepository<TenantAggregateRoot, Guid> sqlSugarRepository, IDataSeeder dataSeeder) : base(repository)
{ {
_repository = sqlSugarRepository; _repository = sqlSugarRepository;
_dataSeeder = dataSeeder; _dataSeeder = dataSeeder;
} }
/// <summary> /// <summary>
/// 多查 /// 租户单查
/// </summary> /// </summary>
/// <param name="input"></param> /// <param name="id">唯一ID</param>
/// <returns></returns> /// <returns></returns>
public override async Task<PagedResultDto<TenantGetListOutputDto>> GetListAsync(TenantGetListInput input) public override Task<TenantGetOutputDto> GetAsync(Guid id)
{ {
RefAsync<int> total = 0; return base.GetAsync(id);
var entities = await _repository.DbQueryable }
.WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
.WhereIF(input.StartTime is not null && input.EndTime is not null, /// <summary>
x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime) /// 租户多查
.ToPageListAsync(input.SkipCount, input.MaxResultCount, total); /// </summary>
return new PagedResultDto<TenantGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities)); /// <param name="input"></param>
} /// <returns></returns>
public override async Task<PagedResultDto<TenantGetListOutputDto>> GetListAsync(TenantGetListInput input)
/// <summary> {
/// 租户选项列表(显示名称) RefAsync<int> total = 0;
/// </summary> var entities = await _repository.DbQueryable
/// <returns></returns> .WhereIF(!string.IsNullOrEmpty(input.Name), x => x.Name.Contains(input.Name!))
public async Task<List<TenantSelectOutputDto>> GetSelectAsync() .WhereIF(input.StartTime is not null && input.EndTime is not null,
{ x => x.CreationTime >= input.StartTime && x.CreationTime <= input.EndTime)
var entities = await _repository.DbQueryable.ToListAsync(); .ToPageListAsync(input.SkipCount, input.MaxResultCount, total);
return entities.Select(x => new TenantSelectOutputDto { Id = x.Id, Name = x.Name }) return new PagedResultDto<TenantGetListOutputDto>(total, await MapToGetListOutputDtosAsync(entities));
.ToList(); }
}
/// <summary>
/// <summary> /// 租户选项列表(显示名称)
/// 创建租户 /// </summary>
/// </summary> /// <returns></returns>
/// <param name="input"></param> public async Task<List<TenantSelectOutputDto>> GetSelectAsync()
/// <returns></returns> {
public override async Task<TenantGetOutputDto> CreateAsync(TenantCreateInput input) var entities = await _repository.DbQueryable.ToListAsync();
{ return entities.Select(x => new TenantSelectOutputDto { Id = x.Id, Name = x.Name })
// 检查是否存在 .ToList();
if (await _repository.IsAnyAsync(x => x.Name == input.Name)) }
{
throw new UserFriendlyException("创建失败,当前租户已存在"); /// <summary>
} /// 创建租户
/// </summary>
return await base.CreateAsync(input); /// <param name="input"></param>
} /// <returns></returns>
public override async Task<TenantGetOutputDto> CreateAsync(TenantCreateInput input)
/// <summary> {
/// 更新租户信息 // 检查是否存在
/// </summary> if (await _repository.IsAnyAsync(x => x.Name == input.Name))
/// <param name="id"></param> {
/// <param name="input"></param> throw new UserFriendlyException("创建失败,当前租户已存在");
/// <returns></returns> }
public override async Task<TenantGetOutputDto> UpdateAsync(Guid id, TenantUpdateInput input)
{ return await base.CreateAsync(input);
if (await _repository.IsAnyAsync(x => x.Name == input.Name && x.Id != id)) }
{
throw new UserFriendlyException("更新失败,更新后租户已存在"); /// <summary>
} /// 更新租户信息
/// </summary>
return await base.UpdateAsync(id, input); /// <param name="id"></param>
} /// <param name="input"></param>
/// <returns></returns>
// 只是为了可以在swagger上展示? public override async Task<TenantGetOutputDto> UpdateAsync(Guid id, TenantUpdateInput input)
/// <summary> {
/// 租户删除 if (await _repository.IsAnyAsync(x => x.Name == input.Name && x.Id != id))
/// </summary> {
/// <param name="ids"></param> throw new UserFriendlyException("更新失败,更新后租户已存在");
/// <returns></returns> }
public override Task DeleteAsync(IEnumerable<Guid> ids)
{ return await base.UpdateAsync(id, input);
return base.DeleteAsync(ids); }
}
/// <summary>
/// <summary> /// 租户删除
/// 初始化租户 /// </summary>
/// </summary> /// <param name="ids"></param>
/// <param name="id"></param> /// <returns></returns>
[HttpPost("tenant/init/{id}")] public override Task DeleteAsync(IEnumerable<Guid> ids)
public async Task InitAsync([FromRoute] Guid id) {
{ return base.DeleteAsync(ids);
using (CurrentTenant.Change(id)) }
{
// 初始化 租户数据库/表 结构 /// <summary>
await CodeFirst(LazyServiceProvider); /// 初始化租户
// 插入 种子数据 /// </summary>
await _dataSeeder.SeedAsync(id); /// <param name="id"></param>
} [HttpPost("tenant/init/{id}")]
} public async Task InitAsync([FromRoute] Guid id)
{
/// <summary> using (CurrentTenant.Change(id))
/// 数据库 / 表 初始化 {
/// </summary> // 初始化 租户数据库/表 结构
/// <param name="service"></param> await CodeFirst(LazyServiceProvider);
private async Task CodeFirst(IServiceProvider service) // 插入 种子数据
{ await _dataSeeder.SeedAsync(id);
var moduleContainer = service.GetRequiredService<IModuleContainer>(); }
var db = await _repository.GetDbContextAsync(); }
// 尝试创建数据库 /// <summary>
db.DbMaintenance.CreateDatabase(); /// 数据库 / 表 初始化
/// </summary>
List<Type> types = new List<Type>(); /// <param name="service"></param>
foreach (var module in moduleContainer.Modules) private async Task CodeFirst(IServiceProvider service)
{ {
types.AddRange(module.Assembly.GetTypes() var moduleContainer = service.GetRequiredService<IModuleContainer>();
.Where(x => x.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null) var db = await _repository.GetDbContextAsync();
.Where(x => x.GetCustomAttribute<SugarTable>() != null)
.Where(x => x.GetCustomAttribute<SplitTableAttribute>() is null)); // 尝试创建数据库
} db.DbMaintenance.CreateDatabase();
if (types.Count > 0) List<Type> types = new List<Type>();
{ foreach (var module in moduleContainer.Modules)
db.CopyNew().CodeFirst.InitTables(types.ToArray()); {
} types.AddRange(module.Assembly.GetTypes()
} .Where(x => x.GetCustomAttribute<IgnoreCodeFirstAttribute>() == null)
.Where(x => x.GetCustomAttribute<SugarTable>() != null)
.Where(x => x.GetCustomAttribute<SplitTableAttribute>() is null));
}
if (types.Count > 0)
{
db.CopyNew().CodeFirst.InitTables(types.ToArray());
}
}
} }

@ -1,50 +1,50 @@
using JetBrains.Annotations; using JetBrains.Annotations;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.Domain.Entities.Auditing; using Volo.Abp.Domain.Entities.Auditing;
using Volo.Abp.TenantManagement; using Volo.Abp.TenantManagement;
using Check = Volo.Abp.Check; using Check = Volo.Abp.Check;
namespace NPin.Framework.TenantManagement.Domain; namespace NPin.Framework.TenantManagement.Domain;
[SugarTable("NPinTenant")] [SugarTable("SysTenant", "租户表")]
[MasterTenant] [MasterTenant]
public class TenantAggregateRoot : FullAuditedAggregateRoot<Guid>, IHasEntityVersion public class TenantAggregateRoot : FullAuditedAggregateRoot<Guid>, IHasEntityVersion
{ {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
public virtual string Name { get; protected set; } public virtual string Name { get; protected set; }
public int EntityVersion { get; protected set; } public int EntityVersion { get; protected set; }
public string TenantConnectionString { get; protected set; } public string TenantConnectionString { get; protected set; }
public DbType DbType { get; protected set; } public DbType DbType { get; protected set; }
[SugarColumn(IsIgnore = true)] [SugarColumn(IsIgnore = true)]
public override ExtraPropertyDictionary ExtraProperties public override ExtraPropertyDictionary ExtraProperties
{ {
get => base.ExtraProperties; get => base.ExtraProperties;
protected set => base.ExtraProperties = value; protected set => base.ExtraProperties = value;
} }
public virtual void SetConnectionString(DbType dbType, string connectionString) public virtual void SetConnectionString(DbType dbType, string connectionString)
{ {
DbType = dbType; DbType = dbType;
TenantConnectionString = connectionString; TenantConnectionString = connectionString;
} }
protected internal virtual void SetName([NotNull] string name) protected internal virtual void SetName([NotNull] string name)
{ {
Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength); Name = Check.NotNullOrWhiteSpace(name, nameof(name), TenantConsts.MaxNameLength);
} }
public TenantAggregateRoot() public TenantAggregateRoot()
{ {
} }
protected internal TenantAggregateRoot(Guid id, [NotNull] string name) : base(id) protected internal TenantAggregateRoot(Guid id, [NotNull] string name) : base(id)
{ {
SetName(name); SetName(name);
} }
} }

@ -1,13 +1,18 @@
namespace NPin.Framework.Upms.Domain.Shared.Consts; namespace NPin.Framework.Upms.Domain.Shared.Consts;
public class ConfigConst public class ConfigConst
{ {
/// <summary> /// <summary>
/// 系统配置前缀 /// 系统配置前缀
/// </summary> /// </summary>
public const string SysConfigPrefix = "Sys"; public const string SysConfigPrefix = "sys";
public const string AliyunConfigKey = "Aliyun"; /// <summary>
public const string TencentConfigKey = "Tencent"; /// 短信配置相关
public const string SmsConfigKey = "Sms"; /// </summary>
public const string SmsConfigKey = "sms";
public const string SmsProvidersKey = $"{SysConfigPrefix}.{SmsConfigKey}.providers";
public const string SmsTemplatesKey = $"{SysConfigPrefix}.{SmsConfigKey}.templates";
public const string SmsSettingsKey = $"{SysConfigPrefix}.{SmsConfigKey}.settings";
public const string SmsConfigModelKey = $"{SysConfigPrefix}.{SmsConfigKey}.config";
} }

@ -1,22 +1,22 @@
using System.ComponentModel; using System.ComponentModel;
namespace NPin.Framework.Upms.Domain.Shared.Enums; namespace NPin.Framework.Upms.Domain.Shared.Enums;
/// <summary> /// <summary>
/// 短信提供商枚举 /// 短信提供商枚举
/// </summary> /// </summary>
public enum SmsProviderEnum public enum SmsProviderTypeEnum
{ {
Aliyun, Aliyun,
Tencent Tencent
} }
/// <summary> /// <summary>
/// 短信类型枚举 /// 短信类型枚举
/// </summary> /// </summary>
public enum SmsTypeEnum public enum SmsTypeEnum
{ {
[Description("登录")] Login, [Description("登录")] Login,
[Description("注册")] Register, [Description("注册")] Register,
[Description("找回密码(重置密码)")] ResetPassword, [Description("找回密码(重置密码)")] ResetPassword,
} }

@ -1,24 +0,0 @@
namespace NPin.Framework.Upms.Domain.Shared.Model;
public class AliyunConfigModel
{
/// <summary>
/// 访问密钥Key
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
/// 访问密钥
/// </summary>
public string AccessKeySecret { get; set; }
/// <summary>
/// 默认 区域ID
/// </summary>
public string RegionId { get; set; }
/// <summary>
/// 默认 短信访问 端点
/// </summary>
public string SmsEndpoint { get; set; } = "dysmsapi.aliyuncs.com";
}

@ -1,54 +1,128 @@
using NPin.Framework.Upms.Domain.Shared.Enums; using Newtonsoft.Json;
using NPin.Framework.Upms.Domain.Shared.Enums;
namespace NPin.Framework.Upms.Domain.Shared.Model;
namespace NPin.Framework.Upms.Domain.Shared.Model;
public class SmsConfigModel
{ public class SmsConfigModel
/// <summary> {
/// 是否启用(总控) /// <summary>
/// </summary> /// 是否启用(总控)
public bool Enabled { get; set; } = false; /// </summary>
public bool Enabled { get; set; } = false;
/// <summary>
/// 设定集 /// <summary>
/// </summary> /// 提供商列表
public Dictionary<SmsTypeEnum, SmsSettings> Settings { get; set; } /// </summary>
} [JsonIgnore]
public List<SmsProvider> Providers { get; set; } = [];
public class SmsSettings
{ /// <summary>
/// <summary> /// 短信模板列表
/// 是否启用 /// </summary>
/// </summary> [JsonIgnore]
public bool Enabled { get; set; } = false; public List<SmsTemplate> Templates { get; set; } = [];
/// <summary> /// <summary>
/// 服务提供商 /// 系统短信设定集
/// </summary> /// 类型:设定
public SmsProviderEnum Provider { get; set; } /// </summary>
[JsonIgnore]
/// <summary> public Dictionary<SmsTypeEnum, SmsSettings> Settings { get; set; } = new();
/// 区域
/// </summary> public SmsProvider GetProvider(SmsSettings settings)
public string Region { get; set; } {
return Providers.First(it => it.Id == settings.ProviderId);
/// <summary> }
/// 短信访问 端点
/// </summary> public SmsTemplate GetTemplate(SmsSettings settings)
public string Endpoint { get; set; } {
return Templates.First(it => it.Id == settings.TemplateId);
/// <summary> }
/// 短信签名名称
/// </summary> public SmsSettings? GetSetting(SmsTypeEnum typeEnum)
public string SignName { get; set; } {
return Settings.GetValueOrDefault(typeEnum, null);
/// <summary> }
/// 短信模板Code }
/// </summary>
public string TemplateCode { get; set; } /// <summary>
/// 短信提供商配置
/// <summary> /// </summary>
/// 过期时间,单位:秒 public class SmsProvider
/// </summary> {
public int Expires { get; set; } /// <summary>
/// ID
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 服务提供商
/// </summary>
public SmsProviderTypeEnum ProviderType { get; set; }
/// <summary>
/// 访问密钥Key
/// </summary>
public string AccessKeyId { get; set; }
/// <summary>
/// 访问密钥
/// </summary>
public string AccessKeySecret { get; set; }
/// <summary>
/// 区域
/// </summary>
public string Region { get; set; }
/// <summary>
/// 短信访问 端点
/// </summary>
public string Endpoint { get; set; }
/// <summary>
/// 短信SdkAppId
/// </summary>
public string SmsSdkAppId { get; set; }
}
public class SmsTemplate
{
/// <summary>
/// ID
/// </summary>
public Guid Id { get; set; }
/// <summary>
/// 短信签名名称
/// </summary>
public string SignName { get; set; }
/// <summary>
/// 短信模板Code
/// </summary>
public string TemplateCode { get; set; }
}
public class SmsSettings
{
/// <summary>
/// 短信类型
/// </summary>
public SmsTypeEnum SmsType { get; set; }
/// <summary>
/// 提供商ID
/// </summary>
public Guid ProviderId { get; set; }
/// <summary>
/// 模板ID
/// </summary>
public Guid TemplateId { get; set; }
/// <summary>
/// 过期时间,单位:秒
/// </summary>
public int Expires { get; set; }
} }

@ -1,31 +0,0 @@
using Newtonsoft.Json;
namespace NPin.Framework.Upms.Domain.Shared.Model;
public class TencentConfigModel
{
/// <summary>
/// 访问密钥Key
/// </summary>
public string SecretId { get; set; }
/// <summary>
/// 访问密钥
/// </summary>
public string SecretKey { get; set; }
/// <summary>
/// 默认区域
/// </summary>
public string Region { get; set; }
/// <summary>
/// 默认短信访问 端点
/// </summary>
public string SmsEndpoint { get; set; } = "sms.tencentcloudapi.com";
/// <summary>
/// 短信SdkAppId
/// </summary>
public string SmsSdkAppId { get; set; }
}

@ -1,46 +1,46 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Authorization; namespace NPin.Framework.Upms.Domain.Authorization;
[SugarTable("Social", "第三方授权表")] [SugarTable("SysSocial", "第三方授权表")]
public class SocialAggregateRoot: AggregateRoot<Guid>, ISoftDelete, IHasCreationTime public class SocialAggregateRoot: AggregateRoot<Guid>, ISoftDelete, IHasCreationTime
{ {
[SugarColumn(IsPrimaryKey = true)] [SugarColumn(IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
public Guid UserId { get; set; } public Guid UserId { get; set; }
public string OpenId { get; set; } public string OpenId { get; set; }
public string? UnionId { get; set; } public string? UnionId { get; set; }
public string Name { get; set; } public string Name { get; set; }
public string Type { get; set; } public string Type { get; set; }
public bool IsDeleted { get; } public bool IsDeleted { get; }
public DateTime CreationTime { get; } public DateTime CreationTime { get; }
[SugarColumn(IsIgnore = true)] [SugarColumn(IsIgnore = true)]
public override ExtraPropertyDictionary ExtraProperties { get; protected set; } public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
public SocialAggregateRoot() public SocialAggregateRoot()
{ {
} }
public SocialAggregateRoot(string type, Guid userId, string openId, string? unionId) public SocialAggregateRoot(string type, Guid userId, string openId, string? unionId)
{ {
UserId = userId; UserId = userId;
OpenId = openId; OpenId = openId;
UnionId = unionId; UnionId = unionId;
Type = type; Type = type;
} }
public SocialAggregateRoot(string type, Guid userId, string openId, string? unionId, string name): this(type, userId, openId, unionId) public SocialAggregateRoot(string type, Guid userId, string openId, string? unionId, string name): this(type, userId, openId, unionId)
{ {
Name = name; Name = name;
} }
} }

@ -1,32 +1,32 @@
using NPin.Framework.SqlSugarCore.Abstractions.Data; using NPin.Framework.SqlSugarCore.Abstractions.Data;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("announcement", "系统公告表")] [SugarTable("SysAnnouncement", "系统公告表")]
public class AnnouncementEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled public class AnnouncementEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{ {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "公告标题")] [SugarColumn(ColumnDescription = "公告标题")]
public string Title { get; set; } public string Title { get; set; }
[SugarColumn(ColumnDescription = "公告分类")] [SugarColumn(ColumnDescription = "公告分类")]
public string Category { get; set; } public string Category { get; set; }
[SugarColumn(ColumnDescription = "公告行为")] [SugarColumn(ColumnDescription = "公告行为")]
public string Action { get; set; } public string Action { get; set; }
[SugarColumn(ColumnDescription = "公告内容", ColumnDataType = StaticConfig.CodeFirst_BigString)] [SugarColumn(ColumnDescription = "公告内容", ColumnDataType = StaticConfig.CodeFirst_BigString)]
public string Content { get; set; } public string Content { get; set; }
public bool IsDeleted { get; } public bool IsDeleted { get; }
public DateTime CreationTime { get; } public DateTime CreationTime { get; }
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
public int OrderNum { get; set; } public int OrderNum { get; set; }
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
} }

@ -1,34 +1,34 @@
using Mapster; using Mapster;
using NPin.Framework.SqlSugarCore.Abstractions.Data; using NPin.Framework.SqlSugarCore.Abstractions.Data;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Config", "系统配置表")] [SugarTable("SysConfig", "系统配置表")]
[SugarIndex($"index_{nameof(Key)}", nameof(Key), OrderByType.Asc, true)] [SugarIndex($"index_{nameof(Key)}", nameof(Key), OrderByType.Asc, true)]
public class ConfigEntity : Entity<Guid>, IEnabled, IOrderNum, ISoftDelete, IAuditedObject public class ConfigEntity : Entity<Guid>, IEnabled, IOrderNum, ISoftDelete, IAuditedObject
{ {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "配置名称")] [SugarColumn(ColumnDescription = "配置名称")]
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "配置键")] [SugarColumn(ColumnDescription = "配置键")]
public string Key { get; set; } = string.Empty; public string Key { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "配置值")] [SugarColumn(ColumnDescription = "配置值")]
public string Value { get; set; } = string.Empty; public string Value { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "配置描述")] [SugarColumn(ColumnDescription = "配置描述")]
public string? Remark { get; set; } = string.Empty; public string? Remark { get; set; } = string.Empty;
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
public int OrderNum { get; set; } public int OrderNum { get; set; }
public bool IsDeleted { get; } public bool IsDeleted { get; }
public DateTime CreationTime { get; } public DateTime CreationTime { get; }
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
} }

@ -1,41 +1,41 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Data; using Volo.Abp.Data;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("File", "文件信息表")] [SugarTable("SysFile", "文件信息表")]
public class FileAggregateRoot : AggregateRoot<Guid>, IAuditedObject public class FileAggregateRoot : AggregateRoot<Guid>, IAuditedObject
{ {
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")] [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "文件大小")] [SugarColumn(ColumnDescription = "文件大小")]
public decimal FileSize { get; set; } public decimal FileSize { get; set; }
[SugarColumn(ColumnDescription = "文件名称")] [SugarColumn(ColumnDescription = "文件名称")]
public string FileName { get; set; } public string FileName { get; set; }
[SugarColumn(ColumnDescription = "文件后缀")] [SugarColumn(ColumnDescription = "文件后缀")]
public string FileExt { get; set; } public string FileExt { get; set; }
[SugarColumn(ColumnDescription = "文件路径")] [SugarColumn(ColumnDescription = "文件路径")]
public string FilePath { get; set; } public string FilePath { get; set; }
public DateTime CreationTime { get; } public DateTime CreationTime { get; }
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
[SugarColumn(IsIgnore = true)] public override ExtraPropertyDictionary ExtraProperties { get; protected set; } [SugarColumn(IsIgnore = true)] public override ExtraPropertyDictionary ExtraProperties { get; protected set; }
public FileAggregateRoot() public FileAggregateRoot()
{ {
} }
public FileAggregateRoot(Guid id) : base(id) public FileAggregateRoot(Guid id) : base(id)
{ {
Id = id; Id = id;
} }
} }

@ -1,81 +1,82 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using IPTools.Core; using IPTools.Core;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using NPin.Framework.Core.Extensions; using NPin.Framework.Core.Extensions;
using SqlSugar; using SqlSugar;
using UAParser; using UAParser;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("LoginLog", "登录日志表")] [SugarTable("SysLoginLog", "登录日志表")]
public class LoginLogEntity : Entity<Guid>, ICreationAuditedObject [SugarIndex($"index_{nameof(LoginUser)}", nameof(LoginUser), OrderByType.Asc)]
{ public class LoginLogEntity : Entity<Guid>, ICreationAuditedObject
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
public DateTime CreationTime { get; }
public Guid? CreatorId { get; } public DateTime CreationTime { get; }
public Guid? CreatorId { get; }
[SugarColumn(ColumnDescription = "登录用户")]
public string? LoginUser { get; set; } [SugarColumn(ColumnDescription = "登录用户")]
public string? LoginUser { get; set; }
[SugarColumn(ColumnDescription = "登录用户ID")]
public Guid LoginUserId { get; set; } [SugarColumn(ColumnDescription = "登录用户ID")]
public Guid LoginUserId { get; set; }
[SugarColumn(ColumnDescription = "登录地点")]
public string? LoginLocation { get; set; } [SugarColumn(ColumnDescription = "登录地点")]
public string? LoginLocation { get; set; }
[SugarColumn(ColumnDescription = "Ipv4")]
public string? LoginIPv4 { get; set; } [SugarColumn(ColumnDescription = "Ipv4")]
public string? LoginIpv4 { get; set; }
[SugarColumn(ColumnDescription = "Ipv6")]
public string? LoginIPv6 { get; set; } [SugarColumn(ColumnDescription = "Ipv6")]
public string? LoginIpv6 { get; set; }
[SugarColumn(ColumnDescription = "浏览器")]
public string? Browser { get; set; } [SugarColumn(ColumnDescription = "浏览器")]
public string? Browser { get; set; }
[SugarColumn(ColumnDescription = "操作系统")]
public string? Os { get; set; } [SugarColumn(ColumnDescription = "操作系统")]
public string? Os { get; set; }
[SugarColumn(ColumnDescription = "登录信息")]
public string? LoginMsg { get; set; } [SugarColumn(ColumnDescription = "登录信息")]
public string? LoginMsg { get; set; }
public static LoginLogEntity GetInfoByHttpContext(HttpContext httpContext)
{ public static LoginLogEntity GetInfoByHttpContext(HttpContext httpContext)
// var ipInfo = httpContext.GetRemoteIpInfo(); {
string ipv4AddrStr = null; // var ipInfo = httpContext.GetRemoteIpInfo();
string ipv6AddrStr = null; string ipv4AddrStr = null;
var ipAddr = httpContext.GetClientIpAddress(); string ipv6AddrStr = null;
if (ipAddr != null) var ipAddr = httpContext.GetClientIpAddress();
{ if (ipAddr != null)
switch (ipAddr.AddressFamily) {
{ switch (ipAddr.AddressFamily)
case AddressFamily.InterNetwork: {
ipv4AddrStr = ipAddr.ToString(); case AddressFamily.InterNetwork:
break; ipv4AddrStr = ipAddr.ToString();
case AddressFamily.InterNetworkV6: break;
ipv6AddrStr = ipAddr.ToString(); case AddressFamily.InterNetworkV6:
break; ipv6AddrStr = ipAddr.ToString();
} break;
} }
}
var location = IPAddress.IsLoopback(ipAddr)
? new IpInfo { Province = "本地", City = "本机" } var location = IPAddress.IsLoopback(ipAddr)
: IpTool.Search(ipAddr.ToString()); ? new IpInfo { Province = "本地", City = "本机" }
: IpTool.Search(ipAddr.ToString());
var clientInfo = GetClientInfo(httpContext);
var clientInfo = GetClientInfo(httpContext);
return new LoginLogEntity
{ return new LoginLogEntity
Browser = clientInfo.Device.Family, {
Os = clientInfo.OS.ToString(), Browser = clientInfo.Device.Family,
LoginIPv4 = ipv4AddrStr, Os = clientInfo.OS.ToString(),
LoginIPv6 = ipv6AddrStr, LoginIpv4 = ipv4AddrStr,
LoginLocation = $"{location.Country}-{location.Province}-{location.City}" LoginIpv6 = ipv6AddrStr,
}; LoginLocation = $"{location.Country}-{location.Province}-{location.City}"
};
ClientInfo GetClientInfo(HttpContext ctx) => Parser.GetDefault().Parse(ctx.GetUserAgent());
} ClientInfo GetClientInfo(HttpContext ctx) => Parser.GetDefault().Parse(ctx.GetUserAgent());
}
} }

@ -1,46 +1,46 @@
using NPin.Framework.SqlSugarCore.Abstractions.Data; using NPin.Framework.SqlSugarCore.Abstractions.Data;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Organization", "组织机构表")] [SugarTable("SysOrganization", "组织机构表")]
public class OrganizationEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled public class OrganizationEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{ {
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")] [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "组织机构名称")] [SugarColumn(ColumnDescription = "组织机构名称")]
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "组织机构编码")] [SugarColumn(ColumnDescription = "组织机构编码")]
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "描述")] [SugarColumn(ColumnDescription = "描述")]
public string? Remark { get; set; } public string? Remark { get; set; }
/// <summary> /// <summary>
/// 负责人ID /// 负责人ID
/// </summary> /// </summary>
public Guid LeaderId { get; set; } public Guid LeaderId { get; set; }
/// <summary> /// <summary>
/// 负责人名称,仅用户展示,不存储 /// 负责人名称,仅用户展示,不存储
/// </summary> /// </summary>
[SugarColumn(IsIgnore = true)] [SugarColumn(IsIgnore = true)]
public string Leader { get; set; } public string Leader { get; set; }
/// <summary> /// <summary>
/// 父节点 ID /// 父节点 ID
/// </summary> /// </summary>
public Guid ParentId { get; set; } public Guid ParentId { get; set; }
public bool IsDeleted { get; } public bool IsDeleted { get; }
public DateTime CreationTime { get; } = DateTime.Now; public DateTime CreationTime { get; } = DateTime.Now;
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
public int OrderNum { get; set; } public int OrderNum { get; set; }
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
} }

@ -1,30 +1,30 @@
using NPin.Framework.SqlSugarCore.Abstractions.Data; using NPin.Framework.SqlSugarCore.Abstractions.Data;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Post", "岗位表")] [SugarTable("SysPost", "岗位表")]
public class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled public class PostEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{ {
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")] [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "岗位编码")] [SugarColumn(ColumnDescription = "岗位编码")]
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "岗位名称")] [SugarColumn(ColumnDescription = "岗位名称")]
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "岗位描述")] [SugarColumn(ColumnDescription = "岗位描述")]
public string? Remark { get; set; } public string? Remark { get; set; }
public bool IsDeleted { get; } public bool IsDeleted { get; }
public DateTime CreationTime { get; } = DateTime.Now; public DateTime CreationTime { get; } = DateTime.Now;
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
public int OrderNum { get; set; } public int OrderNum { get; set; }
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
} }

@ -1,42 +1,42 @@
using NPin.Framework.SqlSugarCore.Abstractions.Data; using NPin.Framework.SqlSugarCore.Abstractions.Data;
using NPin.Framework.Upms.Domain.Shared.Enums; using NPin.Framework.Upms.Domain.Shared.Enums;
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("Role", "角色表")] [SugarTable("SysRole", "角色表")]
public class RoleEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled public class RoleEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IOrderNum, IEnabled
{ {
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")] [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "角色代码")] [SugarColumn(ColumnDescription = "角色代码")]
public string Code { get; set; } = string.Empty; public string Code { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "角色名称")] [SugarColumn(ColumnDescription = "角色名称")]
public string Name { get; set; } = string.Empty; public string Name { get; set; } = string.Empty;
[SugarColumn(ColumnDescription = "角色数据权限范围")] [SugarColumn(ColumnDescription = "角色数据权限范围")]
public DataScopeEnum DataScope { get; set; } = DataScopeEnum.All; public DataScopeEnum DataScope { get; set; } = DataScopeEnum.All;
[SugarColumn(ColumnDescription = "描述")] [SugarColumn(ColumnDescription = "描述")]
public string? Remark { get; set; } public string? Remark { get; set; }
public bool IsDeleted { get; } public bool IsDeleted { get; }
public DateTime CreationTime { get; } = DateTime.Now; public DateTime CreationTime { get; } = DateTime.Now;
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
public int OrderNum { get; set; } public int OrderNum { get; set; }
public bool IsEnabled { get; set; } public bool IsEnabled { get; set; }
#region 导航 #region 导航
[Navigate(typeof(RoleOrganizationEntity), nameof(RoleOrganizationEntity.RoleId), [Navigate(typeof(RoleOrganizationEntity), nameof(RoleOrganizationEntity.RoleId),
nameof(RoleOrganizationEntity.OrgId))] nameof(RoleOrganizationEntity.OrgId))]
public List<OrganizationEntity> OrganizationList { get; set; } public List<OrganizationEntity> OrganizationList { get; set; }
#endregion #endregion
} }

@ -1,16 +1,16 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelRoleOrganization", "角色-机构 关系表")] [SugarTable("SysRelRoleOrganization", "角色-机构 关系表")]
public class RoleOrganizationEntity : Entity<Guid> public class RoleOrganizationEntity : Entity<Guid>
{ {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "角色ID")] [SugarColumn(ColumnDescription = "角色ID")]
public Guid RoleId { get; set; } public Guid RoleId { get; set; }
[SugarColumn(ColumnDescription = "机构ID")] [SugarColumn(ColumnDescription = "机构ID")]
public Guid OrgId { get; set; } public Guid OrgId { get; set; }
} }

@ -8,7 +8,8 @@ using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("User", "用户表")] [SugarTable("SysUser", "用户表")]
[SugarIndex($"index_{nameof(Username)}", nameof(Username), OrderByType.Asc)]
public class UserEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IEnabled, IOrderNum public class UserEntity : Entity<Guid>, ISoftDelete, IAuditedObject, IEnabled, IOrderNum
{ {
#region User #region User

@ -1,24 +1,24 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Auditing; using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("UserMetadata", "用户元数据表")] [SugarTable("SysUserMetadata", "用户元数据表")]
public class UserMetaEntity : Entity<Guid>, IAuditedObject public class UserMetaEntity : Entity<Guid>, IAuditedObject
{ {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
public Guid UserId; public Guid UserId;
[SugarColumn(ColumnDescription = "元数据 键")] [SugarColumn(ColumnDescription = "元数据 键")]
public string Key { get; set; } public string Key { get; set; }
[SugarColumn(ColumnDescription = "元数据 值")] [SugarColumn(ColumnDescription = "元数据 值")]
public string Value { get; set; } public string Value { get; set; }
public DateTime CreationTime { get; } public DateTime CreationTime { get; }
public Guid? CreatorId { get; } public Guid? CreatorId { get; }
public DateTime? LastModificationTime { get; } public DateTime? LastModificationTime { get; }
public Guid? LastModifierId { get; } public Guid? LastModifierId { get; }
} }

@ -1,16 +1,16 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelUserOrganization", "用户-组织机构 关系表")] [SugarTable("SysRelUserOrganization", "用户-组织机构 关系表")]
public class UserOrganizationEntity : Entity<Guid> public class UserOrganizationEntity : Entity<Guid>
{ {
[SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; } [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "用户ID")] [SugarColumn(ColumnDescription = "用户ID")]
public Guid UserId { get; set; } public Guid UserId { get; set; }
[SugarColumn(ColumnDescription = "组织机构ID")] [SugarColumn(ColumnDescription = "组织机构ID")]
public Guid OrganizationId { get; set; } public Guid OrganizationId { get; set; }
} }

@ -1,17 +1,17 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelUserPost","用户-岗位 关系表")] [SugarTable("SysRelUserPost","用户-岗位 关系表")]
public class UserPostEntity: Entity<Guid> public class UserPostEntity: Entity<Guid>
{ {
[SugarColumn(IsPrimaryKey = true)] [SugarColumn(IsPrimaryKey = true)]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "用户ID")] [SugarColumn(ColumnDescription = "用户ID")]
public Guid UserId { get; set; } public Guid UserId { get; set; }
[SugarColumn(ColumnDescription = "岗位ID")] [SugarColumn(ColumnDescription = "岗位ID")]
public Guid PostId { get; set; } public Guid PostId { get; set; }
} }

@ -1,17 +1,17 @@
using SqlSugar; using SqlSugar;
using Volo.Abp.Domain.Entities; using Volo.Abp.Domain.Entities;
namespace NPin.Framework.Upms.Domain.Entities; namespace NPin.Framework.Upms.Domain.Entities;
[SugarTable("RelUserRole", "用户-角色 关系表")] [SugarTable("SysRelUserRole", "用户-角色 关系表")]
public class UserRoleEntity: Entity<Guid> public class UserRoleEntity: Entity<Guid>
{ {
[SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")] [SugarColumn(IsPrimaryKey = true, ColumnDescription = "主键")]
public override Guid Id { get; protected set; } public override Guid Id { get; protected set; }
[SugarColumn(ColumnDescription = "角色ID")] [SugarColumn(ColumnDescription = "角色ID")]
public Guid RoleId { get; set; } public Guid RoleId { get; set; }
[SugarColumn(ColumnDescription = "用户ID")] [SugarColumn(ColumnDescription = "用户ID")]
public Guid UserId { get; set; } public Guid UserId { get; set; }
} }

@ -1,129 +1,78 @@
using AlibabaCloud.OpenApiClient.Models; using Microsoft.Extensions.Logging;
using AlibabaCloud.SDK.Dysmsapi20170525; using Newtonsoft.Json;
using Microsoft.Extensions.Logging; using NPin.Framework.SettingManagement.Domain;
using Newtonsoft.Json; using NPin.Framework.Upms.Domain.Settings;
using NPin.Framework.Upms.Domain.Repositories; using NPin.Framework.Upms.Domain.Shared.Consts;
using NPin.Framework.Upms.Domain.Shared.Enums; using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model; using NPin.Framework.Upms.Domain.Shared.Model;
using NPin.Framework.Upms.Domain.Shared.Options; using NPin.Framework.Upms.Domain.Sms;
using TencentCloud.Common; using Volo.Abp.Domain.Services;
using TencentCloud.Common.Profile;
using TencentCloud.Sms.V20210111; namespace NPin.Framework.Upms.Domain.Managers;
using TencentCloud.Sms.V20210111.Models;
using Volo.Abp.Caching; public class SmsManager : DomainService
using Volo.Abp.Domain.Services; {
private readonly ILogger<SmsManager> _logger;
namespace NPin.Framework.Upms.Domain.Managers;
private readonly ISettingManager _settingManager;
public class SmsManager : DomainService, ISms
{ private readonly IEnumerable<ISms> _smsProviders;
private ILogger<SmsManager> _logger;
private IConfigRepository _configRepository; public SmsManager(ILogger<SmsManager> logger, ISettingManager settingManager, IEnumerable<ISms> smsProviders)
private IDistributedCache<SmsConfigModel> _cache; {
_logger = logger;
public SmsManager(ILogger<SmsManager> logger, IConfigRepository configRepository) _settingManager = settingManager;
{ _smsProviders = smsProviders;
_logger = logger; }
_configRepository = configRepository;
} public async Task<SmsConfigModel> GetSmsConfigModelAsync()
{
public async Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam) var configJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsConfigModelKey);
{ var settingsJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsSettingsKey);
var providersJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsProvidersKey);
try var templateJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsTemplatesKey);
{
var smsSettings = SmsOptions.Config[smsType]; var ret = JsonConvert.DeserializeObject<SmsConfigModel>(configJson ?? string.Empty) ?? new SmsConfigModel();
if (!smsSettings.Enabled)
{ ret.Settings =
return; JsonConvert.DeserializeObject<Dictionary<SmsTypeEnum, SmsSettings>>(settingsJson ?? string.Empty) ??
} new Dictionary<SmsTypeEnum, SmsSettings>();
switch (smsSettings.Provider) ret.Providers = JsonConvert.DeserializeObject<List<SmsProvider>>(providersJson ?? string.Empty) ?? [];
{ ret.Templates = JsonConvert.DeserializeObject<List<SmsTemplate>>(templateJson ?? string.Empty) ?? [];
case SmsProviderEnum.Aliyun:
await SendAliyunSmsAsync(smsSettings, phoneNumbers, templateParam); return ret;
break; }
case SmsProviderEnum.Tencent:
await SendTencentSmsAsync(smsSettings, phoneNumbers, templateParam); public async Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam)
break; {
default: try
throw new Exception("未实现该服务提供商"); {
} var smsConfig = await GetSmsConfigModelAsync();
} if (!smsConfig.Enabled)
catch (Exception ex) {
{ throw new UserFriendlyException("短信服务未启用,无法发送短信。");
_logger.LogError(ex, $"短信发送失败: {ex.Message}"); }
throw new UserFriendlyException($"短信发送失败: {ex.Message}");
} var settings = smsConfig.GetSetting(smsType);
} if (settings is null)
{
private async Task SendTencentSmsAsync(SmsSettings settings, string phoneNumbers, throw new UserFriendlyException("未找到对应短信类型,无法发送短信。");
object templateParam) }
{
var client = SmsClientProvider.CreateClient(TencentOptions, settings); var providerConfig = smsConfig.GetProvider(settings);
var provider = _smsProviders.FirstOrDefault(i => i.ProviderType == providerConfig.ProviderType);
var sendSmsRequest = new SendSmsRequest if (provider is null)
{ {
PhoneNumberSet = phoneNumbers.Split(','), throw new NotImplementedException("未实现该方式的短信控制器");
SignName = settings.SignName, }
TemplateId = settings.TemplateCode,
TemplateParamSet = templateParam as string[] await provider.SendSmsAsync(smsConfig, settings, phoneNumbers, templateParam);
}; }
catch (Exception ex)
var response = await client.SendSms(sendSmsRequest); {
} _logger.LogError(ex, $"短信发送失败: {ex.Message}");
throw new UserFriendlyException($"短信发送失败: {ex.Message}");
private async Task SendAliyunSmsAsync(SmsSettings settings, string phoneNumbers, }
object templateParam) }
{
var client = SmsClientProvider.CreateClient(AliyunOptions, settings);
var sendSmsRequest = new AlibabaCloud.SDK.Dysmsapi20170525.Models.SendSmsRequest
{
PhoneNumbers = phoneNumbers,
SignName = settings.SignName,
TemplateCode = settings.TemplateCode,
TemplateParam = JsonConvert.SerializeObject(templateParam)
};
var response = await client.SendSmsAsync(sendSmsRequest);
}
}
public static class SmsClientProvider
{
public static Client CreateClient(AliyunOptions options, SmsSettings settings)
{
var config = new Config()
{
AccessKeyId = options.AccessKeyId,
AccessKeySecret = options.AccessKeySecret,
Endpoint = settings.Endpoint,
RegionId = settings.RegionId,
};
return new Client(config);
}
public static SmsClient CreateClient(TencentOptions options, SmsSettings settings)
{
var cred = new Credential
{
SecretId = options.SecretId,
SecretKey = options.SecretKey,
};
var httpProfile = new HttpProfile
{
Endpoint = settings.Endpoint,
};
var clientProfile = new ClientProfile()
{
HttpProfile = httpProfile
};
return new SmsClient(cred, settings.RegionId, clientProfile);
}
} }

@ -3,6 +3,7 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Caching.FreeRedis\NPin.Framework.Caching.FreeRedis.csproj" /> <ProjectReference Include="..\..\..\framework\NPin.Framework.Caching.FreeRedis\NPin.Framework.Caching.FreeRedis.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" /> <ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore.Abstractions\NPin.Framework.SqlSugarCore.Abstractions.csproj" />
<ProjectReference Include="..\..\setting-management\NPin.Framework.SettingManagement.Domain\NPin.Framework.SettingManagement.Domain.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj" /> <ProjectReference Include="..\NPin.Framework.Upms.Domain.Shared\NPin.Framework.Upms.Domain.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

@ -1,32 +1,40 @@
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NPin.Framework.Caching.FreeRedis; using NPin.Framework.Caching.FreeRedis;
using NPin.Framework.Upms.Domain.Authorization; using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.Upms.Domain.OperLog; using NPin.Framework.SettingManagement.Domain.Options;
using NPin.Framework.Upms.Domain.Shared; using NPin.Framework.Upms.Domain.Authorization;
using Volo.Abp.AspNetCore.SignalR; using NPin.Framework.Upms.Domain.OperLog;
using Volo.Abp.Caching; using NPin.Framework.Upms.Domain.Settings;
using Volo.Abp.Domain; using NPin.Framework.Upms.Domain.Shared;
using Volo.Abp.AspNetCore.SignalR;
namespace NPin.Framework.Upms.Domain; using Volo.Abp.Caching;
using Volo.Abp.Domain;
[DependsOn(
typeof(NPinFrameworkUpmsDomainSharedModule), namespace NPin.Framework.Upms.Domain;
typeof(NPinFrameworkCachingFreeRedisModule),
// Abp [DependsOn(
typeof(AbpAspNetCoreSignalRModule), typeof(NPinFrameworkUpmsDomainSharedModule),
typeof(AbpDddDomainModule), typeof(NPinFrameworkCachingFreeRedisModule),
typeof(AbpCachingModule) // Settings
)] typeof(NPinFrameworkSettingManagementDomainModule),
public class NPinFrameworkUpmsDomainModule : AbpModule // Abp
{ typeof(AbpAspNetCoreSignalRModule),
public override void ConfigureServices(ServiceConfigurationContext context) typeof(AbpDddDomainModule),
{ typeof(AbpCachingModule)
var services = context.Services; )]
var configuration = services.GetConfiguration(); public class NPinFrameworkUpmsDomainModule : AbpModule
services.AddControllers(opts => {
{ public override void ConfigureServices(ServiceConfigurationContext context)
opts.Filters.Add<PermissionGlobalAttribute>(); {
opts.Filters.Add<OperLogGlobalAttribute>(); var services = context.Services;
}); var configuration = services.GetConfiguration();
} services.AddControllers(opts =>
{
opts.Filters.Add<PermissionGlobalAttribute>();
opts.Filters.Add<OperLogGlobalAttribute>();
});
// 添加Upms模块的设置提供者
Configure<SettingManagementOptions>(opt => { opt.Providers.Add<UpmsSettingManagementProvider>(); });
}
} }

@ -1,86 +1,84 @@
using System.Net; using System.Net;
using System.Net.Sockets; using System.Net.Sockets;
using IPTools.Core; using IPTools.Core;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using NPin.Framework.Core.Extensions; using NPin.Framework.Core.Extensions;
using NPin.Framework.Upms.Domain.Entities; using NPin.Framework.Upms.Domain.Shared.OperLog;
using NPin.Framework.Upms.Domain.Shared.OperLog; using SqlSugar;
using SqlSugar; using Volo.Abp.Auditing;
using UAParser; using Volo.Abp.Domain.Entities;
using Volo.Abp.Auditing;
using Volo.Abp.Domain.Entities; namespace NPin.Framework.Upms.Domain.OperLog;
namespace NPin.Framework.Upms.Domain.OperLog; [SugarTable("SysOperationLog", "操作日志记录表")]
public class OperationLogEntity : Entity<Guid>, ICreationAuditedObject
[SugarTable("OperationLog", "操作日志记录表")] {
public class OperationLogEntity: Entity<Guid>, ICreationAuditedObject [SugarColumn(IsPrimaryKey = true)] public override Guid Id { get; protected set; }
{
[SugarColumn(IsPrimaryKey = true)] [SugarColumn(ColumnDescription = "日志标题")]
public override Guid Id { get; protected set; } public string? Title { get; set; }
[SugarColumn(ColumnDescription = "日志标题")] [SugarColumn(ColumnDescription = "操作类型")]
public string? Title { get; set; } public OperTypeEnum OperType { get; set; }
[SugarColumn(ColumnDescription = "操作类型")] [SugarColumn(ColumnDescription = "请求方式")]
public OperTypeEnum OperType { get; set; } public string? RequestMethod { get; set; }
[SugarColumn(ColumnDescription = "请求方式")] [SugarColumn(ColumnDescription = "操作者")]
public string? RequestMethod { get; set; } public string? OperUser { get; set; }
[SugarColumn(ColumnDescription = "操作者")] [SugarColumn(ColumnDescription = "操作者Ipv4")]
public string? OperUser { get; set; } public string? OperIPv4 { get; set; }
[SugarColumn(ColumnDescription = "操作者Ipv4")] [SugarColumn(ColumnDescription = "操作者Ipv6")]
public string? OperIPv4 { get; set; } public string? OperIPv6 { get; set; }
[SugarColumn(ColumnDescription = "操作者Ipv6")] [SugarColumn(ColumnDescription = "操作地点")]
public string? OperIPv6 { get; set; } public string? OperLocation { get; set; }
[SugarColumn(ColumnDescription = "操作地点")] [SugarColumn(ColumnDescription = "操作方法")]
public string? OperLocation { get; set; } public string? Method { get; set; }
[SugarColumn(ColumnDescription = "操作方法")] [SugarColumn(ColumnDescription = "请求参数")]
public string? Method { get; set; } public string? RequestParam { get; set; }
[SugarColumn(ColumnDescription = "请求参数")] [SugarColumn(ColumnDescription = "请求结果", Length = 9999)]
public string? RequestParam { get; set; } public string? RequestResult { get; set; }
[SugarColumn(ColumnDescription = "请求结果", Length = 9999)] public DateTime CreationTime { get; }
public string? RequestResult { get; set; } public Guid? CreatorId { get; }
public DateTime CreationTime { get; } public static OperationLogEntity GetInfoByHttpContext(HttpContext httpContext)
public Guid? CreatorId { get; } {
// var ipInfo = httpContext.GetRemoteIpInfo();
public static OperationLogEntity GetInfoByHttpContext(HttpContext httpContext) string ipv4AddrStr = null;
{ string ipv6AddrStr = null;
// var ipInfo = httpContext.GetRemoteIpInfo(); IpInfo info = new IpInfo { Province = "本地", City = "本机" };
string ipv4AddrStr = null;
string ipv6AddrStr = null; var ipAddr = httpContext.GetClientIpAddress();
IpInfo info = new IpInfo { Province = "本地", City = "本机" }; if (ipAddr != null)
{
var ipAddr = httpContext.GetClientIpAddress(); switch (ipAddr.AddressFamily)
if (ipAddr != null) {
{ case AddressFamily.InterNetwork:
switch (ipAddr.AddressFamily) ipv4AddrStr = ipAddr.ToString();
{ break;
case AddressFamily.InterNetwork: case AddressFamily.InterNetworkV6:
ipv4AddrStr = ipAddr.ToString(); ipv6AddrStr = ipAddr.ToString();
break; break;
case AddressFamily.InterNetworkV6: }
ipv6AddrStr = ipAddr.ToString();
break; if (!IPAddress.IsLoopback(ipAddr))
} {
info = IpTool.Search(ipAddr.ToString());
if (!IPAddress.IsLoopback(ipAddr)) }
{ }
info = IpTool.Search(ipAddr.ToString());
} return new OperationLogEntity
} {
return new OperationLogEntity OperIPv4 = ipv4AddrStr,
{ OperIPv6 = ipv6AddrStr,
OperIPv4 = ipv4AddrStr, OperLocation = $"{info.Country}-{info.Province}-{info.City}"
OperIPv6 = ipv6AddrStr, };
OperLocation = $"{info.Country}-{info.Province}-{info.City}" }
};
}
} }

@ -0,0 +1,17 @@
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.SettingManagement.Domain.Store;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.Domain.Settings;
public class UpmsSettingManagementProvider: SettingManagementProvider, ITransientDependency
{
public const string ProviderName = "Upms";
public override string Name => ProviderName;
public UpmsSettingManagementProvider(ISettingManagementStore settingManagementStore) : base(settingManagementStore)
{
}
}

@ -0,0 +1,23 @@
using NPin.Framework.SettingManagement.Domain;
using Volo.Abp.Settings;
namespace NPin.Framework.Upms.Domain.Settings;
public static class UpmsSettingManagerExtensions
{
public static Task<string?> GetOrNullUpmsAsync(this ISettingManager settingManager, string name,
bool fallback = true)
{
return settingManager.GetOrNullAsync(name, UpmsSettingManagementProvider.ProviderName, null, fallback);
}
public static Task<List<SettingValue>> GetAllUpmsAsync(this ISettingManager settingManager, bool fallback = true)
{
return settingManager.GetAllAsync(UpmsSettingManagementProvider.ProviderName, null, fallback);
}
public static Task SetUpmsAsync(this ISettingManager settingManager, string name, string value)
{
return settingManager.SetAsync(name, value, UpmsSettingManagementProvider.ProviderName, null);
}
}

@ -0,0 +1,20 @@
using NPin.Framework.Upms.Domain.Shared.Consts;
using Volo.Abp.Settings;
namespace NPin.Framework.Upms.Domain.Settings;
public class UpmsStaticSettingProvider: SettingDefinitionProvider
{
public override void Define(ISettingDefinitionContext context)
{
DefineSmsSettingDefinitions(context);
}
private void DefineSmsSettingDefinitions(ISettingDefinitionContext context)
{
context.Add(new SettingDefinition(ConfigConst.SmsConfigModelKey));
context.Add(new SettingDefinition(ConfigConst.SmsProvidersKey));
context.Add(new SettingDefinition(ConfigConst.SmsSettingsKey));
context.Add(new SettingDefinition(ConfigConst.SmsTemplatesKey));
}
}

@ -0,0 +1,54 @@
using AlibabaCloud.OpenApiClient.Models;
using AlibabaCloud.SDK.Dysmsapi20170525;
using AlibabaCloud.SDK.Dysmsapi20170525.Models;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.Domain.Sms.Handler;
public class AliyunSmsHandler : ISms, ISingletonDependency
{
private readonly ILogger<AliyunSmsHandler> _logger;
public AliyunSmsHandler(ILogger<AliyunSmsHandler> logger)
{
_logger = logger;
}
public SmsProviderTypeEnum ProviderType => SmsProviderTypeEnum.Aliyun;
public async Task SendSmsAsync(SmsConfigModel config, SmsSettings settings, string phoneNumbers,
object templateParam)
{
var client = CreateClient(config.GetProvider(settings));
var template = config.GetTemplate(settings);
var sendSmsRequest = new SendSmsRequest
{
PhoneNumbers = phoneNumbers,
SignName = template.SignName,
TemplateCode = template.TemplateCode,
TemplateParam = JsonConvert.SerializeObject(templateParam)
};
var response = await client.SendSmsAsync(sendSmsRequest);
// TODO 判断结果
_logger.LogDebug(response.ToString());
}
private Client CreateClient(SmsProvider provider)
{
var config = new Config()
{
AccessKeyId = provider.AccessKeyId,
AccessKeySecret = provider.AccessKeySecret,
Endpoint = provider.Endpoint,
RegionId = provider.Region,
};
return new Client(config);
}
}

@ -0,0 +1,64 @@
using Microsoft.Extensions.Logging;
using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
using TencentCloud.Common;
using TencentCloud.Common.Profile;
using TencentCloud.Sms.V20210111;
using TencentCloud.Sms.V20210111.Models;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.Domain.Sms.Handler;
public class TencentSmsHandler : ISms, ISingletonDependency
{
private readonly ILogger<AliyunSmsHandler> _logger;
public TencentSmsHandler(ILogger<AliyunSmsHandler> logger)
{
_logger = logger;
}
public SmsProviderTypeEnum ProviderType => SmsProviderTypeEnum.Tencent;
public async Task SendSmsAsync(SmsConfigModel config, SmsSettings settings, string phoneNumbers,
object templateParam)
{
var client = CreateClient(config.GetProvider(settings));
var template = config.GetTemplate(settings);
var sendSmsRequest = new SendSmsRequest
{
PhoneNumberSet = phoneNumbers.Split(','),
SignName = template.SignName,
TemplateId = template.TemplateCode,
TemplateParamSet = templateParam as string[]
};
var response = await client.SendSms(sendSmsRequest);
// TODO 判断结果
_logger.LogDebug(response.ToString());
}
private SmsClient CreateClient(SmsProvider provider)
{
var cred = new Credential
{
SecretId = provider.AccessKeyId,
SecretKey = provider.AccessKeySecret,
};
var httpProfile = new HttpProfile
{
Endpoint = provider.Endpoint,
};
var clientProfile = new ClientProfile()
{
HttpProfile = httpProfile
};
return new SmsClient(cred, provider.Region, clientProfile);
}
}

@ -1,11 +1,17 @@
using NPin.Framework.Upms.Domain.Shared.Enums; using NPin.Framework.Upms.Domain.Shared.Enums;
using NPin.Framework.Upms.Domain.Shared.Model;
namespace NPin.Framework.Upms.Domain.Managers;
namespace NPin.Framework.Upms.Domain.Sms;
/// <summary>
/// 短信接口 /// <summary>
/// </summary> /// 统一短信接口
public interface ISms /// </summary>
{ public interface ISms
Task SendSmsAsync(SmsTypeEnum smsType, string phoneNumbers, object templateParam); {
/// <summary>
/// 短信提供商类型
/// </summary>
SmsProviderTypeEnum ProviderType { get; }
Task SendSmsAsync(SmsConfigModel config, SmsSettings settings, string phoneNumbers, object templateParam);
} }

@ -0,0 +1,46 @@
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using NPin.Framework.SettingManagement.Domain;
using NPin.Framework.Upms.Domain.Managers;
using NPin.Framework.Upms.Domain.Settings;
using NPin.Framework.Upms.Domain.Shared.Consts;
using NPin.Framework.Upms.Domain.Shared.Model;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore.DataSeeds;
public class SmsConfigDataSeed : IDataSeedContributor, ITransientDependency
{
private readonly ILogger<SmsManager> _logger;
private readonly ISettingManager _settingManager;
public SmsConfigDataSeed(ILogger<SmsManager> logger, ISettingManager settingManager)
{
_logger = logger;
_settingManager = settingManager;
}
public async Task SeedAsync(DataSeedContext context)
{
var configJson = await _settingManager.GetOrNullUpmsAsync(ConfigConst.SmsConfigModelKey);
if (!string.IsNullOrEmpty(configJson))
{
return;
}
var configModel = new SmsConfigModel
{
Enabled = false,
Providers = [],
Settings = [],
Templates = []
};
await _settingManager.SetUpmsAsync(ConfigConst.SmsConfigModelKey, JsonConvert.SerializeObject(configModel));
await _settingManager.SetUpmsAsync(ConfigConst.SmsSettingsKey, JsonConvert.SerializeObject(configModel.Settings));
await _settingManager.SetUpmsAsync(ConfigConst.SmsProvidersKey, JsonConvert.SerializeObject(configModel.Providers));
await _settingManager.SetUpmsAsync(ConfigConst.SmsTemplatesKey, JsonConvert.SerializeObject(configModel.Templates));
}
}

@ -1,10 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<Import Project="..\..\..\common.props" /> <Import Project="..\..\..\common.props" />
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\..\framework\NPin.Framework.Mapster\NPin.Framework.Mapster.csproj" /> <ProjectReference Include="..\..\..\framework\NPin.Framework.Mapster\NPin.Framework.Mapster.csproj" />
<ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore\NPin.Framework.SqlSugarCore.csproj" /> <ProjectReference Include="..\..\..\framework\NPin.Framework.SqlSugarCore\NPin.Framework.SqlSugarCore.csproj" />
<ProjectReference Include="..\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj" /> <ProjectReference Include="..\..\setting-management\NPin.Framework.SettingManagement.SqlSugarCore\NPin.Framework.SettingManagement.SqlSugarCore.csproj" />
</ItemGroup> <ProjectReference Include="..\NPin.Framework.Upms.Domain\NPin.Framework.Upms.Domain.csproj" />
</ItemGroup>
</Project>
</Project>

@ -1,19 +1,22 @@
using NPin.Framework.Mapster; using NPin.Framework.Mapster;
using NPin.Framework.SqlSugarCore; using NPin.Framework.SettingManagement.SqlSugarCore;
using NPin.Framework.Upms.Domain; using NPin.Framework.SqlSugarCore;
using NPin.Framework.Upms.Domain;
namespace NPin.Framework.Upms.SqlSugarCore;
namespace NPin.Framework.Upms.SqlSugarCore.Repositories;
[DependsOn(
typeof(NPinFrameworkUpmsDomainModule), [DependsOn(
// framework typeof(NPinFrameworkUpmsDomainModule),
typeof(NPinFrameworkMapsterModule), // settings
typeof(NPinFrameworkSqlSugarCoreModule) typeof(NPinFrameworkSettingManagementSqlSugarCoreModule),
)] // framework
public class NPinFrameworkUpmsSqlSugarCoreModule : AbpModule typeof(NPinFrameworkMapsterModule),
{ typeof(NPinFrameworkSqlSugarCoreModule)
public override void ConfigureServices(ServiceConfigurationContext context) )]
{ public class NPinFrameworkUpmsSqlSugarCoreModule : AbpModule
{
} public override void ConfigureServices(ServiceConfigurationContext context)
{
}
} }

@ -1,49 +1,49 @@
using NPin.Framework.SqlSugarCore; using NPin.Framework.SqlSugarCore;
using NPin.Framework.Upms.Domain.Authorization; using NPin.Framework.Upms.Domain.Authorization;
using NPin.Framework.Upms.Domain.Shared.Consts; using NPin.Framework.Upms.Domain.Shared.Consts;
using SqlSugar; using SqlSugar;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore; namespace NPin.Framework.Upms.SqlSugarCore.Repositories;
public class NPinUpmsDbContext : SqlSugarDbContext public class NPinUpmsDbContext : SqlSugarDbContext
{ {
public NPinUpmsDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider) public NPinUpmsDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
{ {
} }
protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient) protected override void CustomDataFilter(ISqlSugarClient sqlSugarClient)
{ {
if (DataFilter.IsEnabled<IDataPermission>()) if (DataFilter.IsEnabled<IDataPermission>())
{ {
DataPermissionFilter(sqlSugarClient); DataPermissionFilter(sqlSugarClient);
} }
base.CustomDataFilter(sqlSugarClient); base.CustomDataFilter(sqlSugarClient);
} }
/// <summary> /// <summary>
/// 数据权限过滤 /// 数据权限过滤
/// </summary> /// </summary>
/// <param name="sqlSugarClient"></param> /// <param name="sqlSugarClient"></param>
protected void DataPermissionFilter(ISqlSugarClient sqlSugarClient) protected void DataPermissionFilter(ISqlSugarClient sqlSugarClient)
{ {
// 当前无登录用户,无需过滤 // 当前无登录用户,无需过滤
if (CurrentUser.Id == null) return; if (CurrentUser.Id == null) return;
// 管理员角色 不进行过滤 // 管理员角色 不进行过滤
if (CurrentUser.UserName.Equals(UserConst.Admin) || if (CurrentUser.UserName.Equals(UserConst.Admin) ||
CurrentUser.Roles.Any(r => r.Equals(UserConst.AdminRoleCode))) CurrentUser.Roles.Any(r => r.Equals(UserConst.AdminRoleCode)))
{ {
return; return;
} }
// var expUser = Expressionable.Create<>(); // var expUser = Expressionable.Create<>();
// var expRole = Expressionable.Create<>(); // var expRole = Expressionable.Create<>();
// 无岗位 or 无角色 只能看自己 // 无岗位 or 无角色 只能看自己
// sqlSugarClient.QueryFilter.AddTableFilter() // sqlSugarClient.QueryFilter.AddTableFilter()
} }
} }

@ -1,30 +1,30 @@
using Newtonsoft.Json; using Newtonsoft.Json;
using NPin.Framework.SqlSugarCore.Abstractions; using NPin.Framework.SqlSugarCore.Abstractions;
using NPin.Framework.SqlSugarCore.Repositories; using NPin.Framework.SqlSugarCore.Repositories;
using NPin.Framework.Upms.Domain.Entities; using NPin.Framework.Upms.Domain.Entities;
using NPin.Framework.Upms.Domain.Repositories; using NPin.Framework.Upms.Domain.Repositories;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace NPin.Framework.Upms.SqlSugarCore; namespace NPin.Framework.Upms.SqlSugarCore.Repositories;
public class ConfigRepository : SqlSugarRepository<ConfigEntity, Guid>, IConfigRepository, ITransientDependency public class ConfigRepository : SqlSugarRepository<ConfigEntity, Guid>, IConfigRepository, ITransientDependency
{ {
public ConfigRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base( public ConfigRepository(ISugarDbContextProvider<ISqlSugarDbContext> sugarDbContextProvider) : base(
sugarDbContextProvider) sugarDbContextProvider)
{ {
} }
public async Task<TDestination> GetSingleByKeyAsync<TDestination>(string key) where TDestination : new() public async Task<TDestination> GetSingleByKeyAsync<TDestination>(string key) where TDestination : new()
{ {
var config = await DbQueryable var config = await DbQueryable
.Where(e => e.Key.Equals(key)) .Where(e => e.Key.Equals(key))
.FirstAsync(); .FirstAsync();
if (config is null) if (config is null)
{ {
return new TDestination(); return new TDestination();
} }
var ret = JsonConvert.DeserializeObject<TDestination>(config.Value); var ret = JsonConvert.DeserializeObject<TDestination>(config.Value);
return ret ?? new TDestination(); return ret ?? new TDestination();
} }
} }

@ -1,11 +1,11 @@
using NPin.Framework.Upms.SqlSugarCore; using NPin.Framework.Upms.SqlSugarCore.Repositories;
using Volo.Abp.DependencyInjection; using Volo.Abp.DependencyInjection;
namespace NPin.SqlSugarCore; namespace NPin.SqlSugarCore;
public class NPinDbContext: NPinUpmsDbContext public class NPinDbContext: NPinUpmsDbContext
{ {
public NPinDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider) public NPinDbContext(IAbpLazyServiceProvider lazyServiceProvider) : base(lazyServiceProvider)
{ {
} }
} }

@ -1,29 +1,29 @@
using NPin.Domain; using NPin.Domain;
using NPin.Framework.AuditLogging.SqlSugarCore; using NPin.Framework.AuditLogging.SqlSugarCore;
using NPin.Framework.Mapster; using NPin.Framework.Mapster;
using NPin.Framework.SqlSugarCore; using NPin.Framework.SqlSugarCore;
using NPin.Framework.TenantManagement.SqlSugarCore; using NPin.Framework.TenantManagement.SqlSugarCore;
using NPin.Framework.Upms.SqlSugarCore; using NPin.Framework.Upms.SqlSugarCore.Repositories;
namespace NPin.SqlSugarCore; namespace NPin.SqlSugarCore;
[DependsOn( [DependsOn(
typeof(NPinDomainModule), typeof(NPinDomainModule),
typeof(NPinFrameworkUpmsSqlSugarCoreModule), typeof(NPinFrameworkUpmsSqlSugarCoreModule),
// TODO bbs // TODO bbs
// TODO codegen // TODO codegen
typeof(NPinFrameworkAuditLoggingSqlSugarCoreModule), typeof(NPinFrameworkAuditLoggingSqlSugarCoreModule),
typeof(NPinFrameworkTenantManagementSqlSugarCoreModule), typeof(NPinFrameworkTenantManagementSqlSugarCoreModule),
// //
typeof(NPinFrameworkMapsterModule), typeof(NPinFrameworkMapsterModule),
typeof(NPinFrameworkSqlSugarCoreModule) typeof(NPinFrameworkSqlSugarCoreModule)
)] )]
public class NPinSqlSugarCoreModule : AbpModule public class NPinSqlSugarCoreModule : AbpModule
{ {
public override void ConfigureServices(ServiceConfigurationContext context) public override void ConfigureServices(ServiceConfigurationContext context)
{ {
context.Services.AddNPinDbContext<NPinDbContext>(); context.Services.AddNPinDbContext<NPinDbContext>();
// 默认不开放可根据项目需要是否直接对外开放db // 默认不开放可根据项目需要是否直接对外开放db
// context.Services.AddTransient(x => x.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient); // context.Services.AddTransient(x => x.GetRequiredService<ISqlSugarDbContext>().SqlSugarClient);
} }
} }

@ -30,7 +30,7 @@ using Volo.Abp.Caching;
using Volo.Abp.MultiTenancy; using Volo.Abp.MultiTenancy;
using Volo.Abp.Swashbuckle; using Volo.Abp.Swashbuckle;
namespace NPin; namespace NPin.Web;
[DependsOn( [DependsOn(
typeof(NPinSqlSugarCoreModule), typeof(NPinSqlSugarCoreModule),

@ -1,5 +1,5 @@
using NPin; using NPin.Web;
using Serilog; using Serilog;
using Serilog.Events; using Serilog.Events;

@ -1,15 +1,24 @@
{ {
"$schema": "http://json.schemastore.org/launchsettings.json", "$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": { "profiles": {
"NPin.Web": { "NPin.Web": {
"commandName": "Project", "commandName": "Project",
"launchBrowser": true, "launchBrowser": true,
"launchUrl": "swagger", "launchUrl": "swagger",
"environmentVariables": { "environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development" "ASPNETCORE_ENVIRONMENT": "Development"
}, },
"dotnetRunMessages": true, "dotnetRunMessages": true,
"applicationUrl": "http://localhost:19001" "applicationUrl": "http://localhost:19000"
} },
} "Docker": {
} "commandName": "Docker",
"launchBrowser": false,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_HTTP_PORTS": "19000"
},
"publishAllPorts": true
}
}
}

@ -8,8 +8,8 @@
}, },
// //
"App": { "App": {
"SelfUrl": "http://*:19001", "SelfUrl": "http://*:19000",
"CorsOrigins": "http://localhost:19001;http://localhost:18000" "CorsOrigins": "http://localhost:19000;http://localhost:18000"
}, },
// //
"DbList": [ "DbList": [

Loading…
Cancel
Save