Nop.WebApiFramework 1.0.2

dotnet add package Nop.WebApiFramework --version 1.0.2
                    
NuGet\Install-Package Nop.WebApiFramework -Version 1.0.2
                    
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="Nop.WebApiFramework" Version="1.0.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Nop.WebApiFramework" Version="1.0.2" />
                    
Directory.Packages.props
<PackageReference Include="Nop.WebApiFramework" />
                    
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 Nop.WebApiFramework --version 1.0.2
                    
#r "nuget: Nop.WebApiFramework, 1.0.2"
                    
#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 Nop.WebApiFramework@1.0.2
                    
#: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=Nop.WebApiFramework&version=1.0.2
                    
Install as a Cake Addin
#tool nuget:?package=Nop.WebApiFramework&version=1.0.2
                    
Install as a Cake Tool

Nop.WebApiFramework

ASP.NET Core 企业级 Web API 框架,开箱即用地集成了 DI、ORM、认证、日志、链路追踪、任务调度、对象存储、Swagger 文档等常用组件。

依赖: Nop.Infrastructure + Microsoft.AspNetCore.App


快速开始 — Program.cs 模板

using Nop.WebApiFramework;
using Nop.WebApiFramework.ServiceExtentions;
using Nop.WebApiFramework.UserAccount;

var builder = WebApplication.CreateBuilder(args);
var model = builder.Configuration.Get<AppSettingsModel>()!;

// 1. 基础注入(HttpContext、内存缓存、HttpClient、CORS、OpenTelemetry、Serilog、Swagger)
builder.NetCoreBasic(model.ServiceName!, typeof(ApiGroupNames));

// 2. JWT 认证
builder.Services.AddJwtAuth(builder.Configuration);
builder.Services.AddScoped<UserAuthenticationFilter>();

// 3. 数据库(FreeSql + MySQL,也支持 SqlServer)
builder.Services.AddCustomMySql(model, b => {
    b.UseConnectionString(FreeSql.DataType.MySql, model.FreeSqlDatabase.ConnectionString);
});

// 4. Hangfire 后台任务
builder.Services.AddCustomHangfirePkg(model);

// 5. 统一 ModelState 验证格式
builder.Services.AddControllers()
    .AddNewtonsoftJson()
    .ConfigureCustomApiBehaviorOptions();

var app = builder.Build();

// 6. 通用中间件管道(健康检查 → 请求日志 → 异常处理 → 链路追踪 → CORS)
app.UseWebApiFrameWork(model.ServiceName!);

// 7. Hangfire Dashboard
app.UseCustomHangfire();

// 8. Swagger
app.UseCustomSwagger(typeof(ApiGroupNames));

app.MapControllers();
app.Run();

核心架构

请求管道顺序

HTTP Request
  → NopHealthCheckMiddleware    // /healthcheck 健康检查
  → HttpRequestBodyMiddleware    // 记录请求体/响应体到 Serilog
  → GlobalExceptionMiddleware    // 全局异常捕获 + 数据库连接池自愈
  → OpenTelemetryCustomTag       // 注入 RequestId 到 Activity
  → CORS Middleware
  → Authentication (JWT)
  → Controller

统一响应格式

所有 Controller 继承 WebApiBaseController,有 8 个 Ok/Error 方法,响应统一为:

// 成功
{ "errCode": 0, "errMsg": "ok", "requestId": "abc123", "data": { ... } }

// 失败
{ "errCode": 500, "errMsg": "错误信息", "requestId": "abc123" }

响应模型类(位于 Nop.WebApiFramework):

类 字段 说明
JsonResponse ErrorCode, ErrorMessage, RequestId, IsError 基础响应
JsonResponse<T> 继承 JsonResponse + Data 泛型响应

WebApiBaseController

public abstract class WebApiBaseController : ControllerBase
{
    // 成功响应(无数据)
    ActionResult Ok();

    // 成功响应(带数据)
    ActionResult Ok<T>(T data, int errCode = 0, string errMessage = "ok");

    // 返回 JsonResponse<T> 对象(非 ActionResult,用于组装)
    JsonResponse<T> Ok2<T>(T data, int errCode = 0, string errMessage = "ok");

    // 错误响应
    JsonResponse Error2(string errMessage, int errCode = 500);
    ActionResult Error(string errMessage, int errCode = 500);

    // 直接传入已有的 JsonResponse
    ActionResult Ok(JsonResponse response);
    ActionResult Ok<T>(JsonResponse<T> response) where T : class;

    // 从请求头 UserId 获取当前用户 ID
    long UserId { get; }
}

所有 IServiceCollection 扩展方法

以下方法可直接在 builder.Services. 或 builder. 上调用:

核心入口

方法 说明 注入/启用内容
builder.NetCoreBasic(serviceName, swaggerApiGroupType?) 必调入口 Kestrel 调优(10000并发)、HttpContextAccessor、MemoryCache、HttpClient、CORS、OpenTelemetry Zipkin、Serilog、Swagger
app.UseWebApiFrameWork(appName) 必调管道 健康检查、请求日志、异常处理、链路追踪Tag、CORS
builder.AddCustomCors(policyName?) CORS 服务注册 允许所有来源,预检缓存1小时
app.UseCustomCors(policyName?) CORS 中间件 启用 CORS
builder.ConfigureCustomApiBehaviorOptions() 自定义 ModelState 验证格式 返回 JsonResponse 而非 .NET 原生 400

JWT 认证

方法 说明
services.AddJwtAuth(ConfigurationManager) 从 JwtSetting 节点读取配置,注册 JWT Bearer 认证

数据库(FreeSql)

方法 说明
services.AddCustomMySql(AppSettingsModel, Action<FreeSqlBuilder>) 注册 FreeSql 单例,含 SQL 监控、LINQ 参数化、自动同步表结构

后台任务(Hangfire)

方法 说明
services.AddCustomHangfirePkg(AppSettingsModel) 注册 Hangfire(Redis 存储),禁止重试,失败自动删除
app.UseCustomHangfire() Hangfire Dashboard(/hangfire 路径,无认证限制)

API 文档(Swagger)

方法 说明
services.AddCustomSwagger(Type enumApiGroupNames?) 注册 SwaggerGen(含 Bearer Token 输入框、XML 注释、枚举分组)
app.UseCustomSwagger(Type apiGroup?) 启用 Swagger UI(折叠 Tag、隐藏 Models)

配置模型 — AppSettingsModel

完整配置节点(appsettings.json 示例):

{
  "ServiceName": "MyService",
  "HttpProtocal": "http",
  "TopDomainHost": "www.example.com",
  "IdentityServerUrl": "https://idp.example.com",

  "ConnectionStrings": {
    "MySqlConn": "Server=localhost;Database=mydb;User=root;Password=xxx;",
    "SqlServerConn": "",
    "PostgresConn": "",
    "RedisConnectString": "localhost:6379,password=xxx,defaultDatabase=0",
    "Mongodbsetting": {
      "Configuration": "mongodb://...",
      "Database": "MyDb"
    }
  },

  "FreeSqlDatabase": {
    "ConnectionString": "Server=localhost;Database=mydb;User=root;Password=xxx;",
    "MainDatabaseName": "mydb",
    "SqlExecuteElapsedMillisecondsThreshold": 3000,
    "UseMonitor": true,
    "UseGenerateCommandParameterWithLambda": true,
    "UseAdoConnectionPool": false
  },

  "JwtSetting": {
    "SecurityKey": "your-256-bit-key-here-minimum-32-chars",
    "Issuer": "Nop.WebApiFramework",
    "Audience": "Nop.WebApiFramework",
    "ExpireSeconds": 7200,
    "RefreshExpiresSeconds": 604800
  },

  "ApiSettings": { "AK": "", "SK": "" },

  "PrivateOSSConfig": {
    "AccessId": "",
    "AccessKey": "",
    "EndPoint": "https://oss-cn-hangzhou.aliyuncs.com",
    "BucketName": "private-bucket",
    "Platform": "aliyun",
    "CDNDomain": ""
  },

  "PublicOSSConfig": {
    "AccessId": "",
    "AccessKey": "",
    "EndPoint": "https://oss-cn-hangzhou.aliyuncs.com",
    "BucketName": "public-bucket",
    "Platform": "aliyun",
    "CDNDomain": "https://cdn.example.com"
  },

  "AIAgent": {
    "Completions": { "ApiKey": "", "Uri": "" },
    "Embeddings": { "ApiKey": "", "Uri": "" },
    "GteRerank": { "ApiKey": "", "Uri": "" }
  }
}

配置类说明

配置类 关键属性 说明
AppSettingsModel 所有子配置的根 使用 builder.Configuration.Get<AppSettingsModel>() 获取
JwtSettingModel SecurityKey, Issuer, Audience, ExpireSeconds JWT 签发和验证参数,SecurityKey 至少 256 bit
FreeSqlDatabaseSettings ConnectionString, MainDatabaseName, UseMonitor 数据库配置,UseMonitor=true 时慢 SQL 告警
ConnectionStrings RedisConnectString, MySqlConn, SqlServerConn 各类连接字符串
NopOSSEndPoint构造参数 accessId, accessKey, endPoint, bucketName, platform 对象存储终端配置

JWT 认证体系

组件职责

组件 类型 职责
JwtExtentions.AddJwtAuth() 静态扩展 注册 JWT Bearer 认证服务,配置验证参数
JwtTokenProvider 可注入服务 签发 access_token + refresh_token
AppJwtBearerEvents JwtBearerEvents 子类 从 Header 提取 Bearer token
UserAuthenticationFilter IActionFilter 从 Claims 提取用户信息 → 设置 LoginUserDto.Current
LoginUserDto 静态类 AsyncLocal<UserDto> 存储当前请求的用户
UserDto DTO Id, NickName, Role, PhoneNumber, Password, etc.

使用方式

// 控制器中获取当前用户
public class MyController : WebApiBaseController
{
    public IActionResult GetProfile()
    {
        // 方式1: 基础基类属性(仅返回 ID)
        long userId = this.UserId;

        // 方式2: 完整用户信息
        var user = LoginUserDto.Current;

        return Ok(user);
    }
}

认证流程

客户端请求(Header: Authorization: Bearer xxx)
  → AppJwtBearerEvents.MessageReceived: 提取 token
  → JwtSecurityTokenHandler.ValidateToken: 验证签名/过期/Issuer/Audience
  → AppJwtBearerEvents.TokenValidated: 验证通过
  → UserAuthenticationFilter.OnActionExecuting: 从 Claims 提取 → LoginUserDto.SetCurrent()
  → Controller: 通过 LoginUserDto.Current 访问用户信息

对象存储 — OSS

兼容 S3 协议的 OSS 封装,通过 INopOSSService 接口使用。

平台常量(NopOSSEndPoint.Platform)

常量 平台
NopOSSEndPoint.AliyunPlantform 阿里云 OSS("aliyun")
NopOSSEndPoint.TencentPlantform 腾讯云 COS("tencent")
NopOSSEndPoint.CtyunPlantform 天翼云("ctyun")
NopOSSEndPoint.MinioPlantform MinIO 自建("minio")

常用 API

// 构造终结点
var endpoint = new NopOSSEndPoint(
    accessId: model.PublicOSSConfig.AccessId,
    accessKey: model.PublicOSSConfig.AccessKey,
    endPoint: model.PublicOSSConfig.EndPoint,
    bucketName: model.PublicOSSConfig.BucketName,
    platform: model.PublicOSSConfig.Platform,
    cDNDomain: model.PublicOSSConfig.CDNDomain,
    supportContentDisposition: true
);

// 创建服务实例
var oss = new NopOSSService(endpoint, logger);

// 上传
await oss.PutObject("path/file.jpg", contentString);
await oss.PutObject("path/file.jpg", stream, contentDisposition: "attachment; filename=\"file.jpg\"");

// 下载
var obj = await oss.GetObject("path/file.jpg");

// 分片上传(大文件)
var init = await oss.InitiateMultipartUpload("path/bigfile.zip");
var part1 = await oss.UploadPart("path/bigfile.zip", init.UploadId, stream1, 1, size);
await oss.CompleteMultipartUpload("path/bigfile.zip", init.UploadId, partETags);

// 获取访问 URL
string url = oss.GetObjectUrl("path/file.jpg");                        // 公开访问
string signedUrl = oss.GetObjectUrl("path/file.jpg", withPreSigned: true); // 带临时 token
string token = oss.GetPresignedToken("path/file.jpg", expireMinutes: 30);

注册到 DI

// 私有 OSS
var privateEndpoint = new NopOSSEndPoint(/*...*/);
services.AddSingleton(privateEndpoint);
services.AddScoped<INopOSSService>(sp => new NopOSSService(
    sp.GetRequiredService<PrivateNopOSSConfig>().ToEndpoint(), sp.GetRequiredService<ILogger<NopOSSService>>()
));

// 公开 OSS(同样方式)

异常处理

WebApiException

自定义业务异常,会被 GlobalExceptionMiddleware 统一捕获并返回 JsonResponse 格式。

// 简单抛出
throw new WebApiException("用户名已存在");

// 带错误码和 HTTP 状态码
throw new WebApiException(10001, "资源未找到", httpStatus: 404);

// 从已有 JsonResponse 创建
throw new WebApiException(JsonResponse.ErrorResponse("错误", requestId), httpStatus: 400);

GlobalExceptionMiddleware 特性

  • 业务异常(WebApiException):返回自定义 ErrorCode 和 ErrorMessage
  • ApplicationException:HTTP 400(BadRequest)
  • KeyNotFoundException:HTTP 404(NotFound)
  • 其他异常:HTTP 500,默认屏蔽异常详情(可通过 "SystemExtensionShield": false 关闭)
  • 数据库连接恢复:检测 MySQL 连接失败 → 自动清空 MySqlConnection.ClearAllPools(),下次请求自动恢复
  • 企业微信告警:设置 "EnableQyBotExceptionMessage": true 可将异常推送到企业微信 Bot

中间件管道详情

中间件 注册方法 功能
NopHealthCheckMiddleware UseWebApiFrameWork /healthcheck 端点,返回服务名和心跳
HttpRequestBodyMiddleware UseWebApiFrameWork JSON 请求/响应体记录到 Serilog(跳过 SSE/流式响应,跳过文件流)
GlobalExceptionMiddleware UseWebApiFrameWork 全局异常捕获 + MySQL 连接池自愈
OpenTelemetry Tag UseWebApiFrameWork 自定义 Activity Tag(RequestId 等)
CORS UseWebApiFrameWork 通过 UseCustomCors()

Swagger 分组

通过枚举+特性实现 API 分组:

public enum ApiGroupNames
{
    [GroupInfo("用户管理", "v1", "用户注册登录")]
    User,

    [GroupInfo("内容管理", "v1", "文章、评论等")]
    Content,

    [GroupInfo("系统管理", "v1", "配置、监控等")]
    System
}

// Controller 上标注分组
[ApiGroup("User")]
[Route("[controller]")]
public class AccountController : WebApiBaseController { }

Type apiGroup 参数传入 typeof(ApiGroupNames) 即可。


FreeSql 数据库

services.AddCustomMySql(model, builder => {
    builder.UseConnectionString(DataType.MySql, model.FreeSqlDatabase.ConnectionString);
    // builder.UseConnectionString(DataType.SqlServer, model.FreeSqlDatabase.ConnectionString);
});

配置项说明(FreeSqlDatabaseSettings):

属性 默认值 说明
UseMonitor false 启用时输出 SQL 调试日志
UseGenerateCommandParameterWithLambda true LINQ 参数化查询
UseAdoConnectionPool false ADO.NET 连接池
SqlExecuteElapsedMillisecondsThreshold 3000 慢 SQL 告警阈值(毫秒)

注册后使用:

public class UserService
{
    private readonly IFreeSql _fsql;
    public UserService(IFreeSql fsql) => _fsql = fsql;

    public async Task<UserDto?> GetUser(long id) =>
        await _fsql.Select<UserDto>().Where(u => u.Id == id).FirstAsync();
}

Hangfire 后台任务

// 注册(Redis 存储,Db=2,Prefix="Hangfire:")
services.AddCustomHangfirePkg(model);

// 启用 Dashboard(路径 /hangfire,无认证限制,生产环境需自行加鉴权)
app.UseCustomHangfire();

注意 model.ConnectionStrings.RedisConnectString 必须已配置。


OpenTelemetry & Serilog

NetCoreBasic 自动完成以下注册:

  • OpenTelemetry: Zipkin Exporter + ASP.NET Core / HttpClient / SqlClient Instrumentation
  • Serilog: 从 appsettings.json 读取配置,自动 Filter 掉 /healthcheck 路径,注入 Activity 信息

Serilog 的 appsettings.json 示例:

{
  "Serilog": {
    "MinimumLevel": "Information",
    "WriteTo": [
      { "Name": "Console" },
      {
        "Name": "Seq",
        "Args": { "serverUrl": "http://localhost:5341" }
      }
    ]
  }
}

安装

dotnet add package Nop.WebApiFramework

依赖

本包依赖 Nop.Infrastructure,安装时会自动引入。

主要外部依赖 版本 用途
Autofac.Extensions.DependencyInjection 10.0.0 DI 容器
FreeSql 3.5.303 ORM
Hangfire.AspNetCore / Hangfire.Redis 1.8.22 / 1.12.0 后台任务
Serilog.AspNetCore / Serilog.Sinks.Seq 9.0.0 日志
OpenTelemetry 系列 1.14.0 链路追踪
Swashbuckle.AspNetCore 7.2.0 API 文档
Microsoft.AspNetCore.Authentication.JwtBearer 10.0.0 JWT 认证
Newtonsoft.Json 13.0.4 JSON
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.2 82 7/18/2026
1.0.1 71 7/18/2026
1.0.0 66 7/18/2026