I need to return a consistent response with a similar structure returned for all requests. In the previous .NET web api, I was able to achieve this using DelegatingHandler (MessageHandlers). The object that I want to return will be encapsulated in the Result element. So basically the json response will be in this kind of structure:
Example 1:
{ "RequestId":"some-guid-abcd-1234", "StatusCode":200, "Result": { "Id":42, "Todo":"Do Hello World" } }
Example 2:
{ "RequestId":"some-guid-abcd-1235", "StatusCode":200, "Result": { [ { "Id":42, "Todo":"Print Hello World" }, { "Id":43, "Todo":"Print Thank you" } ] } }
In .NET core, it looks like I need to do this via middleware. I tried but I don't see a nicer way to extract the content like how in the previous web API when you can call HttpResponseMessage.TryGetContentValue
to get the content and wrap it in global/common response model.
How can I achieve the same in .NET core?
I created a middleware to wrap the response for consistency. I also created an extension method to IApplicationBuilder for convenience when registering this middleware. So in Startup.cs, register middleware :
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { //code removed for brevity. ... app.UseResponseWrapper(); //code removed for brevity. ... }
And here's the middleware code:
using System; using System.IO; using System.Net; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Http; using Newtonsoft.Json; namespace RegistrationWeb.Middleware { public class ResponseWrapper { private readonly RequestDelegate _next; public ResponseWrapper(RequestDelegate next) { _next = next; } public async Task Invoke(HttpContext context) { var currentBody = context.Response.Body; using (var memoryStream = new MemoryStream()) { //set the current response to the memorystream. context.Response.Body = memoryStream; await _next(context); //reset the body context.Response.Body = currentBody; memoryStream.Seek(0, SeekOrigin.Begin); var readToEnd = new StreamReader(memoryStream).ReadToEnd(); var objResult = JsonConvert.DeserializeObject(readToEnd); var result = CommonApiResponse.Create((HttpStatusCode)context.Response.StatusCode, objResult, null); await context.Response.WriteAsync(JsonConvert.SerializeObject(result)); } } } public static class ResponseWrapperExtensions { public static IApplicationBuilder UseResponseWrapper(this IApplicationBuilder builder) { return builder.UseMiddleware<ResponseWrapper>(); } } public class CommonApiResponse { public static CommonApiResponse Create(HttpStatusCode statusCode, object result = null, string errorMessage = null) { return new CommonApiResponse(statusCode, result, errorMessage); } public string Version => "1.2.3"; public int StatusCode { get; set; } public string RequestId { get; } public string ErrorMessage { get; set; } public object Result { get; set; } protected CommonApiResponse(HttpStatusCode statusCode, object result = null, string errorMessage = null) { RequestId = Guid.NewGuid().ToString(); StatusCode = (int)statusCode; Result = result; ErrorMessage = errorMessage; } } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With