Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asp.net 5 web api return status code and body

I'm working on a project using ASP.NET 5 and I'm writing a web api.

I've inherited some code and database stored procedures that use raiserror to indicate something is wrong (username/password incorrect, expired license etc).

The stored procedure returns nothing to uniquely identify that error, except the message text.

I want to be able to return a HTTP UNAUTHORIZED response, but also shuttle the error message along to the client too.

The built in IActionResult HttpUnauthorized() method doesn't allow for a reason to be given.

So I wrote my own ActionResult that looks like this:

public class UnauthorizedWithMessageResult : IActionResult
{
    private readonly string _message;

    public UnauthorizedWithMessageResult(string message)
    {
        _message = message;
    }

    public async Task ExecuteResultAsync(ActionContext context)
    {
        using (var sw = new HttpResponseStreamWriter(context.HttpContext.Response.Body, Encoding.UTF8))
        {
            await sw.WriteLineAsync(_message);
        }

        await new HttpUnauthorizedResult().ExecuteResultAsync(context);
    }
}

The problem is that the client is receiving a 200-OK like everything is fine.

I've stepped through this and after the delegation to HttpUnauthorizedResult has been done, the status code is indeed set to 403.

It looks like Web API is (at some point) seeing that there's content in the body of the response and decides that means everything is OK and resets the status code.

Is there any way to get around this without having to resort to sending the message as a header or something? (or is that the correct way to do this?)

like image 815
Clint Avatar asked Mar 24 '16 02:03

Clint


2 Answers

You can do this:

return new ObjectResult("The message") { 
    StatusCode = (int?) HttpStatusCode.Unauthorized 
};
like image 74
CSJ Avatar answered Nov 14 '22 23:11

CSJ


It works this way:

public IActionResult IWillNotBeCalled()
{
    return new UnauthorizedWithMessageResult("MY SQL ERROR");            
}

public class UnauthorizedWithMessageResult : IActionResult
{
    private readonly string _message;

    public UnauthorizedWithMessageResult(string message)
    {
        _message = message;
    }

    public async Task ExecuteResultAsync(ActionContext context)
    {
        // you need to do this before setting the body content
        context.HttpContext.Response.StatusCode = 403;

        var myByteArray = Encoding.UTF8.GetBytes(_message);
        await context.HttpContext.Response.Body.WriteAsync(myByteArray, 0, myByteArray.Length);
        await context.HttpContext.Response.Body.FlushAsync();
    }
}

You have to set the StatusCode before setting the body and you have to flush the body stream to be sure that the content will be set inside the response.

enter image description here

Hope it helps :)

like image 29
Luca Ghersi Avatar answered Nov 15 '22 00:11

Luca Ghersi