Search code examples
c#.net-coreactionresult

Return new ActionResult with value without using ControllerBase


I need to return an ActionResult containing an object, however, I do not inherit from ControllerBase, so I'm unable to use the Ok, BadRequest etc. methods. How can I do this?


More info:

The reason I do not inherit from ControllerBase is that I hold a generic Response object, which contains a method that returns an ActionResult. The logic to determine which ActionResult should be returned will be in this method.


I've tried:

  • ContentResult
    This gives me the option to provide a value, but only accepts a string Content value.

  • StatusCodeResult
    This doesnt give me the option to provide an object to use as the value.

  • OkResult, BadRequest etc.
    This doesnt give me the option to specify a value.


My Code:

public enum ResponseStatus 
{
    Ok, 
    BadRequest,
    // ...
}

public class ResponseObject<T>
{
    public ResponseStatus Status { get; set; }
    public T Value { get; set; }

    public ActionResult ToActionResult()
    {
        switch (Status)
        {
            case ResponseStatus.Ok:
               return new SomethingThatIsOk(this); // this doesnt exist, I dont know to return, hence the question

            case ResponseStatus.BadRequest:
               return new SomethingThatIsBadRequest(this); // this doesnt exist, I dont know to return, hence the question

            // ...
        }
    }
}

Solution

  • There are multiple derived results that can be used to get the desired behavior.

    public class ResponseObject<T> {
        public ResponseStatus Status { get; set; }
        public T Value { get; set; }
    
        public ActionResult ToActionResult() {
            switch (Status) {
                case ResponseStatus.Ok:
                   return new OkObjectResult(this);
    
                case ResponseStatus.BadRequest:
                   return new BadRequestObjectResult(this);
    
                // ...
            }
        }
    }
    

    Use the one appropriate to your desired status.

    ObjectResult Class has a few derived classes that worked for this scenario,

    Microsoft.AspNetCore.Mvc.AcceptedAtActionResult
    Microsoft.AspNetCore.Mvc.AcceptedAtRouteResult
    Microsoft.AspNetCore.Mvc.AcceptedResult
    Microsoft.AspNetCore.Mvc.BadRequestObjectResult
    Microsoft.AspNetCore.Mvc.ConflictObjectResult
    Microsoft.AspNetCore.Mvc.CreatedAtActionResult
    Microsoft.AspNetCore.Mvc.CreatedAtRouteResult
    Microsoft.AspNetCore.Mvc.CreatedResult
    Microsoft.AspNetCore.Mvc.NotFoundObjectResult
    Microsoft.AspNetCore.Mvc.OkObjectResult
    Microsoft.AspNetCore.Mvc.UnauthorizedObjectResult
    Microsoft.AspNetCore.Mvc.UnprocessableEntityObjectResult
    System.Web.Http.BadRequestErrorMessageResult
    System.Web.Http.ExceptionResult
    System.Web.Http.InvalidModelStateResult
    System.Web.Http.NegotiatedContentResult<T>
    System.Web.Http.ResponseMessageResult
    

    but I would suggest you review the API documentation for any other classes that may suit your needs.

    All the ControllerBase does is wrap the creation of the result in a method

    /// <summary>
    /// Creates an <see cref="OkObjectResult"/> object that produces an <see cref="StatusCodes.Status200OK"/> response.
    /// </summary>
    /// <param name="value">The content value to format in the entity body.</param>
    /// <returns>The created <see cref="OkObjectResult"/> for the response.</returns>
    [NonAction]
    public virtual OkObjectResult Ok([ActionResultObjectValue] object value)
        => new OkObjectResult(value);
    

    Source

    /// <summary>
    /// Creates an <see cref="BadRequestObjectResult"/> that produces a <see cref="StatusCodes.Status400BadRequest"/> response.
    /// </summary>
    /// <param name="error">An error object to be returned to the client.</param>
    /// <returns>The created <see cref="BadRequestObjectResult"/> for the response.</returns>
    [NonAction]
    public virtual BadRequestObjectResult BadRequest([ActionResultObjectValue] object error)
        => new BadRequestObjectResult(error);
    

    Source