My controller:
public class MyController : ControllerBase
{
[HttpGet("/getResponse/{userId}")]
public async Task<MyResponse> GetResponseAsync(long userId)
{
return await _myService.GetResponseAsync(userId);
}
[HttpGet("/getUser/{userId}")]
public async Task<MyUser> GetUserAsync(long userId)
{
return await _myService.GetUserAsync(userId);
}
}
though my controller returns an object of MyResponse
or MyUser class, I want to return a custom generic response object i.e.
public class ApiResponse
{
public object Response { get; set; }
public bool IsSuccess { get; set; }
public IList<string> Errors { get; set; }
public ApiResponse(object response, bool success, IList<string> errors = null)
{
this.Response = response;
this.IsSuccess = success;
this.Errors = errors;
}
public ApiResponse()
{
}
}
I tried to use IActionFilter's OnActionExecuted(ActionExecutedContext context) to read the response object, but I don't see any response of MyUser or MyResponse object in the body when i debug for variable a.
public void OnActionExecuted(ActionExecutedContext context)
{
ApiResponse _response = new ApiResponse();
var httpResponse = context.HttpContext.Response;
if (httpResponse != null)
{
if (httpResponse.StatusCode == 200)
{
var a = httpResponse.Body;
}
}
}
Is there a way to read the type of object and assign that particular object to the ApiResponse.response proeperty?
CodePudding user response:
There are a few types of MVC filters, and IActionFilter is not the best tool for this job. What you want is ResultFilter.
Please take a look at official documentation here https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-6.0 for more details.
An answer provided here may also be useful for you: https://stackoverflow.com/a/64725441/2895299
However, it is going to work with your filter implementation as well, you're just looking for a response object in wrong place. Your object is going to be accessible under:
context.Result
Response in HttpContext object is going to be accessible later, not at filter stage of MVC pipeline. Please observe, that context.HttpContext.Response.HasStarted is equal to false.
CodePudding user response:
There's already IETF RFC 7807 for HTTP API problem responses, with its own content type, application/problem json
. ASP.NET Core uses it to return automatic model validation failure responses.
It's a bad idea to use a custom format when there's a standard that's actually used by clients and libraries.
Example responses can be :
HTTP/1.1 403 Forbidden
Content-Type: application/problem json
Content-Language: en
{
"type": "https://example.com/probs/out-of-credit",
"title": "You do not have enough credit.",
"detail": "Your current balance is 30, but that costs 50.",
"instance": "/account/12345/msgs/abc",
"balance": 30,
"accounts": ["/account/12345",
"/account/67890"]
}
Or
HTTP/1.1 400 Bad Request
Content-Type: application/problem json
Content-Language: en
{
"type": "https://example.net/validation-error",
"title": "Your request parameters didn't validate.",
"invalid-params": [ {
"name": "age",
"reason": "must be a positive integer"
},
{
"name": "color",
"reason": "must be 'green', 'red' or 'blue'"}
]
}
ASP.NET Core uses the ProblemDetails and the more specific ValidationProblemDetails classes to report errors.
It's possible to send a Problem or ValidationProblem response using the Problem or ValidationProblem functions, eg:
var details=new ValidationProblemDetails(someDictionary);
return ValidationProblem(details);
The Handle errors in ASP.NET Core web APIs article shows how ASP.NET Core can be configured to returns customized ProblemDetails for specific exceptions