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
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="MiniApi.Framework.Core" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="MiniApi.Framework.Core" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="MiniApi.Framework.Core" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add MiniApi.Framework.Core --version 1.0.0
                    
#r "nuget: MiniApi.Framework.Core, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package MiniApi.Framework.Core@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=MiniApi.Framework.Core&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=MiniApi.Framework.Core&version=1.0.0
                    
Install as a Cake Tool

MiniApi.Framework.Core 使用教程(完整版)

本教程面向下游业务 API 项目(如Test.Sample.Api)。只要项目引用 MiniApi.Framework.Core,即可用极少的代码复用一套完整的迷你 API 框架能力:模块化端点发现、统一响应、JWT / Basic / 签名多套认证、对象映射、缓存抽象、Elasticsearch、声明式定时任务、基于队列的异步文本日志。

文中所有示例均可在本目录(Test.Sample.Api)找到对应的真实可运行代码。


目录

  1. 快速开始
  2. 模块化:IMiniModule
  3. 统一响应:ApiResult
  4. 当前用户:ICurrentUser
  5. 缓存抽象:ICacheProvider
  6. Elasticsearch
  7. 对象映射:Mapster
  8. 认证与安全层
  9. 定时任务:AddJob<T>
  10. 文本日志:TxtLogger
  11. appsettings.json 完整配置参考
  12. 本示例项目文件清单
  13. 注意事项

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 的映射配置。业务只需:

  1. 在业务项目里写一个 IRegister 实现类定义映射规则;
  2. 端点注入 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"
  }
}

客户端签名规则(必须与后台一致):

  1. 收集所有 query 参数,排除 sign 自身;
  2. 按 key 不区分大小写排序,拼接为 k1=v1&k2=v2&...;
  3. 按 Algorithm 求摘要:
    • HmacSha256:HMAC-SHA256(Secret 作为 key, message) → hex 小写;
    • Md5:MD5(message + Secret) → hex 小写;
  4. 把 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&timespan=...&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 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

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