.Net Core API 全局修改响应
.Net Core API Modify Response Globally
我正在使用 Angular 客户端开发 .Net Core API 项目。而APIProgram.cs文件配置如下,
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://127.0.0.1", "http://localhost", "https://127.0.0.1", "https://localhost")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHsts();
app.UseHttpsRedirection();
// non-api routes Spa
app.Use(async (context, next) =>
{
await next();
string path = context.Request.Path.Value == null ? "" : context.Request.Path.Value;
bool isNotFound = context.Response.StatusCode == 404;
bool isApiRequest = path.StartsWith("/api/");
bool hasPathExtension = Path.HasExtension(path);
if (isNotFound && !(isApiRequest || hasPathExtension))
{
context.Request.Path = "/index.html";
await next();
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRequestLocalization();
if (app.Environment.IsDevelopment())
{
app.UseCors();
}
//app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
//app.MapRazorPages();
app.MapControllers();
app.Run();
我需要做的是将每个控制器的响应、异常包装到全局的通用响应结构中(使用中间件或任何其他方法),如下所示,
[Serializable]
public class SampleResponse
{
public string? RequestUrlFormat { get; set; }
public string? RequestUrl { get; set; }
public bool Success { get; set; } = false;
public object? Data { get; set; }
public object? Error { get; set; }
}
所以每个响应都是 200OK 成功响应,如果有异常详细信息。
ex: if there are no errors, 'Success' = 'true', has 'Data' and 'Error' = null. If there are errors, 'Success' = 'false', has 'Error' and 'Data' = null.
我已经有了其他值的方法。我只需要修改 API 响应,SampleResponse
的例外情况
我怎样才能做到这一点?
您可以通过两种方式实现。
通用操作:有一个static
方法来接受所需的输入,自定义和格式化响应。
- 响应包装器的中间件。
- 在返回响应之前在每个控制器方法中调用静态方法。
工作样本:https://github.com/nayanbunny/dotnet-webapi-response-wrapper-sample
请求Url可以从HttpContext
获得
using Microsoft.AspNetCore.Http.Extensions;
// GetDisplayUrl(), GetEncodedUrl(), Path etc.
var requestUrl = HttpContext.Current.Request.GetDisplayUrl()
普通静态方法
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
public static class ResponseWrapManager
{
public static SampleResponse ResponseWrapper(object? result, HttpContext context, object? exception = null) {
requestUrl = context.Request.GetDisplayUrl();
requestUrlFormat = string.Empty;
status = result != null;
data = result;
error = exception != null ? ExceptionWrapper(exception) : null;
// NOTE: Add any further customizations if needed
var response = new SampleResponse {
RequestUrl = requestUrl,
RequestUrlFormat = requestUrlFormat,
Status = status,
Data = data,
Error = error
};
return response;
}
}
选项 1:响应包装器中间件
ResponseWrapperMiddleware.cs
using Newtonsoft.Json;
public class ResponseWrapperMiddleware
{
private readonly RequestDelegate _next;
public ResponseWrapperMiddleware(RequestDelegate next) => _next = next;
public async Task Invoke(HttpContext context)
{
// Storing Context Body Response
var currentBody = context.Response.Body;
// Using MemoryStream to hold Controller Response
using var memoryStream = new MemoryStream();
context.Response.Body = memoryStream;
// Passing call to Controller
await _next(context);
// Resetting Context Body Response
context.Response.Body = currentBody;
// Setting Memory Stream Position to Beginning
memoryStream.Seek(0, SeekOrigin.Begin);
// Read Memory Stream data to the end
var readToEnd = new StreamReader(memoryStream).ReadToEnd();
// Deserializing Controller Response to an object
var result = JsonConvert.DeserializeObject(readToEnd);
var exception = ""; // Exception Caught
// Invoking Customizations Method to handle Custom Formatted Response
var response = ResponseWrapManager.ResponseWrapper(result, context, exception);
// return response to caller
await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
}
}
Startup.cs (.Net < 6.0)
public void Configure(...)
{
...
app.UseMiddleware<ResponseWrapperMiddleware>();
...
}
Program.cs (.Net >= 6.0)
app.UseMiddleware<ResponseWrapperMiddleware>();
选项 2:控制器方法中的响应格式
TextController.cs
[HttpGet(Name="GetTestData")]
public IEnumerable<Test> Get()
{
result = new Enumerable.Range(1,5).Select(index => new Test {
Id = index,
Name = $"Test {index}"
});
return ResponseWrapManager.ResponseWrapper(result, HttpContext, exception)
}
我正在使用 Angular 客户端开发 .Net Core API 项目。而APIProgram.cs文件配置如下,
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://127.0.0.1", "http://localhost", "https://127.0.0.1", "https://localhost")
.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHsts();
app.UseHttpsRedirection();
// non-api routes Spa
app.Use(async (context, next) =>
{
await next();
string path = context.Request.Path.Value == null ? "" : context.Request.Path.Value;
bool isNotFound = context.Response.StatusCode == 404;
bool isApiRequest = path.StartsWith("/api/");
bool hasPathExtension = Path.HasExtension(path);
if (isNotFound && !(isApiRequest || hasPathExtension))
{
context.Request.Path = "/index.html";
await next();
}
});
app.UseDefaultFiles();
app.UseStaticFiles();
// app.UseCookiePolicy();
app.UseRouting();
// app.UseRequestLocalization();
if (app.Environment.IsDevelopment())
{
app.UseCors();
}
//app.UseAuthentication();
app.UseAuthorization();
// app.UseSession();
// app.UseResponseCompression();
// app.UseResponseCaching();
//app.MapRazorPages();
app.MapControllers();
app.Run();
我需要做的是将每个控制器的响应、异常包装到全局的通用响应结构中(使用中间件或任何其他方法),如下所示,
[Serializable]
public class SampleResponse
{
public string? RequestUrlFormat { get; set; }
public string? RequestUrl { get; set; }
public bool Success { get; set; } = false;
public object? Data { get; set; }
public object? Error { get; set; }
}
所以每个响应都是 200OK 成功响应,如果有异常详细信息。
ex: if there are no errors, 'Success' = 'true', has 'Data' and 'Error' = null. If there are errors, 'Success' = 'false', has 'Error' and 'Data' = null.
我已经有了其他值的方法。我只需要修改 API 响应,SampleResponse
我怎样才能做到这一点?
您可以通过两种方式实现。
通用操作:有一个static
方法来接受所需的输入,自定义和格式化响应。
- 响应包装器的中间件。
- 在返回响应之前在每个控制器方法中调用静态方法。
工作样本:https://github.com/nayanbunny/dotnet-webapi-response-wrapper-sample
请求Url可以从HttpContext
using Microsoft.AspNetCore.Http.Extensions;
// GetDisplayUrl(), GetEncodedUrl(), Path etc.
var requestUrl = HttpContext.Current.Request.GetDisplayUrl()
普通静态方法
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
public static class ResponseWrapManager
{
public static SampleResponse ResponseWrapper(object? result, HttpContext context, object? exception = null) {
requestUrl = context.Request.GetDisplayUrl();
requestUrlFormat = string.Empty;
status = result != null;
data = result;
error = exception != null ? ExceptionWrapper(exception) : null;
// NOTE: Add any further customizations if needed
var response = new SampleResponse {
RequestUrl = requestUrl,
RequestUrlFormat = requestUrlFormat,
Status = status,
Data = data,
Error = error
};
return response;
}
}
选项 1:响应包装器中间件
ResponseWrapperMiddleware.cs
using Newtonsoft.Json;
public class ResponseWrapperMiddleware
{
private readonly RequestDelegate _next;
public ResponseWrapperMiddleware(RequestDelegate next) => _next = next;
public async Task Invoke(HttpContext context)
{
// Storing Context Body Response
var currentBody = context.Response.Body;
// Using MemoryStream to hold Controller Response
using var memoryStream = new MemoryStream();
context.Response.Body = memoryStream;
// Passing call to Controller
await _next(context);
// Resetting Context Body Response
context.Response.Body = currentBody;
// Setting Memory Stream Position to Beginning
memoryStream.Seek(0, SeekOrigin.Begin);
// Read Memory Stream data to the end
var readToEnd = new StreamReader(memoryStream).ReadToEnd();
// Deserializing Controller Response to an object
var result = JsonConvert.DeserializeObject(readToEnd);
var exception = ""; // Exception Caught
// Invoking Customizations Method to handle Custom Formatted Response
var response = ResponseWrapManager.ResponseWrapper(result, context, exception);
// return response to caller
await context.Response.WriteAsync(JsonConvert.SerializeObject(response));
}
}
Startup.cs (.Net < 6.0)
public void Configure(...)
{
...
app.UseMiddleware<ResponseWrapperMiddleware>();
...
}
Program.cs (.Net >= 6.0)
app.UseMiddleware<ResponseWrapperMiddleware>();
选项 2:控制器方法中的响应格式
TextController.cs
[HttpGet(Name="GetTestData")]
public IEnumerable<Test> Get()
{
result = new Enumerable.Range(1,5).Select(index => new Test {
Id = index,
Name = $"Test {index}"
});
return ResponseWrapManager.ResponseWrapper(result, HttpContext, exception)
}