How to write custom actionResult in asp.net core
Solution 1
Here is an example:
public class TestResult
{
public Exception Exception { get; set; }
public object Data { get; set; }
}
public class TestActionResult : IActionResult
{
private readonly TestResult _result;
public TestActionResult(TestResult result)
{
_result = result;
}
public async Task ExecuteResultAsync(ActionContext context)
{
var objectResult = new ObjectResult(_result.Exception ?? _result.Data)
{
StatusCode = _result.Exception != null
? StatusCodes.Status500InternalServerError
: StatusCodes.Status200OK
};
await objectResult.ExecuteResultAsync(context);
}
}
ObjectResult
is the type your results are converted if you return a non-IActionResult
from an action. It will do content negotiation for you.
You could also inherit from ObjectResult
and setup the status code and data to be written in the constructor.
More on content negotiation in ASP.NET Core: https://docs.microsoft.com/en-us/aspnet/core/mvc/models/formatting#content-negotiation
Solution 2
Despite @juunas answer is technically correct, what you really try to achieve is a custom error handling. And the better way is to decouple this logic using Action Filter, Middleware filter or the separate Middleware (depends on what scope you what to cover).
The main idea is that controller should not be responsible for handling exceptions. It should return expected result with OK status or say that something wrong (throw exception) and delegate to other parts of pipeline what to do with problem.
Look into SO: Error handling in ASP.NET Core 1.0 Web API (Sending ex.Message to the client) for examples. Also Error Handling in ASP.NET Core doc may be useful.
Related videos on Youtube
Comments
-
Binson Eldhose almost 2 years
In webApi2 i could write a custom ActionResult by inheriting IHttpActionResult.
Sample :
public class MenivaActionResult : IHttpActionResult { private readonly HttpRequestMessage _request; private readonly ServiceResponseBase _response; public MenivaActionResult(HttpRequestMessage request, ServiceResponseBase response) { _request = request; _response = response; } public Task<HttpResponseMessage> ExecuteAsync(CancellationToken token) { HttpResponseMessage httpresponseMessage = _response.Exception != null ? _request.CreateErrorResponse((HttpStatusCode)_response.HttpCode, _response.Exception.Message+":"+_response.Exception.HelpCode) : _request.CreateResponse((HttpStatusCode)_response.HttpCode, _response.Data); return Task.FromResult(httpresponseMessage); } }
The ServiceResponseBase class object holds all the exception and data from service layer..
How i can port this code to asp.net core. I tried but i dont know how create a response message from HttpRequestMessage object in .net core. The IActionResult only have
Task ExecuteResultAsync(ActionContext context)
method. how i can modify the response from this method -
Binson Eldhose about 7 yearsBut i need to pass objects than a simple string ,i need to to use the default content negotiation feature so cannot convert the object in to any form of string representation like json or xml. _request.CreateResponse((HttpStatusCode)_response.HttpCode, _response.Data); this line in my webapi2 automatically negotiate the data
-
juunas about 7 years@BinsonEldhose See my updated example. That would be the job of
ObjectResult
. -
juunas about 7 yearsAbsolutely, you could use an exception filter to achieve the same thing.
-
David Noreña almost 7 yearsnice example man, but what about folder structure for custom actionresults like this ?
-
juunas almost 7 yearsYou mean what should the folder name be for this class? That's up to you and your team :) I typically use a Results folder.
-
George Taskos over 6 yearsHow do you unit test TestActionResult? I am curious to make sure the ActionContext is mocked and assert for the expected results;
-
juunas over 6 yearsTry yourself. If you have a specific problem, write a new question.
-
JB's over 5 years@juunas I need to pass extra information like a message, requestId along with the result. What I did is inherit a class from
ObjectResult
, populated the custom object result via the ctr and did thisawait customObjectResult.ExecuteResultAsync(context);
but the response json only had data no other values. Is it becauseObjectResult
ctr takes data and the output is only data? If so how can I achieve the intended result? -
Ross about 5 yearsFantastic! Thanks!
-
Jason about 2 yearsNot sure why this was downvoted. Worked great for a local web api returning a message in an unsuccessful result without including the exception detail.