文章目录
一、安装 ABP CLI
安装
dotnet tool install -g Volo.Abp.Studio.Cli
更新
dotnet tool update -g Volo.Abp.Studio.Cli
二、使用CLI创建项目
abp new Demo.CMS -t module --no-ui -csf -dbms MySQL
命令解析
Demo.CMS:公司名称.项目名称
-t:指定模板名称
no-ui:无用户界面
-csf:指定项目是位于输出文件夹中的新文件夹中,还是直接位于输出文件夹中。
-dbms:设置所使用的数据库
官网连接
三、调整项目结构
- 创建
CMS.Shared
解决方案,用于存放一些共享的代码,如全局返回模型、帮助类等。 - 创建
Demo.CMS.Swagger
,用于存放Swagger相关代码。 - 创建
Demo.CMS.Caching
,用于存放缓存相关代码。
四、配置统一返回结果
返回模型统一放在
CMS.Shared
中
1.创建响应码枚举
namespace CMS.Shared.Base.Enum
{
/// <summary>
/// 响应码枚举
/// </summary>
public enum ResponseResultCode
{
/// <summary>
/// 成功
/// </summary>
Succeed = 0,
/// <summary>
/// 失败
/// </summary>
Failed = 1,
}
}
2.创建响应实体
using CMS.Shared.Base.Enum;
namespace CMS.Shared.Base
{
/// <summary>
/// 响应实体
/// </summary>
public class ResponseResult
{
/// <summary>
/// 响应码
/// </summary>
public ResponseResultCode Code { get; set; }
/// <summary>
/// 响应信息
/// </summary>
public string Message { get; set; }
/// <summary>
/// 成功
/// </summary>
public bool Success => Code == ResponseResultCode.Succeed;
/// <summary>
/// 时间戳(毫秒)
/// </summary>
public long Timestamp { get; } = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
/// <summary>
/// 响应成功
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
public void IsSuccess(string message = "")
{
Message = message;
Code = ResponseResultCode.Succeed;
}
/// <summary>
/// 响应失败
/// </summary>
/// <param name="message"></param>
/// <param name="data"></param>
/// <returns></returns>
public void IsFailed(string message = "")
{
Message = message;
Code = ResponseResultCode.Failed;
}
/// <summary>
/// 响应失败
/// </summary>
/// <param name="exception"></param>
public void IsFailed(Exception exception)
{
Message = exception.InnerException?.StackTrace!;
Code = ResponseResultCode.Failed;
}
}
}
3.创建响应实体(泛型)
using CMS.Shared.Base.Enum;
namespace CMS.Shared.Base
{
/// <summary>
/// 响应实体(泛型)
/// </summary>
/// <typeparam name="T"></typeparam>
public class ResponseResult<T> : ResponseResult where T : class
{
/// <summary>
/// 返回结果
/// </summary>
public T? Result { get; set; }
/// <summary>
/// 响应成功
/// </summary>
/// <param name="result"></param>
/// <param name="message"></param>
public void IsSuccess(T? result = null, string message = "")
{
Message = message;
Code = ResponseResultCode.Succeed;
Result = result;
}
}
}
五、配置并使用统一返回结果过滤器
1.创建NoWrapperAttribute
using System;
namespace Demo.CMS.Attribute
{
/// <summary>
/// 无需包装返回结果特性
/// 该特性用于标记在控制器类或方法上,表示其返回结果不需要被ResultWrapperFilter过滤器进行统一包装。
/// </summary>
[AttributeUsage(
AttributeTargets.Class | AttributeTargets.Method, // 指定该特性可应用于类和方法
AllowMultiple = false, // 指定一个元素上不能多次应用此特性
Inherited = false // 指定该特性不会被子类继承
)]
public class NoWrapperAttribute : System.Attribute
{
// 由于这是一个标记特性(Marker Attribute),通常不包含任何属性或方法
// 它仅仅用于在运行时通过反射等方式被检测到
}
}
2.创建ResultWrapperFilter
using CMS.Shared.Base;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System.Linq;
using CMS.Shared.Base.Enum;
using Demo.CMS.Attribute;
namespace Demo.CMS.Filter
{
/// <summary>
/// 全局统一返回结果过滤器
/// 用于自动将控制器的返回结果包装成统一的响应格式。
/// 如果控制器或其方法上标记了NoWrapperAttribute,则不进行包装,直接返回原始值。
/// </summary>
public class ResultWrapperFilter : ActionFilterAttribute
{
/// <summary>
/// 在结果执行前调用,用于包装返回结果。
/// </summary>
/// <param name="context">当前结果执行的上下文信息。</param>
public override void OnResultExecuting(ResultExecutingContext context)
{
// 尝试获取当前控制器动作描述符
var controllerActionDescriptor = context.ActionDescriptor as ControllerActionDescriptor;
// 检查控制器方法上是否有NoWrapperAttribute特性
var actionWrapper = controllerActionDescriptor?.MethodInfo.GetCustomAttributes(typeof(NoWrapperAttribute), false).FirstOrDefault();
// 检查控制器上是否有NoWrapperAttribute特性
var controllerWrapper = controllerActionDescriptor?.ControllerTypeInfo.GetCustomAttributes(typeof(NoWrapperAttribute), false).FirstOrDefault();
// 如果包含NoWrapperAttribute,则说明不需要对返回结果进行包装,直接返回原始值
if (actionWrapper != null || controllerWrapper != null)
{
return;
}
// 创建一个新的响应结果对象
var rspResult = new ResponseResult<object>();
// 检查当前结果是否为ObjectResult类型
if (context.Result is ObjectResult)
{
var objectResult = context.Result as ObjectResult;
// 如果ObjectResult的值为null,则设置响应状态为失败,并返回错误信息
if (objectResult?.Value == null)
{
rspResult.Code = ResponseResultCode.Failed;
rspResult.Message = "未找到资源";
context.Result = new ObjectResult(rspResult);
}
else
{
// 如果返回结果已经是ResponseResult<T>类型的,则不需要进行再次包装
if (objectResult.DeclaredType.IsGenericType && objectResult.DeclaredType?.GetGenericTypeDefinition() == typeof(ResponseResult<>))
{
return;
}
// 否则,将原始结果设置到rspResult的Result属性中,并更新context的Result为包装后的结果
rspResult.Result = objectResult.Value;
context.Result = new ObjectResult(rspResult);
}
}
}
}
}
3.在HttpApiHostModule中使用
context.Services.AddControllers(options =>
{
// 全局统一返回结果过滤器
options.Filters.Add<ResultWrapperFilter>();
});
六、配置全局异常捕获
1.创建GlobalExceptionMiddleware
using System;
using System.Net;
using System.Threading.Tasks;
using CMS.Shared.Base;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;
using Serilog;
namespace Demo.CMS.Middlewares
{
/// <summary>
/// 全局异常处理中间件
/// </summary>
/// <param name="next"></param>
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
public GlobalExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
Log.Error(ex, "!!!发生了一个异常!!!");
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
var res = new ResponseResult();
res.IsFailed(ex.Message + ",请查看日志!");
var json = JsonConvert.SerializeObject(res);
await context.Response.WriteAsync(json);
}
}
}
}
2.移除Abp自带的过滤器
Configure<MvcOptions>(options =>
{
var filterMetadata = options.Filters.FirstOrDefault(x => x is ServiceFilterAttribute attribute && attribute.ServiceType == typeof(AbpExceptionFilter));
// 移除 AbpExceptionFilter,不然会和自定义全局异常捕获有冲突
options.Filters.Remove(filterMetadata);
});
3.在HttpApiHostModule中使用
app.UseMiddleware<GlobalExceptionMiddleware>();
写在最后
任何问题评论区或私信讨论,欢迎指正。
标签:初始化,项目,Abpvnext,创建,响应,context,using,CMS,public From: https://blog.csdn.net/dxh0515/article/details/141221503