P0 实现全局异常处理中间件:移除所有Controller重复try-catch,统一异常响应

This commit is contained in:
claw_bot 2026-03-11 07:56:58 +00:00
parent 949fa8e85b
commit 89244fc078
3 changed files with 385 additions and 414 deletions

View File

@ -51,8 +51,6 @@ public class PortfolioController : ControllerBase
/// <returns>创建的投资组合信息</returns>
[HttpPost]
public ActionResult<ApiResponse<CreatePortfolioResponse>> CreatePortfolio([FromBody] CreatePortfolioRequest request)
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -123,18 +121,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating portfolio");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<CreatePortfolioResponse>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 获取当前用户的投资组合列表
@ -142,8 +128,6 @@ public class PortfolioController : ControllerBase
/// <returns>投资组合列表</returns>
[HttpGet]
public ActionResult<ApiResponse<GetPortfoliosResponse>> GetPortfolios()
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -169,18 +153,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving portfolios");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<GetPortfoliosResponse>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 获取当前用户的总资产概览
@ -188,8 +160,6 @@ public class PortfolioController : ControllerBase
/// <returns>总资产数据(总市值、今日盈亏、累计收益率等)</returns>
[HttpGet("assets")]
public ActionResult<ApiResponse<TotalAssetsResponse>> GetTotalAssets()
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -215,18 +185,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving total assets");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<TotalAssetsResponse>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 获取单个投资组合详情
@ -235,8 +193,6 @@ public class PortfolioController : ControllerBase
/// <returns>投资组合详情(含持仓明细)</returns>
[HttpGet("{id}")]
public async Task<ActionResult<ApiResponse<PortfolioDetailResponse>>> GetPortfolioById(string id)
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -262,18 +218,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving portfolio");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<PortfolioDetailResponse>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 获取投资组合的交易记录(流水)
@ -284,8 +228,6 @@ public class PortfolioController : ControllerBase
/// <returns>交易记录列表</returns>
[HttpGet("transactions")]
public ActionResult<ApiResponse<GetTransactionsResponse>> GetTransactions([FromQuery] string portfolioId, [FromQuery] int limit = 10, [FromQuery] int offset = 0)
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -311,18 +253,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error retrieving transactions");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<GetTransactionsResponse>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 记录一笔交易(买入/卖出)
@ -331,8 +261,6 @@ public class PortfolioController : ControllerBase
/// <returns>创建的交易记录</returns>
[HttpPost("transactions")]
public ActionResult<ApiResponse<CreateTransactionResponse>> CreateTransaction([FromBody] CreateTransactionRequest request)
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -405,18 +333,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error creating transaction");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<CreateTransactionResponse>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 获取投资组合策略信号
@ -425,8 +341,6 @@ public class PortfolioController : ControllerBase
/// <returns>策略信号</returns>
[HttpGet("{id}/signal")]
public async Task<ActionResult<ApiResponse<StrategySignal>>> GetPortfolioSignal(string id)
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -489,18 +403,6 @@ public class PortfolioController : ControllerBase
message = "success"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error getting portfolio signal: {PortfolioId}", id);
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<StrategySignal>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = null,
message = ex.Message
});
}
}
/// <summary>
/// 删除投资组合
@ -509,8 +411,6 @@ public class PortfolioController : ControllerBase
/// <returns>删除结果</returns>
[HttpDelete("{id}")]
public async Task<ActionResult<ApiResponse<bool>>> DeletePortfolio(string id)
{
try
{
var userId = GetCurrentUserId();
if (string.IsNullOrEmpty(userId))
@ -579,16 +479,4 @@ public class PortfolioController : ControllerBase
message = "删除成功"
});
}
catch (Exception ex)
{
_logger.LogError(ex, "Error deleting portfolio");
return StatusCode(AssetManager.Models.StatusCodes.InternalServerError, new ApiResponse<bool>
{
code = AssetManager.Models.StatusCodes.InternalServerError,
data = false,
message = ex.Message
});
}
}
}

View File

@ -0,0 +1,80 @@
using AssetManager.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
using System.Net;
using System.Text.Json;
using System.Threading.Tasks;
namespace AssetManager.API.Middleware;
/// <summary>
/// 全局异常处理中间件统一捕获所有API异常返回标准格式响应
/// </summary>
public class GlobalExceptionMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<GlobalExceptionMiddleware> _logger;
public GlobalExceptionMiddleware(RequestDelegate next, ILogger<GlobalExceptionMiddleware> logger)
{
_next = next;
_logger = logger;
}
public async Task InvokeAsync(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception ex)
{
_logger.LogError(ex, "请求处理异常: {Path}", context.Request.Path);
await HandleExceptionAsync(context, ex);
}
}
private static Task HandleExceptionAsync(HttpContext context, Exception exception)
{
context.Response.ContentType = "application/json";
var response = new ApiResponse<object>
{
code = StatusCodes.Status500InternalServerError,
data = null,
message = exception.Message
};
// 根据异常类型设置不同的状态码
switch (exception)
{
case UnauthorizedAccessException _:
context.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
response.code = StatusCodes.Status401Unauthorized;
response.message = "未授权访问";
break;
case ArgumentException _:
case InvalidOperationException _:
context.Response.StatusCode = (int)HttpStatusCode.BadRequest;
response.code = StatusCodes.Status400BadRequest;
break;
case KeyNotFoundException _:
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
response.code = StatusCodes.Status404NotFound;
break;
default:
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
response.code = StatusCodes.Status500InternalServerError;
// 生产环境可以隐藏具体错误信息,避免泄露敏感信息
// response.message = "服务器内部错误";
break;
}
var result = JsonSerializer.Serialize(response, new JsonSerializerOptions
{
PropertyNamingPolicy = JsonNamingPolicy.CamelCase
});
return context.Response.WriteAsync(result);
}
}

View File

@ -115,6 +115,9 @@ var app = builder.Build();
// 初始化数据库
app.Services.InitializeDatabase();
// 全局异常处理中间件(必须放在最前面)
app.UseMiddleware<GlobalExceptionMiddleware>();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();