更新框架,增加云库搜索模块
This commit is contained in:
1 parent
8526e5e0d2
commit
f2caec6083
192 files changed
+3626
-804
No files matched your search
@@ -0,0 +1,18 @@
|
||||
using MAX.Framework.Dtos;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Framework.Commons
|
||||
{
|
||||
public class AppException : Exception
|
||||
{
|
||||
public int Code { get; }
|
||||
|
||||
public AppException(string message, int code = ResultCode.BusinessError)
|
||||
: base(message)
|
||||
{
|
||||
Code = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
using MAX.Framework.Dtos;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Framework.Commons
|
||||
{
|
||||
public class GlobalExceptionFilter : IExceptionFilter
|
||||
{
|
||||
private readonly ILogger<GlobalExceptionFilter> _logger;
|
||||
|
||||
public GlobalExceptionFilter(ILogger<GlobalExceptionFilter> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void OnException(ExceptionContext context)
|
||||
{
|
||||
var traceId = context.HttpContext.TraceIdentifier;
|
||||
|
||||
var result = context.Exception switch
|
||||
{
|
||||
AppException be => ApiResult.Fail(be.Message, be.Code),
|
||||
ValidationException ve => ApiResult.Fail(ve.Message, ResultCode.ValidationError),
|
||||
UnauthorizedAccessException => ApiResult.Fail("未授权访问", ResultCode.Unauthorized),
|
||||
_ => ApiResult.Fail("服务器内部错误", ResultCode.ServerError)
|
||||
};
|
||||
|
||||
_logger.LogError(context.Exception, "请求异常 TraceId: {TraceId}", traceId);
|
||||
|
||||
context.Result = new ObjectResult(result)
|
||||
{
|
||||
StatusCode = 200 // 关键:HTTP状态码统一200,业务状态用Code表达
|
||||
};
|
||||
context.ExceptionHandled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Framework.Commons
|
||||
{
|
||||
public class PageData<T>
|
||||
{
|
||||
public long Total { get; set; }
|
||||
public int PageIndex { get; set; }
|
||||
public int PageSize { get; set; }
|
||||
public int TotalPages => PageSize > 0 ? (int)Math.Ceiling((double)Total / PageSize) : 0;
|
||||
public List<T> List { get; set; } = new();
|
||||
|
||||
public PageData() { }
|
||||
|
||||
public PageData(List<T> list, long total, int pageIndex, int pageSize)
|
||||
{
|
||||
List = list;
|
||||
Total = total;
|
||||
PageIndex = pageIndex;
|
||||
PageSize = pageSize;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
using MAX.Framework.Dtos;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace MAX.Framework.Commons
|
||||
{
|
||||
/// <summary>
|
||||
/// 返回过滤
|
||||
/// </summary>
|
||||
public class UnifyResultFilter : IActionFilter
|
||||
{
|
||||
public void OnActionExecuted(ActionExecutedContext context)
|
||||
{
|
||||
if (context.Result is ObjectResult objResult)
|
||||
{
|
||||
if (!IsAlreadyWrapped(objResult.Value))
|
||||
{
|
||||
var apiResult = ApiResult<object>.Success(objResult.Value);
|
||||
|
||||
objResult.Value = apiResult;
|
||||
objResult.DeclaredType = null;
|
||||
}
|
||||
}
|
||||
else if (context.Result is EmptyResult || context.Result is NoContentResult)
|
||||
{
|
||||
context.Result = new ObjectResult(ApiResult.Success());
|
||||
}
|
||||
}
|
||||
|
||||
public void OnActionExecuting(ActionExecutingContext context) { }
|
||||
private static bool IsAlreadyWrapped(object? value)
|
||||
{
|
||||
if (value is null) return false;
|
||||
|
||||
var type = value.GetType();
|
||||
|
||||
// 递归判断:只要类型链上有任何一层是 ApiResult<> 的开放泛型定义,或直接是 ApiResult,就算已包装
|
||||
while (type is not null)
|
||||
{
|
||||
if (type == typeof(ApiResult)) return true;
|
||||
if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(ApiResult<>)) return true;
|
||||
type = type.BaseType;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
using MAX.Framework.Dtos;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace MAX.Framework.Commons
|
||||
{
|
||||
public class UnsupportedMediaTypeHandlingMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
|
||||
public UnsupportedMediaTypeHandlingMiddleware(RequestDelegate next)
|
||||
{
|
||||
_next = next;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
// 用一个内存流替换原始的Response.Body,方便判断状态码后决定是否要改写
|
||||
var originalBodyStream = context.Response.Body;
|
||||
using var memoryStream = new MemoryStream();
|
||||
context.Response.Body = memoryStream;
|
||||
|
||||
await _next(context);
|
||||
|
||||
if (context.Response.StatusCode == StatusCodes.Status415UnsupportedMediaType)
|
||||
{
|
||||
var result = ApiResult.Fail("请求参数格式不正确", ResultCode.ValidationError);
|
||||
|
||||
var json = JsonSerializer.Serialize(result);
|
||||
var bytes = Encoding.UTF8.GetBytes(json);
|
||||
|
||||
context.Response.Clear();
|
||||
context.Response.StatusCode = StatusCodes.Status200OK; // 统一成200,和其他接口一致
|
||||
context.Response.ContentType = "application/json; charset=utf-8";
|
||||
context.Response.ContentLength = bytes.Length;
|
||||
|
||||
await context.Response.Body.WriteAsync(bytes);
|
||||
await context.Response.Body.FlushAsync(originalBodyStream is null ? default : default);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 非415的情况,把内存流内容原样写回真正的Response.Body
|
||||
memoryStream.Seek(0, SeekOrigin.Begin);
|
||||
await memoryStream.CopyToAsync(originalBodyStream);
|
||||
}
|
||||
|
||||
context.Response.Body = originalBodyStream;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user