How to throw exception in Web API? - c#

How can I throw a exception to in ASP.net Web Api?
Below is my code:
public Test GetTestId(string id)
{
Test test = _test.GetTest(id);
if (test == null)
{
throw new HttpResponseException(HttpStatusCode.NotFound);
}
return test;
}
I don't think I am doing the right thing, How do my client know it is a HTTP 404 error?

It's absolutely fine.
Alternatively, if you wish to provide more info (to allow, as you say, the client to distinguish from regular 404):
if (test == null)
{
throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound,
"this item does not exist"));
}

This blogpost should help you understand WebAPI error handling a bit better.
What you have in your code snippet should work. The server will send back a 404 Not Found to the client if test is null with no response body. If you want a response body, you should consider using Request.CreateErrorResponse as explained in the blog post above and passing that response to the HttpResponseException.

Related

Xero webhook not working says "Response contained a body"

I am trying to get a webhook setup with Xero working locally. I am using ngrok to allow xero to call my localhost. To get the webhook working I must correctly return the "intent to receive"
It seems to be working fine in that I can debug it and follow it through. However when I try to return 200 for success (hashes match) or 401 unauthorized (hashes don't match) the receiving Xero still doesn't accept it. All it says is: "Response contained a body"
According to the Xero webhook docs my endpoint must ensure:
It uses HTTPS
It responds within 5 seconds with a 200 O.K status code
There is no body in the response
There are no cookies in the response headers
If the signature is invalid a 401 Unauthorised status code is returned
I have tried returning the code in various ways:
public IHttpActionResult WebHooks()
{
//if hash check fails I tried these
return Unauthorized();
return Request.CreateResponse((int)HttpStatusCode.Unauthorized);
return StatusCode(HttpStatusCode.Unauthorized);
//if hash check matched I tried the following
return Ok();
return Request.CreateResponse((int)HttpStatusCode.OK);
return StatusCode(HttpStatusCode.OK);
}
In seething desperation I also tried
public int WebHooks()
{
//if hash check matches
return 200;
//if hash check fails
return 401;
}
Thank you in advance for your help. I spent too long searching for an existing answer, but I couldn't find any. What am I doing wrong? As far as I can see my webapi should work.
Figured it out. This is what I did to get it working:
if (hashedPayload != xeroSignature)
{
ControllerContext.HttpContext.Response.Clear();
ControllerContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
ControllerContext.HttpContext.Response.End();
return Content(string.Empty);
}
ControllerContext.HttpContext.Response.Clear();
ControllerContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.OK;
return Content(string.Empty);
Nothing I tried worked and my swear-jar overfloweth. I noticed through ngrok that the "intent to receive" would return a 302 (as opposed to 401) and then would redirect to Account/Login.
This led me down a rabbit hole to where I discovered the answer
To quote:
If you are adding asp.net WebApi inside asp.net MVC web site you
probably want to respond unauthorized to some requests. But then
ASP.NET infrastructure come into play and when you try to set response
status code to HttpStatusCode.Unauthorized you will get 302 redirect
to login page.
That was exactly the behaviour I saw. When I tried the webhook in a new webapi project with only one method - it worked. However I want to get it working in my MVC site. I added what this post suggested and it now works perfectly for me.
Many thanks to #Jacob Alley

ASP.NET WebHookReceiver "return HttpStatusCode.Unauthorized" returns HTML instead

I'm developing a webhook receiver for an external tool.
I’m using ASP.NET WebHooks framework (more : https://learn.microsoft.com/en-us/aspnet/webhooks/ )
Everything is working great, except one thing : I can’t return a HttpStatusCode.Unauthorized.
This is a structure of code in WebHookReceiver :
public override async Task<HttpResponseMessage> ReceiveAsync(string id, HttpRequestContext context, HttpRequestMessage request)
{
try
{
var authheader = request.Headers.Authorization;
if (authheader == null || string.IsNullOrEmpty(authheader.Parameter))
{
return new HttpResponseMessage(HttpStatusCode.Unauthorized);
}
I was expecting a simple HTTP response with the code HttpStatusCode.Unauthorized (Side note, ANY other Http code works as expected). Instead it returns the whole HTML Microsoft login page. I don’t even know where it’s taking it from.
My solution for now is just returning “BadRequest” and message “Authorization failed”
Ok got it.
This is perfectly normal.
https://www.restapitutorial.com/httpstatuscodes.html
The request requires user authentication. The response MUST include a
WWW-Authenticate header field (section 14.47) containing a challenge
applicable to the requested resource.
For my case, I should use 403 Forbidden

asp.net MVC controller - What should controller return if user is unauthorized?

So I have this code inside the controller of my MVC for a page
[HttpGet, Route]
[Authorize(nameof(Access))]
public async Task<ActionResult> ListStuff()
{
var canRead = HasAccess()
if(!canRead)
{
throw new HttpResponseException(HttpStatusCode.Unauthorized);
}
}
I'm using C# attributes for security validation and what I want is if the attribute with the 'HasAccess()' function returns false then the page show show an 'unauthorized' error, as you guys can see I tried throwing an HttpResponseException, I'm pretty sure this isn't the proper way to do it. Any suggestions?
You send a GET http request to your running service, eg:http://localhost:8080/Myservice.svc/$metadata. I've used postman in the past to help with sending http requests.
Link to free postman

What to return when a route/url is found but not the resource behind it?

When a route customer/1 exists but the resource/entity behind the customer search does not exist,
Should I return a 404? I mean the route exists...
or should I return a
204 (No content) because I could not find a customer and the result is empty.
Microsoft sample:
public IHttpActionResult Get (int id)
{
Product product = _repository.Get (id);
if (product == null)
{
return NotFound(); // Returns a NotFoundResult
}
return Ok(product); // Returns an OkNegotiatedContentResult
}
In my opinion a NotFound() => 404 is not correct here?!
CLARIFICATION/IMPROVEMENT of my question.
I need to distinguish between a
1) route: customer/1 => route does not exist
( I would return here 404, but this is anyway handled by the framework...)
2) route: customer/1 => exists but the resource/entity in database NOT
( I would return here a 404)
3) route: customersSearch/searchterm => the resource/entity in database is not found
( I would return a 204 )
Would you please be that kind and correct your answer to this more clear question please?
General REST guidelines state that in this instance you should return a 404. You have asked for a specific resource that doesn't exist. As if you had requested a physical document from a website.
At all my work places that has been the pattern and issued by the enterprise architecture teams :)
A word of advice though... have some form of logging for this scenario so you can detect a "logical" 404 (in this scenario) versus a true no resource / handler / script mapping was available to service the request! At least to identify issues at deploy time :)
Its a design question but I agree with you that 404 is probably not the appropriate status code here since 4xx means client error. I would pick something from 2xx(204 is indeed a good choice here) or 5xx. For your reference, here's RFC for http status codes:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
Based on your update, 204 is an acceptable return code.
I tend to use a custom HTTP Reason Phrase to differentiate that the 404 was due to a resource not being found as opposed to a malformed URL resulting in an incorrect Route. The 404 is still the correct response code to use under all 3 scenarios, yet if you are trying to make development time easier by differentiating the reasons, then use a different reason phrase.
e.g.
Incorrect route returns default 404 Not Found
Correct route, but no resource with that ID found 404 Customer Not Found
Correct route, but no resources found that match the search criteria 404 No Customers Found
I interpret 204 as different from the above comments in that the 204 spec states (emphasis mine):
The server has fulfilled the request but does not need to return an entity-body
in this scenario, the api did need to return an entity-body, it simply wasn't able to because the requested information wasn't available. Hence it was Not Found
Example of how to return a custom reason phrase in Web API.
public IHttpActionResult Get (int id)
{
Product product = _repository.Get (id);
if (product == null)
{
var response = Request.CreateErrorResponse(HttpStatusCode.NotFound, "");
response.ReasonPhrase = "Product Not Found";
return response;
}
return Ok(product); // Returns an OkNegotiatedContentResult
}

System.Net HttpStatusCode class does not have code 422

Is there a way to handle http status code 422 gracefully. I am looking for the best practice here. I know that HttpStatusCode is an enum so what i tried is this,
HttpStatusCode Unprocessable = (HttpStatusCode)422;
if (Response == (HttpStatusCode)422)
but does not allow me to compare it. Am i doing something wrong here?
Whats the best possible way to add this status code at runtime.
I was using RestSharp which returns the server response status code in a property of type HttStatusCode and I needed to check for a 422 response myself but the of course the type doesn't include it. Fortunately I was still able to test using the following:
if(response.StatusCode == (HttpStatusCode)422)
{
// Do my stuff..
}
The older versions of .NET don't have this HTTP status code but some of the newer ones do (See MS Docs).
If you are using one of the older frameworks, then you can get the response and check the StatusCode like the following (like Nick said):
var httpResponseCode = Response as HttpWebResponse;
if (httpResponseCode.StatusCode == (HttpStatusCode)422)
{
//your code here
}
If more than one action in your API can possibly return a 422, you could consider wrapping the check in an extension method like so:
public static bool IsUnprocessableEntityResponse(this HttpResponseMessage message)
{
Requires.NotNull(message, nameof(message));
return (int) message.StatusCode == StatusCodes.Status422UnprocessableEntity;
}
Which you can then use in your client like so:
if (response.IsUnprocessableEntityResponse())
return Response.UnprocessableEntity<Resource>();
While also avoiding the 422 magic number in your source code at the same time.

Categories