6

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?)

4
  • You can't set a status code after you write any portion of the response body. Have you tried calling HttpUnauthorizedResult.ExecuteResultAsync before writing your message? Commented Mar 24, 2016 at 2:38
  • 1
    looks this link may solve your problem weblogs.asp.net/gunnarpeipman/… Commented Mar 24, 2016 at 3:02
  • @Gomes that looks very promising! I suppose conceptually it makes sense, shall have to take a look soon! Commented Mar 24, 2016 at 3:05
  • @Gomes unfortunately that doesn't solve my issue, the StatusDescription property is no longer a thing... Commented Mar 24, 2016 at 4:06

3 Answers 3

11

You can do this:

return new ObjectResult("The message") { 
    StatusCode = (int?) HttpStatusCode.Unauthorized 
};
Sign up to request clarification or add additional context in comments.

Comments

5

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 :)

1 Comment

it's a bit odd to return 403 - Forbidden and call it Unauthorized (which is 401)
-1

You can return any status code you want, like so:

return new HttpStatusCodeResult(403);

1 Comment

It's not the status code that's the problem, it's adding some text to the response body along with a status code that's proving to be challenging.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.