IGeekFan.FreeKit.Infrastructure
核心基础设施项目(src/BuildingBlocks/IGeekFan.FreeKit.Infrastructure,目标框架 net10.0),提供贯穿各层的基类与横切能力:Controller 基类、应用/领域服务基类、认证授权、缓存、异常体系、加解密、中间件、过滤器、DTO 与扩展方法。它是 BuildingBlocks 中最底层、被其它构建块与所有业务模块共享的"全家桶"约定层。
:::info 依赖
本项目无任何本地 ProjectReference,全部通过 NuGet 引用:
IGeekFan.FreeKit.Extras/IGeekFan.FreeKit.Modularity/IGeekFan.FreeKit.Email/IGeekFan.Localization.FreeSql(版本0.0.554)FreeSql+FreeSql.Repository及扩展、FreeRedis+FreeRedis.DistributedCacheDotNetCore.CAP(MySQL / RabbitMQ / InMemory / Dashboard)、Mapster、Serilog.*、AspNetCoreRateLimit、Owl.reCAPTCHA、Ardalis.GuardClauses、IP2Region.Net/IPTools.China、HtmlAgilityPack、System.IO.Hashing等 :::
模块与命名空间
| 文件夹 | 命名空间 | 职责 |
|---|---|---|
Application/ | ...Infrastructure.Application | Controller 基类、ApplicationService、CrudAppService |
DDD/ | ...Infrastructure.DDD | DomainService、IDomainEventDispatcher |
Caches/ | ...Infrastructure.Caches | ICacheService、CacheableAttribute、Provider |
Exceptions/ | ...Infrastructure.Exceptions | BusinessException、GuardExtensions |
Contracts/ | ...Infrastructure.Contracts | ResponseCode、ClaimsConsts、AuthenticationConst |
Authentication/ | ...Infrastructure.Authentication | CookieJwtBearerHandler、AuthMode |
Authorization/ | ...Infrastructure.Authorization | KitAuthorizeAttribute、IPermissionStore、策略 |
Security/ | ...Infrastructure.Security | CurrentUserExtensions、CryptoUtil |
DTO/ | ...Infrastructure.DTO | ApiResponse、PageQuery、EnumDto、JwtSettings |
Utils/ / Tools | ...Infrastructure.Utils / Tools | AESUtil、Md5Util、DESUtil、SM4Util、ToolHelper |
Middleware/ | ...Infrastructure.Middleware | EncryptionMiddleware |
BasicAuthentication/ | ...Infrastructure.BasicAuthentication | Basic 认证 |
IpRateLimiting/ | ...Infrastructure.IpRateLimiting | AddIpRateLimiting |
Filters/ | ...Infrastructure.Filters | SensitiveDataAttribute、ExceptionNotifier |
Google/ | ...Infrastructure.Google | reCAPTCHA |
Cap/ | ...Infrastructure.Cap | CAP 事务扩展 |
Common/ Extensions/ AspNetCore/ Serilog/ ApiClient/ | 对应命名空间 | 文件/HTTP/CAP 扩展、Autofac、日志、本地化等 |
Controller 基类
KitApiControllerBase
最底层基类,完全为空(仅 [ApiController]),不需要认证:
[ApiController]
public abstract class KitApiControllerBase : ControllerBase { }
FreeKitController
带 [Authorize] 的基类,大多数控制器继承它。它没有泛型变体,也不注入任何成员;认证 scheme 由全局 DefaultPolicy 统一管理。当前用户通过 ControllerBase.User 或从 DI 解析 ICurrentUser 获取。
[Authorize]
public abstract class FreeKitController : KitApiControllerBase { }
// 需要认证的 API
[ApiController]
[Route("api/[controller]")]
public class ArticleController : FreeKitController
{
private readonly IArticleService _articleService;
public ArticleController(IArticleService articleService) => _articleService = articleService;
[HttpGet]
public async Task<IActionResult> GetList() => Ok(await _articleService.GetListAsync());
}
// 不需要认证的 API
[ApiController]
[Route("api/[controller]")]
public class PublicController : KitApiControllerBase
{
[HttpGet("health")]
public IActionResult Health() => Ok("ok");
}
应用服务基类
ApplicationService
提供常用服务的懒加载注入(通过 IServiceProvider.GetRequiredService)。
| 属性 | 类型 | 可见性 |
|---|---|---|
CapPublisher | DotNetCore.CAP.ICapPublisher | public |
Mediator | MediatR.IMediator | public |
ServiceProvider | IServiceProvider | public |
CurrentUser | IGeekFan.FreeKit.Extras.Security.ICurrentUser | public |
UnitOfWorkManager | FreeSql.UnitOfWorkManager | public |
LoggerFactory | ILoggerFactory | public |
AuthorizationService | IAuthorizationService | public |
Logger | ILogger | protected |
PermissionStore | IPermissionStore | protected |
方法:GetEffectiveUserIdAsync(string permission, Guid? queryUserId)(取"有效用户"——支持模拟登录场景)、CurrentUnitOfWork(protected)、LazyGetRequiredService<T>(ref T)。
public class ArticleService : ApplicationService, IArticleService
{
private readonly IArticleRepository _repository;
public ArticleService(IArticleRepository repository) => _repository = repository;
public async Task<List<ArticleDto>> GetListAsync()
{
var userId = CurrentUser.FindUserId(); // ICurrentUser 扩展
var articles = await _repository.GetListAsync();
return articles.Adapt<List<ArticleDto>>(); // Mapster 映射
}
}
CrudAppService
CRUD 应用服务模板。泛型参数顺序固定为 7 个:
public class ArticleCrudService : CrudAppService<
Article, // 1. TEntity
ArticleDto, // 2. TGetOutputDto (用于 Get/单条)
ArticleListDto, // 3. TGetListOutputDto (用于列表)
Guid, // 4. TKey
ArticleListQuery, // 5. TGetListQuery (通常是 PageQuery 子类)
CreateArticleRequest, // 6. TCreateReq
UpdateArticleRequest // 7. TUpdateReq
>, IArticleCrudService
{
public ArticleCrudService(IBaseRepository<Article, Guid> repository) : base(repository) { }
}
// 自动获得:GetListAsync / GetAsync / CreateAsync / UpdateAsync / DeleteAsync
接口约束:
TGetOutputDto : IEntityDto<TKey>、TGetListOutputDto : class, IEntityDto<TKey>。GetListAsync(TGetListQuery)返回PagedResultDto<TGetListOutputDto>(来自IGeekFan.FreeKit.Extras.Dto)。
可重写的 protected virtual 方法(用于自定义行为):
| 方法 | 签名 |
|---|---|
CreateFilteredQuery | ISelect<TEntity> CreateFilteredQuery(TGetListQuery query) |
ApplySorting | ISelect<TEntity> ApplySorting(ISelect<TEntity> query, TGetListQuery input) |
MapToGetListOutputDto | TGetListOutputDto MapToGetListOutputDto(TEntity entity)(默认 entity.Adapt<TGetListOutputDto>()) |
EntityListToDtoList | List<TGetListOutputDto> EntityListToDtoList(IList<TEntity>, TGetListQuery) |
EntityListToDtoListAsync | ValueTask<List<TGetListOutputDto>> EntityListToDtoListAsync(IList<TEntity>, TGetListQuery) |
GetEntityByIdAsync | Task<TEntity> GetEntityByIdAsync(TKey id) / GetEntityByIdAsync(TKey id, bool throwEx, bool validateCurrentUser = false) |
ValidateEntityPermissions | void ValidateEntityPermissions(TKey id, bool throwEx, bool validateCurrentUser, TEntity entity) |
CreateAsync | Task<TGetOutputDto> CreateAsync(TEntity entity, TCreateReq createReq) |
:::caution 易错点
- 不存在
MapToEntity/MapToEntityList/CreateEntityAsync/UpdateEntityAsync/DeleteEntityAsync这类钩子;实体↔DTO 映射统一用 Mapster 的entity.Adapt<T>()/dto.Adapt(entity)。 - 不存在非泛型的
CrudAppServiceBase;CrudAppService<>本身就是唯一基类。 - 不存在
PagerListDto<T>;列表分页统一返回PagedResultDto<T>。 :::
领域服务基类
DomainService
public class DomainService : IDomainService // IDomainService : IScopedDependency
{
public IServiceProvider ServiceProvider { get; set; }
public ICurrentUser CurrentUser { get; } // public
public UnitOfWorkManager UnitOfWorkManager { get; } // public
public ILoggerFactory LoggerFactory { get; }
public IAuthorizationService AuthorizationService { get; }
protected ILogger Logger { get; }
protected IUnitOfWork CurrentUnitOfWork { get; }
}
与
ApplicationService相比,DomainService没有CapPublisher、Mediator、PermissionStore——它专注于领域逻辑与聚合根,不直接发分布式事件。
领域事件分发
public interface IDomainEventDispatcher
{
Task DispatchAndClearEvents(IEnumerable<IDomainEventBase> entitiesWithEvents);
}
DomainEventDispatcher 遍历每个含事件的实体 → 取出 GetDomainEvents() → ClearDomainEvents() 清空 → 对每个领域事件 await mediator.Publish(...)(经 MediatR 发布):
public class OrderDomainService : DomainService, IOrderDomainService
{
private readonly IDomainEventDispatcher _eventDispatcher;
public async Task PlaceOrderAsync(Order order)
{
// 业务逻辑...
order.AddDomainEvent(new OrderPlacedEvent(order.Id));
await _eventDispatcher.DispatchAndClearEvents(new IDomainEventBase[] { order });
}
}
缓存系统
两种缓存策略
public enum CacheStrategyType { Redis = 0, Memory = 1 } // Redis 为默认
ICacheService
public interface ICacheService
{
T CacheShell<T>(string key, int timeoutSeconds, Func<T> getData);
Task<T> CacheShellAsync<T>(string key, int timeoutSeconds, Func<Task<T>> getData);
Task<T?> GetAsync<T>(string key);
void Set<T>(string key, int timeoutSeconds, T value);
Task SetAsync<T>(string key, int timeoutSeconds, T value);
void Remove(string key);
void RemoveByPrefix(string prefix);
}
CacheService 默认实现基于 FreeRedis 的 IRedisClient(timeoutSeconds == 0 时直接执行 getData() 不缓存)。
注册
// 无参:注册 RedisCacheProvider / MemoryCacheProvider / CacheProviderFactory(均为 Singleton)
builder.Services.AddCacheStrategy();
源码中没有 AddCacheStrategy(CacheStrategyType.Redis) 这种带参重载,也没有强类型 CacheOptions 类。缓存开关与默认过期通过配置读取:"Cache:Enable"(bool,默认 false)、"Cache:ExpireSeconds"(int,默认 -1)。
使用方式
// 同步壳
var article = _cache.CacheShell("article:" + id, 300, () => _repository.Find(id));
// 异步壳
var article = await _cache.CacheShellAsync("article:" + id, 300, async () => await _repository.FindAsync(id));
[Cacheable] 特性
[AttributeUsage(AttributeTargets.Method)],属性:CacheKey(默认 null)、ExpireSeconds(默认 0)、CacheStrategy(默认 Redis)。
[Cacheable(CacheKey = "article:detail", ExpireSeconds = 300)]
public async Task<Article> GetByIdAsync(Guid id) => await _repository.FindAsync(id);
异常体系
BusinessException
[Serializable]
public class BusinessException : Exception
{
public int StatusCode { get; set; }
public int? Code { get; set; }
public BusinessException WithCode(int? code);
public BusinessException WithStatusCode(int statusCode);
public BusinessException WithData(string name, object value);
}
其基类 CustomException 还提供 ErrorMessages(只读)、StatusCode(默认 InternalServerError)。
常用异常
throw new BusinessException("订单状态不允许操作");
throw new BusinessException("业务错误").WithCode((int)ResponseCode.BusinessException);
throw new EntityNotFoundException(typeof(Article), id);
throw new BadRequestException("参数无效");
throw new InvalidEmailException(email);
throw new InvalidDateException(date);
| 异常类 | 说明 |
|---|---|
BusinessException | 业务异常,带 Code / StatusCode |
EntityNotFoundException | 实体不存在(携带 EntityType / Id) |
BadRequestException | 请求参数错误 |
InvalidEmailException / InvalidDateException | 邮箱 / 日期格式校验失败 |
:::caution 已知问题
BadRequestException 当前把 StatusCode 设为 HttpStatusCode.NotFound(404)而非 400,属疑似 bug。若依赖其 HTTP 状态码,请留意。
:::
Guard(基于 Ardalis.GuardClauses)
GuardExtensions 是 IGuardClause 的扩展方法,调用方式为 Guard.Against.*:
Guard.Against.NegativeOrZero(amount, nameof(amount));
Guard.Against.Null(order, nameof(order));
Guard.Against.NotFound(id, nameof(id));
常用方法:Null / NullOrEmpty / NullOrWhiteSpace、NegativeOrZero(decimal/int/long/double)、Negative、NotExists、NotFound、InvalidDate、InvalidEmail、InvalidCurrency、InvalidPhoneNumber。
ResponseCode 枚举(完整)
| 值 | 说明 |
|---|---|
Success = 0 | 成功 |
BusinessException = 1001 | 业务异常 |
Failed = 1002 | 失败 |
UnknownError = 1007 | 未知错误 |
ServerUnknownError = 999 | 服务端未知错误 |
AuthenticationFailed = 10000 | 认证失败 |
NoPermission = 10001 | 无权限 |
RefreshTokenError = 10100 | 刷新令牌错误 |
NotFound = 10020 | 资源不存在(描述"资源不存在") |
ParameterError = 10030 | 参数错误(描述"参数错误") |
TokenInvalidation = 10040 | 令牌失效(描述"令牌失效") |
TokenExpired = 10050 | Token 过期 |
RepeatField = 10060 | 字段重复 |
Inoperable = 10070 | 不可操作 |
ManyRequests = 10140 | 请求过多 |
BadFileToken = 40001 | 文件令牌错误 |
统一响应 ApiResponse
public static ApiResponse Ok(string? message = "操作成功");
public static ApiResponse Failed(string? message = "操作失败");
public static ApiResponse New(ResponseCode errorCode, string? message);
public static ApiResponse<T> Ok<T>(T data, string? message = "操作成功") where T : class;
public static ApiResponse<T> Failed<T>(string? message = "操作成功") where T : class;
return Ok(ApiResponse.Ok(data));
return BadRequest(ApiResponse.Failed("错误信息"));
throw new BusinessException(ResponseCode.BusinessException, "业务错误");
授权与认证
认证模式
public enum AuthMode { Jwt = 0, OpenIddict = 1 }
JwtSettings 模型
public class JwtSettings
{
public string Audience { get; }
public DateTime ExpiresTime { get; set; } // 默认 86400 秒(1 天)
public string Issuer { get; }
public SecurityKey SecurityKey { get; }
public TokenValidationParameters TokenValidationParameters { get; }
}
由配置构造(典型键:
JwtSettings:Issuer/JwtSettings:Audience/JwtSettings:ExpiresTime;密钥经SecurityKey注入)。具体配置键名以JwtSettings的绑定为准。
CookieJwtBearerHandler
CookieJwtBearerHandler : JwtBearerHandler,支持三种 Token 来源(按顺序):
- Query(
?access_token=...)——仅当请求路径以/hubs开头时(SignalR Hub 等无法设请求头的场景); - Authorization header——标准
Bearer; - Cookie(
access_token)——浏览器会话。
要求 JWT alg 为 HS256,验证参数取自 JwtSettings.TokenValidationParameters。
KitAuthorize 特性
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class KitAuthorizeAttribute(string permission, string module) : Attribute, IAsyncAuthorizationFilter
{
public string Permission { get; set; }
public string Module { get; set; }
}
先校验 ValidTokenRequirement(失败 → UnauthorizedResult),再校验 ValidPermissionRequirement(Permission)(失败 → ForbidResult)。
[KitAuthorize("Article.Create", "CmsKit")]
public IActionResult Create() { /* ... */ }
权限存储
public interface IPermissionStore
{
Task<bool> CheckPermissionAsync(string permission);
Task<bool> CheckAccessTokenAsync(string accessToken);
}
注意:源码中只有
IPermissionStore,没有IPermissionChecker/PermissionChecker。
授权结果处理
KitAuthorizationMiddlewareResultHandler : IAuthorizationMiddlewareResultHandler 会把未登录 → ResponseCode.AuthenticationFailed(401)、Token 失效 → TokenExpired(401)、无权限 → NoPermission(403),从而让 API 响应与 ResponseCode 体系一致。
中间件
加密中间件
public class EncryptionSettings
{
public bool Enable { get; set; } = false;
public string? EncryptionKey { get; set; }
public string? EncryptionIV { get; set; }
}
EncryptionMiddleware 在 Enable==true 时,将 JSON 响应体用 CryptoUtil.Encrypt 加密后包成 {"data": "<密文>"}。注册方式:
// 注意:没有 UseEncryption() 扩展,需显式 UseMiddleware
app.UseMiddleware<EncryptionMiddleware>();
{
"Encryption": { "Enable": true, "EncryptionKey": "your-key", "EncryptionIV": "your-iv" }
}
源码中没有 app.UseEncryption() 扩展方法,只有 EncryptionMiddleware 类本身;请使用 app.UseMiddleware<EncryptionMiddleware>()。
Basic 认证(保护 Swagger 等)
app.UseBasicAuthentication();
public class BasicAuthenticationOption : AuthenticationSchemeOptions
{
public bool Enable { get; set; } = false;
public List<string>? ProtectPaths { get; set; }
public string? Realm { get; set; }
public string? UserName { get; set; }
public string? UserPassword { get; set; }
}
仅当 Enable==true 且 ProtectPaths 非空时,才对匹配路径启用 Basic 认证。
{
"Basic": { "Enable": true, "ProtectPaths": ["/swagger"], "UserName": "admin", "UserPassword": "123456" }
}
IP 限流
builder.Services.AddIpRateLimiting(builder.Configuration);
底层绑定 AspNetCoreRateLimit 的 IpRateLimitOptions / IpRateLimitPolicies(配置节 IpRateLimiting)。没有 FreeKit 自定义的限流选项类,参数含义与默认值以 AspNetCoreRateLimit 为准。
过滤器与特性
SensitiveDataAttribute(数据脱敏)
[AttributeUsage(AttributeTargets.Property)]
public class SensitiveDataAttribute : Attribute
{
public bool IsSensitive { get; set; } = false; // 唯一属性
}
public class UserDto
{
[SensitiveData(IsSensitive = true)]
public string Phone { get; set; } // 序列化时按规则脱敏
}
SensitiveDataAttribute 只有 IsSensitive 一个属性,没有 Mask 之类的自定义掩码属性。
RecaptchaVerifyActionFilter(reCAPTCHA)
[ServiceFilter(typeof(RecaptchaVerifyActionFilter))]
[HttpPost]
public IActionResult Submit(SubmitRequest request) { /* 自动验证 reCAPTCHA */ }
builder.Services.AddGooglereCaptchav3(builder.Configuration);
// 选项类 GooglereCAPTCHAOptions:Enabled(默认 false)、HeaderKey("Google-RecaptchaToken")、Version(V3)、MinimumScore(0.9F)
异常通知 ExceptionNotifier
支持三通道告警(邮件 / 飞书 / 企业微信),由 IExceptionNotifier.NotifyAsync(Exception) 触发。
public class ExceptionNotifyOptions // SectionName = "ExceptionNotify"
{
public bool Enabled { get; set; } = false;
public MailNotifyOptions Mail { get; set; } // Enabled(默认 false)、MailTo
public WebhookChannelOptions Feishu { get; set; } // Enabled(默认 false)、WebhookUrl、Secret
public WebhookChannelOptions WeCom { get; set; } // Enabled(默认 false)、WebhookUrl、Secret
}
源码中没有名为 ExceptionNotifyFilter 的过滤器类,异常通知能力由 IExceptionNotifier / ExceptionNotifier 提供(通常由全局异常过滤器在捕获后调用)。
安全工具
AES 加密
public static class AESUtil
{
public static string Encrypt(string source, string key, string iv = "",
PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.ECB);
public static string Decrypt(string source, string key, string iv = "",
PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC);
// 另提供接受 AESInput 对象的重载
}
Encrypt 默认 CipherMode.ECB,而 Decrypt 默认 CipherMode.CBC——加解密默认的 mode 不一致,调用时务必显式指定一致的 mode 与 iv。
DES 加密
public class DESUtil
{
public static string Encrypt(string sourceString, string Key, string Iv = "12345678",
PaddingMode padding = PaddingMode.PKCS7, CipherMode mode = CipherMode.CBC);
public static string Decrypt(string encryptedString, string Key, string Iv = "12345678", ...);
}
Key必须为 8 位(不足抛ArgumentException,超长截断);Iv默认"12345678"。
SM4 国密
public class SM4Util
{
public static byte[] GenerateKey();
public static byte[] Encrypt_CBC_Padding(byte[] key, byte[] iv, byte[] data);
public static byte[] Decrypt_CBC_Padding(byte[] key, byte[] iv, byte[] cipherText);
public static byte[] Encrypt_ECB_Padding(string key, string data); // 也提供 byte[]/NoPadding 重载
public static byte[] Decrypt_ECB_Padding(string key, string cipherText, Base64OrHexEnum type = Base64OrHexEnum.Hex);
}
注意:CBC 系列方法参数为
byte[](密钥/IV/数据),而非字符串。
MD5 哈希
public class Md5Util
{
public static string Md5Hash(string source); // 32 位大写
public static bool VerifyMd5(string mdPwd, string source); // 大小写不敏感比较
public static string Md5(string soureString, MD5Digit mD5Digit = MD5Digit.Digit32);
public static string Md5ToBase64(string s, MD5Digit mD5Digit = MD5Digit.Digit32);
}
// MD5Digit : Digit16 = 16, Digit32 = 32
Md5与Md5Hash两套方法都存在;Md5Hash/VerifyMd5是推荐的确定性哈希(可作缓存键)写法。
Base64 与文件
ToolHelper.Base64Encode(content); // UTF8 → Base64
ToolHelper.Base64Decode(content); // Base64 → UTF8
// 另含:FileToHashBase64String / GetFileMD5Hash / GetFileSHA256Hash 等
数据脱敏
var masked = MaskHelper.MaskPhoneNumber("13812345678"); // "138****5678"
CryptoUtil(遗留)
CryptoUtil.Encrypt/Decrypt/EncryptRequestData/ImgDecryptApi 含硬编码密钥,仅用于特定历史兼容,建议新代码勿依赖。
DTO 基类
ApiResponse
public class ApiResponse : IApiResponse
{
public int Code { get; set; }
public string? Message { get; set; }
public static ApiResponse Ok(string? message = "操作成功");
public static ApiResponse Failed(string? message = "操作失败");
public static ApiResponse New(ResponseCode errorCode, string? message);
public static ApiResponse<T> Ok<T>(T data, string? message = "操作成功") where T : class;
public static ApiResponse<T> Failed<T>(string? message = "操作成功") where T : class;
}
public class ApiResponse<T> : ApiResponse, IApiResponse<T> where T : class
{
public T Data { get; set; }
}
PageQuery
public class PageQuery : BasePagingInfo, ISortedResultRequest, IValidatableObject
{
public const int MaxPageSize = 50;
// 默认:PageNumber=1, PageSize=30, Sorting="Id desc", IsQueryCount=true
public string? Sorting { get; set; }
public bool? IsQueryCount { get; set; }
}
验证规则:PageNumber >= 1;PageSize >= 1 且 PageSize <= 50。分页列表结果统一返回 PagedResultDto<T>(来自 IGeekFan.FreeKit.Extras.Dto)。
public class ArticleListQuery : PageQuery
{
public string? Keyword { get; set; }
}
[HttpGet]
public async Task<PagedResultDto<ArticleDto>> GetList(ArticleListQuery query)
=> await _articleService.GetListAsync(query);
其它
ISortedResultRequest:string? Sorting { get; set; }(支持"Name ASC, Age DESC"风格)。EnumDto.FromEnum<T>():把枚举转为List<EnumDto>(Value/Label)。
扩展方法
分页(E 静态类)
public static Task<List<TEntity>> ToPagerListAsync<TEntity>(this ISelect<TEntity> source, PageQuery pageQuery);
public static List<TEntity> ToPagerList<TEntity>(this ISelect<TEntity> source, PageQuery pageQuery);
public static ISelect<TEntity> ApplyPage<TEntity>(this ISelect<TEntity> source, PageQuery pageQuery);
IsQueryCount==false 时设 Count=-1 并仅 Skip/Take。
文件(IFileProvider / IFileInfo)
var files = fileProvider.GetFilesRecursively("Templates"); // IEnumerable<(string, IFileInfo)>
var content = await fileInfo.ReadAsStringAsync(Encoding.UTF8);
CAP 分布式事务
// 开启事务(返回 MySqlCapTransaction,绑定 FreeSql 事务)
ICapTransaction tx = unitOfWork.BeginTransaction(publisher, autoCommit: false);
// 提交:先 unitOfWork.Commit() 再 tx.Flush()
tx.Commit(unitOfWork);
// 服务注册
services.AddKitCap(configuration, assemblies); // 绑定 ConnectionStrings,注册 MySQL+RabbitMQ 等
当前用户扩展(CurrentUserExtensions)
CurrentUser.FindUserId(); // Guid(找不到返回 Guid.Empty)
CurrentUser.FindUserIdThrowException(); // 未登录抛异常
CurrentUser.IsAdmin(); // IsInRole("Admin")
CurrentUser.IsImpersonating(); // 是否处于模拟登录
CurrentUser.FindImpersonatorUserId(); // 模拟者 Id
CurrentUser.FindImpersonatorUserName();
CurrentUser.FindOriginalTenantId(); // 模拟前的原始租户
CurrentUser.GetActorDisplayName();
Autofac 领域服务注册
containerBuilder.RegisterDomainServices(typeof(SomeModule).Assembly); // 批量注册 IDomainService
依赖关系
Infrastructure 是 BuildingBlocks 的基础;Web 与 Auth.Client 建立在它之上(见 building-blocks 总览)。
相关文档
- BuildingBlocks 总览
- Web 启动层
- Auth Client
- Extras 扩展包 —
PagedResultDto、仓储、ICurrentUser等底层定义 - 共享功能