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?)
You can do this:
return new ObjectResult("The message") {
StatusCode = (int?) HttpStatusCode.Unauthorized
};
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.
Hope it helps :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With