MiniApi.Framework.Core
1.0.0
dotnet add package MiniApi.Framework.Core --version 1.0.0
NuGet\Install-Package MiniApi.Framework.Core -Version 1.0.0
<PackageReference Include="MiniApi.Framework.Core" Version="1.0.0" />
<PackageVersion Include="MiniApi.Framework.Core" Version="1.0.0" />
<PackageReference Include="MiniApi.Framework.Core" />
paket add MiniApi.Framework.Core --version 1.0.0
#r "nuget: MiniApi.Framework.Core, 1.0.0"
#:package MiniApi.Framework.Core@1.0.0
#addin nuget:?package=MiniApi.Framework.Core&version=1.0.0
#tool nuget:?package=MiniApi.Framework.Core&version=1.0.0
MiniApi.Framework.Core 使用教程(完整版)
本教程面向下游业务 API 项目(如Test.Sample.Api)。只要项目引用 MiniApi.Framework.Core,即可用极少的代码复用一套完整的迷你 API 框架能力:模块化端点发现、统一响应、JWT / Basic / 签名多套认证、对象映射、缓存抽象、Elasticsearch、声明式定时任务、基于队列的异步文本日志。
文中所有示例均可在本目录(
Test.Sample.Api)找到对应的真实可运行代码。
目录
- 快速开始
- 模块化:IMiniModule
- 统一响应:ApiResult
- 当前用户:ICurrentUser
- 缓存抽象:ICacheProvider
- Elasticsearch
- 对象映射:Mapster
- 认证与安全层
- 8.1 JWT(默认启用)
- 8.2 Basic 认证层
- 8.3 签名 + 时间戳认证
- 定时任务:AddJob<T>
- 文本日志:TxtLogger
- appsettings.json 完整配置参考
- 本示例项目文件清单
- 注意事项
1. 快速开始
一个全新的 API 项目,接入框架只需要 两行:
using Test.Sample.Api.Modules.Test;
using MiniApi.Framework;
var builder = WebApplication.CreateBuilder(args);
// ① builder 阶段:注册框架全部服务(选项绑定 / JWT / Swagger / 模块化 / 缓存 / 日志 …)
builder.Services.AddMiniFramework(builder.Configuration);
var app = builder.Build();
// ② app 阶段:装配中间件管道 + 自动映射所有模块端点 + 启动定时任务 + 初始化文本日志
app.UseMiniFramework();
app.Run();
AddMiniFramework 与 UseMiniFramework 是框架的唯二入口,二者分别在 builder 阶段与 app.Build() 之后调用。任何附加能力(自定义用户解析、定时任务等)都写在两行之间。
2. 模块化:IMiniModule
框架通过自动发现把实现了 IMiniModule 的类注册为模块,并以统一的路由前缀挂载端点,无需手动 MapGet。
写一个模块
using MiniApi.Framework.Framework.Modular;
using MiniApi.Framework.Framework.Responses;
public class TestModule : IMiniModule
{
// 模块名(用于 Swagger 标签与注册日志)
public string Name => "Test";
// 路由前缀:默认 /api/{Name.ToLowerInvariant()},即 /api/test
// 也可显式覆盖,例如 "/api/user/address"
public string? RoutePrefix => "/api/test";
// builder 阶段调用:注册本模块需要的服务(仓储 / HttpClient 等)
public void RegisterServices(IServiceCollection services, IConfiguration configuration) { }
// 映射端点。路径均为“相对路径”,前缀由框架统一拼接。
public void MapEndpoints(IEndpointRouteBuilder endpoints)
{
endpoints.MapGet("/hello", () => ApiResult.Ok("hello"))
.AllowAnonymous() // 匿名可访问
.WithSummary("匿名示例接口");
endpoints.MapGet("/me", (ICurrentUser user) => ApiResult.Ok(new { user.UserId }))
.RequireAuthorization() // 需要 JWT 登录
.WithSummary("受保护接口");
}
}
关键约定
- 自动发现:只要
IMiniModule实现类位于入口程序集,AddMiniFramework会扫描并调用RegisterServices,UseMiniFramework内部调用MapMiniModules()自动挂载(你不需要手动调用MapMiniModules)。 - 模块必须有无参构造函数:框架先用无参构造创建临时实例触发
RegisterServices与路由注册;真实请求时端点 lambda 内的模块依赖由 DI 注入。 - 依赖注入到端点:在 lambda 第一个参数写具体类型(如
(ICurrentUser user, ICacheProvider cache)),框架自动从 DI 解析,无需自己new。 - 一个程序集可以有多个模块,各自独立维护一组端点、独立路由前缀。
3. 统一响应:ApiResult
所有业务接口统一返回 { "Code": 200, "Msg": "ok", "result": ... }。HTTP 状态码始终为 200(除非框架级错误),业务状态用 Code 表达。
// 成功,带数据
return ApiResult.Ok(new { Id = 1, Name = "商品" });
// 成功,无数据(result 字段整体省略)
return ApiResult.OkEmpty();
// 业务错误(Code 仍为 200,Msg 带文案);errorDetail 可传明细数组
return ApiResult.Error("库存不足", new[] { new { Sku = "A1", Left = 0 } });
// 输入校验错误(字段级明细)
return ApiResult.Validation(new List<FieldError>
{
new("Username", "字段必填")
});
分页结果使用 PagedResult<T>,字段固定小写:
var paged = PagedResult<Order>.Of(pageIndex: 1, pageSize: 20, total: 100, items: orders);
return ApiResult.Ok(paged);
// → { "Code":200, "Msg":"ok", "result": { "pageindex":1, "pagesize":20, "total":100, "items":[ ... ] } }
命名空间:MiniApi.Framework.Framework.Responses。
4. 当前用户:ICurrentUser
端点注入 ICurrentUser 即可读取登录用户信息,无需从 HttpContext 重复取值。
endpoints.MapGet("/me", (ICurrentUser user) => ApiResult.Ok(new
{
user.UserId,
user.UserName,
user.IsAuthenticated,
user.Roles,
IsAdmin = user.IsInRole("admin"),
// 任意自定义 claim 直接按类型读取,无需改 Core
Phone = user["phone"]
})).RequireAuthorization();
接口成员:IsAuthenticated / UserId / UserName / Roles / IsInRole(role) / 索引器 user[claimType] / Claims(全部 claim 快照)。
默认实现与可替换性
- 默认实现
HttpCurrentUser从 JWT 的sub/NameIdentifier取UserId,从ClaimTypes.Role取角色。 - 当新项目 token 的 claim 命名不同(如
uid/user_id)时,有三种最小改动方式:
方式一:读自定义 claim(零改动) —— 直接用 user["uid"] 读取,无需改任何代码。
方式二:继承重写(推荐) —— 继承 HttpCurrentUser,只重写差异的虚方法:
using System.Security.Claims;
using MiniApi.Framework.Framework.Auth;
public class DemoCurrentUser : HttpCurrentUser
{
public DemoCurrentUser(IHttpContextAccessor accessor) : base(accessor) { }
protected override string? ResolveUserId(ClaimsPrincipal principal)
{
var baseId = base.ResolveUserId(principal); // 优先沿用框架默认
if (!string.IsNullOrWhiteSpace(baseId)) return baseId;
return principal.FindFirst("uid")?.Value // 再取本项目差异 claim
?? "demo-override-active"; // 兜底(演示用)
}
}
在 Program.cs 中用一行覆盖默认实现(与调用顺序无关,稳定生效):
builder.Services.AddMiniFramework(builder.Configuration);
builder.Services.ReplaceCurrentUser<DemoCurrentUser>(); // 一行覆盖
方式三:彻底自定义富接口 —— 业务项目定义 interface IMyCurrentUser : ICurrentUser(带租户/部门/邮箱等字段),自行实现并 ReplaceCurrentUser<MyUser>(),在需要处注入 IMyCurrentUser。
示例文件:
Modules/Test/DemoCurrentUser.cs、Modules/Test/TestModule.cs的/whoami与/me端点。
5. 缓存抽象:ICacheProvider
业务只依赖 ICacheProvider,底层按配置在 Memory / Redis 间切换,代码不变。
endpoints.MapGet("/cache/set", async (ICacheProvider cache, string key, string value) =>
{
await cache.SetStringAsync(key, value, TimeSpan.FromMinutes(5));
return ApiResult.Ok(new { Provider = cache.Name, Key = key });
}).AllowAnonymous();
endpoints.MapGet("/cache/get", async (ICacheProvider cache, string key) =>
{
var v = await cache.GetStringAsync(key);
return ApiResult.Ok(new { Provider = cache.Name, Key = key, Value = v });
}).AllowAnonymous();
切换 provider 只改 appsettings 的 Cache:Provider(Memory / Redis),无需改代码。配置见 第 11 节。
6. Elasticsearch
框架对 ES 采用安全默认 + 优雅降级:
Elasticsearch:Enabled=false时,框架注册的是占位工厂DisabledElasticsearchClientFactory,不建立任何连接;业务模块注入IElasticsearchClientFactory后先判IsEnabled即可优雅跳过检索逻辑。Enabled=true时才注册真实工厂;每个集群可独立配置EnableAuth(用户名 + 密码 Basic 登录)。启用鉴权却缺少Username时,启动即抛明确异常(fail-fast)。
endpoints.MapGet("/search", async (IElasticsearchClientFactory esFactory) =>
{
if (!esFactory.IsEnabled)
return ApiResult.Error("ES 未启用");
var client = esFactory.DefaultClient; // 默认集群
// 或 esFactory.GetClient("logs"); // 按名取集群
// ...
}).RequireAuthorization();
EnableAuth 用法(appsettings):
{
"Elasticsearch": {
"Enabled": true,
"Clusters": [
{
"Name": "default",
"Url": "http://localhost:9200",
"EnableAuth": true,
"Username": "elastic",
"Password": "你的密码",
"DefaultIndex": "products"
}
]
}
}
7. 对象映射:Mapster
AddMiniFramework 已注入 Mapster 并自动扫描程序集内实现 IRegister 的映射配置。业务只需:
- 在业务项目里写一个
IRegister实现类定义映射规则; - 端点注入
IMapper(注意命名空间是MapsterMapper)使用。
定义映射规则(自动被发现)
using Mapster;
using Test.Sample.Api.Modules.Test.Dtos;
using Test.Sample.Api.Modules.Test.Entities;
namespace Test.Sample.Api.Modules.Test.Mapping;
public class TestMappingRegister : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<Product, ProductDto>()
.Map(dest => dest.CreatedAt, src => src.CreatedAt.ToString("yyyy-MM-dd HH:mm"));
}
}
端点中使用
endpoints.MapGet("/map/product", (MapsterMapper.IMapper mapper) =>
{
var product = new Product { Id = 1, Name = "测试商品", Price = 199m, CreatedAt = DateTime.Now };
var dto = mapper.Map<ProductDto>(product); // 自动套用上面的规则
return ApiResult.Ok(dto);
}).AllowAnonymous();
注:Mapster v10 的
IMapper/Mapper位于MapsterMapper命名空间;AddMapster()无程序集扫描重载,框架已替你TypeAdapterConfig.GlobalSettings.Scan(...)扫描入口程序集与 Core 程序集。
8. 认证与安全层
8.1 JWT(默认启用)
AddMiniFramework 默认启用 JWT Bearer 认证,appsettings 的 Jwt 节点提供 Issuer / Audience / SecretKey。只要各项目的 Jwt 配置一致,同一份令牌即可跨项目解析同一用户(无需共享 session / 数据库)。
- 受保护端点:
.RequireAuthorization() - 生成令牌:注入
ITokenService(框架已注册)
endpoints.MapGet("/me", (ICurrentUser user) => ApiResult.Ok(new { user.UserId }))
.RequireAuthorization();
8.2 Basic 认证层
作为接口级额外安全层:标记了 RequireBasicAuth 的端点,必须携带 Authorization: Basic base64(user:pass) 且命中账号列表,否则返回 401。
endpoints.MapGet("/secure", (HttpContext ctx) =>
{
var user = ctx.Items["BasicAuthUser"] as string ?? "unknown";
return ApiResult.Ok(new { Layer = "Basic", AuthenticatedAs = user });
}).AllowAnonymous().RequireBasicAuth(); // 注意:先用 AllowAnonymous 关闭 JWT,再加 Basic 层
配置(appsettings):
{
"BasicAuth": {
"Enabled": false,
"Realm": "MiniApi",
"Accounts": [
{ "Username": "apiuser", "Password": "apipass" }
]
}
}
BasicAuth:Enabled=false 时过滤器直接放行。生产环境建议密码走环境变量 / 密钥管理。
8.3 签名 + 时间戳认证
适合服务端到服务端 / 开放 API 的场景:调用方用 Secret 对所有请求参数(含 timespan)做签名,经 url 参数 sign 传给后台;后台用相同算法重算比对,并校验 timespan 是否在有效窗口内。
endpoints.MapGet("/sign/echo", (HttpContext ctx) =>
{
// 走到这里说明签名已通过校验
return ApiResult.Ok(new { Verified = true });
}).AllowAnonymous().RequireSignAuth();
配置(appsettings):
{
"SignAuth": {
"Enabled": true,
"Secret": "demo-sign-secret",
"TimestampToleranceSeconds": 300,
"Algorithm": "HmacSha256"
}
}
客户端签名规则(必须与后台一致):
- 收集所有 query 参数,排除
sign自身; - 按 key 不区分大小写排序,拼接为
k1=v1&k2=v2&...; - 按
Algorithm求摘要:HmacSha256:HMAC-SHA256(Secret 作为 key, message)→ hex 小写;Md5:MD5(message + Secret)→ hex 小写;
- 把
sign与timespan一起放进请求 query。
C# 示例:
using System.Security.Cryptography;
using System.Text;
string ComputeSign(Dictionary<string, string> p, string secret, bool md5 = false)
{
var msg = string.Join("&",
p.OrderBy(k => k.Key, StringComparer.OrdinalIgnoreCase)
.Select(k => $"{k.Key}={k.Value}"));
if (md5)
{
using var m = MD5.Create();
return Convert.ToHexString(m.ComputeHash(Encoding.UTF8.GetBytes(msg + secret))).ToLowerInvariant();
}
using var h = new HMACSHA256(Encoding.UTF8.GetBytes(secret));
return Convert.ToHexString(h.ComputeHash(Encoding.UTF8.GetBytes(msg))).ToLowerInvariant();
}
// 调用
var ts = DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
var p = new Dictionary<string, string> { ["name"] = "x", ["timespan"] = ts };
p["sign"] = ComputeSign(p, "demo-sign-secret");
var query = string.Join("&", p.Select(k => $"{k.Key}={Uri.EscapeDataString(k.Value)}"));
// GET /api/...?name=x×pan=...&sign=...
Python 示例:
import hashlib, hmac, time, urllib.parse
def sign(params: dict, secret: str, algo="hmac"):
items = sorted(params.items(), key=lambda kv: kv[0].lower())
msg = "&".join(f"{k}={v}" for k, v in items)
if algo == "md5":
return hashlib.md5((msg + secret).encode()).hexdigest().lower()
return hmac.new(secret.encode(), msg.encode(), hashlib.sha256).hexdigest().lower()
ts = str(int(time.time()))
params = {"name": "x", "timespan": ts}
params["sign"] = sign(params, "demo-sign-secret")
url = "http://localhost:5200/api/...?" + urllib.parse.urlencode(params)
timespan支持秒(10 位)与毫秒(13 位);偏差超过TimestampToleranceSeconds即失效。
9. 定时任务:AddJob<T>
引用项目只需一行声明式注册任务类 + 周期,框架在 UseMiniFramework() 阶段自动完成:DI 注册 → 构建调度 → 启动 → 挂关闭钩子。无需任何集中式注册清单。
任务类(普通 POCO)
约定暴露 Task RunAsync() 方法(默认反射调用,零侵入);构造函数可注入依赖。
using Microsoft.Extensions.Logging;
using MiniApi.Framework.Framework.Caching;
public class HeartbeatJob
{
private readonly ILogger<HeartbeatJob> _logger;
private readonly ICacheProvider _cache;
public HeartbeatJob(ILogger<HeartbeatJob> logger, ICacheProvider cache)
{
_logger = logger;
_cache = cache;
}
public async Task RunAsync()
{
var now = DateTime.UtcNow;
await _cache.SetStringAsync("heartbeat:last", now.ToString("o"), TimeSpan.FromMinutes(2));
_logger.LogInformation("[HeartbeatJob] 心跳 @ {Time}", now);
}
}
注册(Program.cs,builder 阶段)
builder.Services.AddMiniFramework(builder.Configuration);
// 约定 RunAsync():零侵入
builder.Services.AddJob<HeartbeatJob>(
cfg => cfg.Every(1).Minutes(),
description: "测试项目心跳任务(演示 AddJob 声明式注册)");
// 业务方法不叫 RunAsync 时,用 Func<T, Task> 重载显式指定
builder.Services.AddJob<ReportTask>(
cfg => cfg.Everyday().At(2, 0),
t => t.DoWorkAsync(),
name: "Report.Daily");
- 周期语法来自 FluentScheduler:
Every(30).Seconds()、Every(1).Minutes()、Everyday().At(2, 0)等。 - 任务名默认取类型名,可用
name:/description:参数覆盖(供管理 API 展示)。 - 启动完全由
UseMiniFramework()接管,你不需要任何Register/Start/Stop。
管理 API(主项目 MiniApi.Framework)
主项目内置 SystemJobs 模块,提供任务查看 / 立即触发等管理能力(路由 /api/systemjobs)。
示例文件:
Modules/Test/Jobs/HeartbeatJob.cs、Program.cs中的AddJob、模块内/job/heartbeat校验端点。
10. 文本日志:TxtLogger
基于 System.Threading.Channels 有界队列的异步文本日志。业务线程调用 .Info/.Warn/.Error 时仅同步入队即返回(零阻塞),后台单消费者异步落盘;应用停止时自动排空队列,保证不丢日志。
静态用法(推荐,无需注入)
using MiniApi.Framework.Framework.TxtLogger;
TxtLogger.Info("处理订单 {0} 完成", orderId); // 注:当前实现为简单字符串拼接
TxtLogger.Warn("库存偏低");
TxtLogger.Error(ex, "扣减库存失败"); // 记录完整异常堆栈
注入式用法(可选)
需要构造函数注入或单元测试 mock 时,仍可注入 ITxtLogger:
public class MyService(ITxtLogger log)
{
public void Do() => log.Info("来自注入式 ITxtLogger");
}
配置(appsettings 的 TxtLogger 节点)
{
"TxtLogger": {
"Enabled": true,
"Directory": "logs",
"FileNameFormat": "{0:yyyy-MM-dd}.txt",
"SplitByLevel": false,
"QueueCapacity": 10000,
"FlushBatchSize": 50,
"RetentionDays": 7,
"TimestampFormat": "yyyy-MM-dd HH:mm:ss.fff"
}
}
- 日志文件按天轮转(默认
logs/2026-09-13.txt),格式:[2026-09-13 20:21:45.187] [INFO] 处理订单 123 完成。 Enabled=false时所有方法 no-op;框架未初始化时也安全 no-op(绝不抛异常)。- 调优点:
FlushBatchSize控制批量落盘频率(应用停止会强制 flush 剩余内容);QueueCapacity为突发缓冲,超出时丢弃最旧条目以保护业务线程。
示例文件:模块内
/log端点演示静态调用;日志落盘于运行目录logs/。
11. appsettings.json 完整配置参考
{
"Database": {
"Connections": [
{
"ConfigId": "default",
"DbType": "Sqlite",
"ConnectionString": "DataSource=./app.db;",
"IsAutoCloseConnection": true
}
]
},
"Jwt": {
"Issuer": "MiniApi.Framework",
"Audience": "MiniApi.Clients",
"SecretKey": "请替换为至少 32 字节的随机密钥",
"AccessTokenExpirationMinutes": 60,
"RefreshTokenExpirationDays": 7
},
"Elasticsearch": {
"Enabled": false,
"Clusters": [
{
"Name": "default",
"Url": "http://localhost:9200",
"EnableAuth": false,
"DefaultIndex": "products"
}
]
},
"Cache": {
"Enabled": false,
"Provider": "Memory",
"Redis": {
"ConnectionString": "127.0.0.1:6379",
"Password": null,
"DefaultDatabase": -1,
"AbortOnConnectFail": false,
"ConnectTimeoutSeconds": 10
}
},
"BasicAuth": {
"Enabled": false,
"Realm": "MiniApi",
"Accounts": [
{ "Username": "apiuser", "Password": "apipass" }
]
},
"SignAuth": {
"Enabled": false,
"Secret": "demo-sign-secret",
"TimestampToleranceSeconds": 300,
"Algorithm": "HmacSha256"
},
"TxtLogger": {
"Enabled": true,
"Directory": "logs",
"FileNameFormat": "{0:yyyy-MM-dd}.txt",
"SplitByLevel": false,
"QueueCapacity": 10000,
"FlushBatchSize": 50,
"RetentionDays": 7,
"TimestampFormat": "yyyy-MM-dd HH:mm:ss.fff"
}
}
安全默认:所有鉴权(
BasicAuth/SignAuth)与 Elasticsearch 默认关闭,开启需显式配置;JWT 提供开发兜底密钥,生产务必替换为环境变量注入的真实密钥。
12. 本示例项目文件清单
Test.Sample.Api 已覆盖上述全部能力,可作为你新建项目的模板:
| 文件 | 演示内容 |
|---|---|
Program.cs |
两行接入 + ReplaceCurrentUser + AddJob 声明式注册 |
Modules/Test/TestModule.cs |
模块端点:匿名 / 受保护 / 缓存 / Basic / 签名 / Mapster / Job 校验 / 静态日志 |
Modules/Test/DemoCurrentUser.cs |
继承 HttpCurrentUser 重写 ResolveUserId 的最小改动示例 |
Modules/Test/Jobs/HeartbeatJob.cs |
RunAsync() 约定 + 依赖注入的定时任务 |
Modules/Test/Mapping/TestMappingRegister.cs |
IRegister 映射规则(自动被发现) |
Modules/Test/Entities/Product.cs、Dtos/ProductDto.cs |
映射用实体 / DTO |
appsettings.json |
上述全部配置节点 |
13. 注意事项
- 模块自动发现范围:只扫描入口程序集(即 Web 项目本身)。若模块类放在独立类库,需确保该类库被 Web 项目引用并打入入口程序集。
- JWT 401 的响应形态:JWT 鉴权失败(未带 / 过期令牌)走 ASP.NET 默认的
ProblemDetails响应体(非ApiResult信封),这是框架已知限制;而 Basic / 签名认证失败统一用ApiResult(HTTP 200,Code=401)。 ReplaceCurrentUser调用时机:写在AddMiniFramework之后即可,内部用RemoveAll保证与顺序无关。TxtLogger实时性权衡:未达FlushBatchSize时日志在内存缓冲,进程被强杀可能丢失少量最新日志(正常停止会 flush)。需要更强实时性可调小FlushBatchSize。- Mapster
IMapper命名空间:注入时用MapsterMapper.IMapper,映射配置类需实现Mapster.IRegister。 - 多项目共享用户:保证各项目的
Jwt:Issuer/Jwt:Audience/Jwt:SecretKey完全一致,令牌即可跨项目通用。
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"Database": {
"Connections": [
{
"ConfigId": "default",
"DbType": "Sqlite",
"ConnectionString": "DataSource=./erp_sample.db;",
"IsAutoCloseConnection": true
}
]
},
"Jwt": {
"Issuer": "MiniApi.Framework",
"Audience": "MiniApi.Clients",
"SecretKey": "please-replace-this-with-a-32byte-random-secret-key-for-prod-env",
"AccessTokenExpirationMinutes": 60,
"RefreshTokenExpirationDays": 7
},
"Elasticsearch": {
"Enabled": false,
"Clusters": [
{
"Name": "default",
"Url": "http://localhost:9200",
"EnableAuth": false,
"DefaultIndex": "***",
"Username": "***",
"Password": "***"
}
]
},
"Cache": {
"Enabled": false,
"Provider": "Memory",
"Redis": {
"ConnectionString": "127.0.0.1:6379",
"Password": null,
"DefaultDatabase": -1,
"AbortOnConnectFail": false,
"ConnectTimeoutSeconds": 10
}
},
"BasicAuth": {
"Enabled": false,
"Realm": "MiniApi",
"Accounts": [
{ "Username": "apiuser", "Password": "apipass" }
]
},
"SignAuth": {
"Enabled": true,
"Secret": "demo-sign-secret",
"TimestampToleranceSeconds": 300,
"Algorithm": "HmacSha256"
},
"TxtLogger": {
"Enabled": true,
"Directory": "logs",
"FileNameFormat": "{0:yyyy-MM-dd}.txt",
"SplitByLevel": false,
"QueueCapacity": 10000,
"FlushBatchSize": 50,
"RetentionDays": 7,
"TimestampFormat": "yyyy-MM-dd HH:mm:ss.fff"
}
}
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Elastic.Clients.Elasticsearch (>= 8.15.10)
- FluentScheduler (>= 6.0.0)
- Mapster (>= 10.0.12)
- Mapster.DependencyInjection (>= 10.0.12)
- Microsoft.AspNetCore.Authentication.JwtBearer (>= 10.0.0)
- MiniValidation (>= 0.10.0)
- SqlSugarCore (>= 5.1.4.156)
- StackExchange.Redis (>= 3.2.0)
- Swashbuckle.AspNetCore (>= 7.2.0)
- System.IdentityModel.Tokens.Jwt (>= 8.2.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.0 | 73 | 9/13/2026 |