Liwendong.Frameworks.MvcExtend
1.7.1
dotnet add package Liwendong.Frameworks.MvcExtend --version 1.7.1
NuGet\Install-Package Liwendong.Frameworks.MvcExtend -Version 1.7.1
<PackageReference Include="Liwendong.Frameworks.MvcExtend" Version="1.7.1" />
<PackageVersion Include="Liwendong.Frameworks.MvcExtend" Version="1.7.1" />
<PackageReference Include="Liwendong.Frameworks.MvcExtend" />
paket add Liwendong.Frameworks.MvcExtend --version 1.7.1
#r "nuget: Liwendong.Frameworks.MvcExtend, 1.7.1"
#:package Liwendong.Frameworks.MvcExtend@1.7.1
#addin nuget:?package=Liwendong.Frameworks.MvcExtend&version=1.7.1
#tool nuget:?package=Liwendong.Frameworks.MvcExtend&version=1.7.1
Liwendong.Frameworks.MvcExtend
MVC 扩展,提供 MVC5(net451/net46/net47/net48)与 ASP.NET Core(netcoreapp3.1/net8.0)的统一异常处理、统一 JSON 返回、模型校验、请求日志、分页结果等基础设施。
主要内容
MVC5(NetFrameworkMvcBaseController)
继承 System.Web.Mvc.Controller 的基类控制器:
- 统一异常处理(
OnException):EasyErrorException返回业务提示(沿用异常自带的ResultErrorCode)并按需记录 Tip 日志;ArgumentException返回参数错误提示并记录 Warn 日志;其他异常返回通用提示"系统异常,请联系相关人员"(ResultErrorCode.Exception),不向客户端暴露内部异常细节,完整信息仅写入 Exception 日志。 - 统一 JSON 返回:重写
Json(...),全部走JsonNetResult(Newtonsoft.Json,忽略循环引用、无长度限制)。 - 快捷方法:
JsonResultInfo(...)系列(含ResultErrorCode重载)返回统一ResultInfo包装;PageJsonResultInfo(...)返回分页结果;LargeJson(...)用于大数据量返回。
ASP.NET Core(MvcBaseController)
继承 Microsoft.AspNetCore.Mvc.Controller 的基类控制器,与 MVC5 基类对等:
- 统一异常处理:通过实现
IExceptionFilter接入管道(Core 3.x 的Controller已不再提供OnException重写点),处理逻辑与CommonResultExceptionFilter共用同一实现;同时注册全局过滤器时以先到者为准(均有ExceptionHandled判断,不会重复处理)。 - 快捷方法:与 MVC5 基类一致的
JsonResultInfo(...)/PageJsonResultInfo(...)系列。
public class HomeController : MvcBaseController
{
public IActionResult Index()
{
return JsonResultInfo(true, new { Name = "test" });
}
}
MVC5(JsonNetResult)
基于 Newtonsoft.Json 的 JsonResult,解决 MVC5 默认 JavaScriptSerializer 的循环引用与长度限制问题,支持 ignoreNullValue 配置。
异常过滤器(Filter.CommonResultExceptionFilter,Core)
IAsyncExceptionFilter 实现,与两个基类控制器共用 CommonResultExceptionHandler 处理逻辑:
services.AddControllers(options =>
{
options.Filters.Add<CommonResultExceptionFilter>();
});
响应已开始写入(HasStarted)时跳过写回,处理完成后置 ExceptionHandled = true。
模型校验(Filter.ModelStateValidationFilterAttribute)
ModelState 无效时直接返回统一错误结果(ResultErrorCode.Tips,消息为各字段错误拼接),不再进入 Action:
- MVC5:继承
ActionFilterAttribute,可直接[ModelStateValidationFilter]打在 Controller/Action 上。 - Core:实现
IActionFilter,可[ModelStateValidationFilter]直接使用,也可全局注册options.Filters.Add<ModelStateValidationFilterAttribute>()。
请求日志(Filter.RequestLogActionFilter)
记录入参、返回值与执行耗时(Tip 级别,LogManage.WriteTipLog):
- 入参/返回值超过
MaxContentLength(默认 2000 字符)自动截断。 - 未处理的异常不在此记录(交给异常过滤器,避免重复)。
- MVC5:可直接
[RequestLogActionFilter]打在 Controller/Action 上,也可GlobalFilters.Add(new RequestLogActionFilter())全局注册;计时状态存放于HttpContext.Items,过滤器实例共享安全。 - Core:
options.Filters.Add<RequestLogActionFilter>()全局注册,或[TypeFilter(typeof(RequestLogActionFilter))]。
分页模型(Models.PageResult<T>)
继承 ResultInfo<T>(总记录数复用基类 Count),包含 Items(当前页数据)、PageIndex/PageSize/TotalPages 与 HasPreviousPage/HasNextPage,配合基类的 PageJsonResultInfo(...) 使用:
return PageJsonResultInfo(list, pageIndex, pageSize, totalCount);
// 返回:{ Success, Info, Code, Count(总数), Items, PageIndex, PageSize, TotalPages, HasPreviousPage, HasNextPage }
使用注意
- 未知异常的
Info不返回Exception.Message(可能包含 SQL、路径等内部细节),统一为通用提示TipsResources.Abnormal,如前端依赖具体错误消息排查问题,请改为查看服务端日志。 EasyErrorException的错误码使用异常自带的ResultErrorCode(默认值即Tips,未显式指定错误码的调用行为不变)。GetExceptionMethodDescrption(拼写错误的旧方法名)已标记[Obsolete],请改用GetExceptionMethodDescription,旧方法在后续大版本中移除。- Core 基类控制器与异常过滤器同时生效时不会重复处理(内部有
ExceptionHandled判断),推荐二选一:要么继承MvcBaseController,要么全局注册CommonResultExceptionFilter。 - Core 侧
JsonResultInfo/PageJsonResultInfo返回的JsonResult由宿主的 JSON 配置决定序列化方式(默认 System.Text.Json,调用AddNewtonsoftJson()后为 Newtonsoft.Json);异常过滤器内部固定使用 Newtonsoft.Json 序列化ResultInfo。
更新日志
1.7.0 (2026-10-15)
新增
- 目标框架扩展为
net8.0;netcoreapp3.1;net451;net46;net47;net48(新增 net8.0 与 net47):ASP.NET Core 侧经共享框架Microsoft.AspNetCore.App引用编译(源码沿用#if NETCOREAPP3_1_OR_GREATER条件编译,自动覆盖 net8.0),MVC5 侧沿用Microsoft.AspNet.Mvc5.3.0;无行为变更。
1.6.0 (2026-10-10)
新增
- Core 版基类控制器
MvcBaseController:与 MVC5NetFrameworkMvcBaseController对等,提供统一异常处理(实现IExceptionFilter接入,Core 3.x 无OnException重写点)与JsonResultInfo/PageJsonResultInfo快捷方法。 - 模型校验过滤器
ModelStateValidationFilterAttribute(MVC5/Core 双实现):ModelState无效时直接返回ResultErrorCode.Tips的统一错误结果,字段错误拼接为提示消息。 - 请求日志过滤器
RequestLogActionFilter(MVC5/Core 双实现):记录入参、返回值与执行耗时(Tip 级别),超长内容截断(MaxContentLength,默认 2000);未处理异常不重复记录。 - 分页模型
PageResult<T>:继承ResultInfo<T>,提供Items/PageIndex/PageSize/TotalPages/HasPreviousPage/HasNextPage,两端基类配套PageJsonResultInfo(...)。 - 基类
JsonResultInfo新增ResultErrorCode重载(含带数据版本),与EasyErrorException.ResultErrorCode配合直接返回错误码。
优化
- 两端异常处理逻辑收敛到公共的
CommonResultExceptionHandler(映射 ResultInfo + 日志),MVC5 基类、Core 基类、Core 异常过滤器三处复用,消除重复代码。 - MVC5 基类
EasyErrorException的日志级别由 Warn 统一为 Tip(与 Core 过滤器一致),controller_action作为 events,方法描述写入 keyword。
1.5.0 (2026-10-10)
修复
CommonResultExceptionFilter未标记异常已处理:OnExceptionAsync之前未设置ExceptionHandled = true,异常会继续冒泡导致响应被二次写入、状态码被覆盖;现已修复。CommonResultExceptionFilter响应写入未等待:Response.WriteAsync的 Task 之前被直接丢弃,现改为await;并增加HasStarted判断,响应已开始时不再写回。- 异常信息泄露:MVC5 基类与 Core 过滤器之前把未知异常的
Exception.Message原样返回给客户端(可能包含 SQL、路径等内部细节),现统一返回通用提示"系统异常,请联系相关人员",完整信息仅写入日志。 - Action 重载导致二次异常:
GetExceptionActionDescription中GetMethod遇到重载会抛AmbiguousMatchException,现统一由ExceptionDescribeHelper捕获处理。 - MVC5 错误码固定为
Tips:EasyErrorException分支现使用异常自带的ResultErrorCode,与 Core 过滤器行为一致。
优化
- 删除
CommonResultExceptionFilter中约 40 行注释掉的死代码。 - 异常方法描述逻辑(Action/TargetSite → Description)抽取为公共的
ExceptionDescribeHelper,MVC5 与 Core 两端复用,消除重复代码。 LargeJson(...)由 MVC5 默认的JavaScriptSerializer改为JsonNetResult(Newtonsoft.Json),与Json(...)重写行为一致,避免两套序列化规则。- Core 过滤器中的 Action 名称正则改为
static readonly Regex(Compiled),避免每次请求重新编译。 JsonNetResult:ArgumentNullException("context")改为nameof(context),补齐 XML 注释。
新增
- 新增正确拼写的
GetExceptionMethodDescription(MVC5 基类与 Core 过滤器均有);旧的GetExceptionMethodDescrption标记[Obsolete]。 - 目标框架新增
net48,与Liwendong.Frameworks依赖链保持一致。 - 包内附带 README.md 与 XML 文档注释(
GenerateDocumentationFile),消费方获得 IntelliSense;显式声明Newtonsoft.Json依赖。
版本历史
1.7.1 (2026-10-17)
- 修复:
CommonResultExceptionFilter改 try/finally 置位ExceptionHandled(写响应抛异常时标记不再失效);MvcBaseController.OnException补response.HasStarted判断;NetFrameworkMvcBaseController.OnException的ExceptionHandled=true移入真正处理分支 - 修复:
CommonResultExceptionHandler日志调用包 try/catch 兜底(失败输出 Trace),日志设施异常不再打断异常处理链 - 修复:
CommonResultExceptionFilter的正则补 matchTimeout(5 秒) - 修复:Core 版
ModelStateValidationFilterAttribute补[AttributeUsage(Class | Method)] - 修复:
PageResult对 pageSize/totalCount 增加负数校验(按 0 处理) - 优化:
RequestLogActionFilter入参/返回值日志对 password/pwd/token/secret/phone/mobile 等敏感字段值脱敏为***(字段名列表可静态配置);JsonNetResult注明Data==null时不写响应体的历史行为
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. 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. |
| .NET Core | netcoreapp3.1 is compatible. |
| .NET Framework | net451 is compatible. net452 was computed. net46 is compatible. net461 was computed. net462 was computed. net463 was computed. net47 is compatible. net471 was computed. net472 was computed. net48 is compatible. net481 was computed. |
-
.NETCoreApp 3.1
- Liwendong.Frameworks (>= 1.8.1)
- Newtonsoft.Json (>= 13.0.3)
-
.NETFramework 4.5.1
- Liwendong.Frameworks (>= 1.8.1)
- Microsoft.AspNet.Mvc (>= 5.3.0)
- Microsoft.AspNet.WebApi.Core (>= 5.2.7)
- Newtonsoft.Json (>= 13.0.3)
-
.NETFramework 4.6
- Liwendong.Frameworks (>= 1.8.1)
- Microsoft.AspNet.Mvc (>= 5.3.0)
- Microsoft.AspNet.WebApi.Core (>= 5.2.7)
- Newtonsoft.Json (>= 13.0.3)
-
.NETFramework 4.7
- Liwendong.Frameworks (>= 1.8.1)
- Microsoft.AspNet.Mvc (>= 5.3.0)
- Microsoft.AspNet.WebApi.Core (>= 5.2.7)
- Newtonsoft.Json (>= 13.0.3)
-
.NETFramework 4.8
- Liwendong.Frameworks (>= 1.8.1)
- Microsoft.AspNet.Mvc (>= 5.3.0)
- Microsoft.AspNet.WebApi.Core (>= 5.2.7)
- Newtonsoft.Json (>= 13.0.3)
-
net8.0
- Liwendong.Frameworks (>= 1.8.1)
- Newtonsoft.Json (>= 13.0.3)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.