How to write custom actionResult in asp.net core

30,505

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.

Share:
30,505

Related videos on Youtube

Binson Eldhose
Author by

Binson Eldhose

A programmer,

Updated on July 18, 2022

Comments

  • Binson Eldhose
    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
    Binson Eldhose about 7 years
    But 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
    juunas about 7 years
    @BinsonEldhose See my updated example. That would be the job of ObjectResult.
  • juunas
    juunas about 7 years
    Absolutely, you could use an exception filter to achieve the same thing.
  • David Noreña
    David Noreña almost 7 years
    nice example man, but what about folder structure for custom actionresults like this ?
  • juunas
    juunas almost 7 years
    You 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
    George Taskos over 6 years
    How do you unit test TestActionResult? I am curious to make sure the ActionContext is mocked and assert for the expected results;
  • juunas
    juunas over 6 years
    Try yourself. If you have a specific problem, write a new question.
  • JB's
    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 this await customObjectResult.ExecuteResultAsync(context); but the response json only had data no other values. Is it because ObjectResult ctr takes data and the output is only data? If so how can I achieve the intended result?
  • Ross
    Ross about 5 years
    Fantastic! Thanks!
  • Jason
    Jason about 2 years
    Not sure why this was downvoted. Worked great for a local web api returning a message in an unsuccessful result without including the exception detail.