API过滤器
响应筛选器,用于统一格式化响应请求
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class SkipApiResponseFilterAttribute : Attribute
{
}
public class ApiResponseActionFilter : IActionFilter
{
public void OnActionExecuting(ActionExecutingContext context)
{
// 在Action执行之前,你可以添加逻辑,但在这个场景中我们不需要。
}
public void OnActionExecuted(ActionExecutedContext context)
{
// 检查是否应该跳过ApiResponseActionFilter
if (context.ActionDescriptor.EndpointMetadata.Any(em => em is SkipApiResponseFilterAttribute))
{
return; // 如果有SkipApiResponseFilterAttribute,则直接返回,不再处理。
}
object extraData = null;
// 检查是否有额外的数据需要添加到响应中
if (context.HttpContext.Items.ContainsKey("ExtraData"))
{
extraData = context.HttpContext.Items["ExtraData"];
}
//请求正常返回数据
if (context.Result is ObjectResult objectResult)
{
var apiResponse = new CustomRestfulResult<object>()
{
StatusCode = objectResult.StatusCode??200,
Data = objectResult.Value,
Succeeded = true,
Timestamp = DateTime.Now.GetTimeSpan(),
Extras = extraData
};
context.Result = new ObjectResult(apiResponse)
{
StatusCode = objectResult.StatusCode
};
}
//返回请求码
else if (context.Result is StatusCodeResult statusCodeResult)
{
var apiResponse = new CustomRestfulResult<object>()
{
StatusCode = statusCodeResult.StatusCode,
Data = null,
Succeeded = false,
Timestamp = DateTime.Now.GetTimeSpan(),
Extras = extraData
};
context.Result = new ObjectResult(apiResponse)
{
StatusCode = statusCodeResult.StatusCode
};
}
}
}
异常筛选器
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.AspNetCore.Mvc;
using System.Net;
public class ApiExceptionFilter : IExceptionFilter
{
public void OnException(ExceptionContext context)
{
object extraData = null;
// 检查是否有额外的数据需要添加到响应中
if (context.HttpContext.Items.ContainsKey("ExtraData"))
{
extraData = context.HttpContext.Items["ExtraData"];
}
// 你可以根据不同类型的异常返回不同的错误信息或状态码
var statusCode = context.Exception is ArgumentException ?
(int)HttpStatusCode.BadRequest :
(int)HttpStatusCode.InternalServerError;
var response = new CustomRestfulResult<string>
{
StatusCode = statusCode,
Succeeded = false,
Errors = context.Exception.Message,
Timestamp = DateTime.Now.GetTimeSpan(),
Extras = extraData
};
context.Result = new ObjectResult(response)
{
StatusCode = statusCode
};
// 设置为true,表示异常已经被处理
context.ExceptionHandled = true;
}
}
/// <summary>
/// 客制化请求响应结果
/// </summary>
/// <typeparam name="T"></typeparam>
public class CustomRestfulResult<T>
{
/// <summary>
/// 状态码
/// </summary>
public int? StatusCode { get; set; }
/// <summary>
/// 数据
/// </summary>
public T? Data { get; set; }
/// <summary>
/// 执行成功
/// </summary>
public bool Succeeded { get; set; }
/// <summary>
/// 错误信息
/// </summary>
public object? Errors { get; set; }
/// <summary>
/// 附加数据
/// </summary>
public object? Extras { get; set; }
/// <summary>
/// 时间戳
/// </summary>
public long Timestamp { get; set; }
}
/// <summary>
/// 时间扩展
/// </summary>
public static class ExtensionForDateTime
{
/// <summary>
/// DateTime转换为Unix时间戳
/// </summary>
/// <param name="dateTime">当前时间</param>
/// <returns>Unix时间戳(转换为秒)</returns>
public static long GetTimeSpan(this DateTime dateTime)
{
// 转换为UTC时间
DateTime utcNow = dateTime.ToUniversalTime();
// Unix时间戳起点
DateTime unixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
// 计算时间差
TimeSpan elapsed = utcNow.Subtract(unixEpoch);
// 转换为秒(Unix时间戳)
return (long)elapsed.TotalSeconds;
}
}
using System.Globalization;
using System.Text.Json.Serialization;
using System.Text.Json;
/// <summary>
/// 自定义日期时间格式转换器
/// </summary>
public class JsonDateTimeConverter : JsonConverter<DateTime>
{
private const string DateFormat = "yyyy-MM-dd HH:mm:ss"; // 自定义的日期时间格式
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.ParseExact(reader.GetString(), DateFormat, CultureInfo.InvariantCulture);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString(DateFormat, CultureInfo.InvariantCulture));
}
}
拓展
public static class ControllerExtensions
{
public static IMvcBuilder AddCustomConfig(this IMvcBuilder builder)
{
// 在这里添加您的自定义配置
builder.Services.AddControllers(options =>
{
// API 自动规范化RESTful风格
options.Filters.Add(new ApiResponseActionFilter());
// API 异常捕获
options.Filters.Add(new ApiExceptionFilter());
// API 日志记录 使用TypeFilter来实现依赖注入
options.Filters.Add(typeof(ApiRequestResponseLoggingFilter));
}).AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonDateTimeConverter());
});
return builder;
}
}
使用
builder.Services.AddControllers().AddCustomConfig();
api中使用
[ApiController]
[Route("[controller]")]
public class RadarController : ControllerBase
{
/// <summary>
/// hello
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("Hello")]
public string Hello()
{
return "hello";
}
/// <summary>
/// GetCount
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("GetCount")]
public string GetCount()
{
//增加额外数据
HttpContext.Items["ExtraData"] = new { totalCount = 100 };
return "GetCount";
}
/// <summary>
/// GetFile
/// </summary>
/// <returns></returns>
[HttpGet]
[Route("GetFile")]
[SkipApiResponseFilterAttribute] //跳过格式化
public IActionResult GetFile()
{
// 设置文件路径
var filePath = Path.Combine(Directory.GetCurrentDirectory(), "Data", fileName);
// 检查文件是否存在
if (!System.IO.File.Exists(filePath))
{
return NotFound("文件不存在");
}
// 读取文件的byte数组
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
// 返回文件流作为文件类型的响应
return File(fileBytes, "application/octet-stream", fileName);
}
}