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.
Related
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
Currently I have 3rd party WebApi which has the following external call using Flurl builder.
await _client.Url.ToString().PostJsonAsync(data);
And I'm trying to handle the response with such endpoint:
[HttpPost]
public void HandleResponse(HttpResponseMessage response)
{
}
The response message is with status OK but has Content and Headers = null
How can I handle this properly?
This API endpoint doesn't make any sense to me:
[HttpPost]
public void HandleResponse(HttpResponseMessage response)
{
//...
}
The endpoint would be handling a request and returning a response, not the other way around. Something more like this:
[HttpPost]
public HttpResponseMessage HandleResponse(HttpRequestMessage request)
{
//...
}
When something contacts an API (or server of any kind, really), it's sending a request to that API. That API receives the request and returns a response. The semantics of these two words pretty much describe the process, it's very important to keep them straight.
Consider it like this... If someone asks you a question, what you receive is a question. Not an answer. What you send back to that person is the answer.
I'm writing a REST API with NancyFx. I often got code like this:
Post["/something"] = _ => {
// ... some code
if (success)
return HttpStatusCode.OK;
else
return someErrorObject;
};
The client always assumes application/json as the content type of all responses. It actually sets Accept: application/json in the request. Responses without application/json are errors regardless of the actual body. It simply checks the content type and aborts if it doesn't match json. I can't change this behaviour.
Now I face the problem that by simply returning HttpStatusCode.OK Nancy sets Content-Type: text/html but as said the client assumes application/json and fails with an error even the body is empty.
I was able to force the content type like this:
return Negotiate
.WithContentType("application/json")
.WithStatusCode(HttpStatusCode.OK);
I don't want to repeat this code everywhere. Of course I could abstract that in a single function but I'm looking for a more elegant solution.
Is there a way to override the default Content-Type of respones so that return HttpStatusCode.OK sets my Content-Type to application/json?
Based on the assumption of wanting to return all responses as JSON you will need a custom bootstrapper. You can enhance this further if you like by using an insert as opposed to clearing the response processors thus the fallback of using the XML processor etc is possible.
This will get automatically picked up by Nancy by the way no additional configuration required.
public class Bootstrap : DefaultNancyBootstrapper
{
protected override NancyInternalConfiguration InternalConfiguration
{
get
{
return NancyInternalConfiguration.WithOverrides(
(c) =>
{
c.ResponseProcessors.Clear();
c.ResponseProcessors.Add(typeof(JsonProcessor));
});
}
}
}
I have written a ServiceHelper class that will assist with POST's to a C# Web API controller
public class ServiceHelper<TResponse, TRequest> : IServiceHelper<TResponse, TRequest>
{
public TResponse Execute
(
string endpoint,
string controller,
string action,
TRequest request,
string format = "application/json"
)
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri(endpoint);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(format));
var response = httpClient.PostAsJsonAsync(String.Format("{0}/{1}", controller, action),
request).Result;
return response.Content.ReadAsAsync<TResponse>().Result;
}
}
}
I keep on getting
Additional information: No MediaTypeFormatter is available to read an object of type 'ReadMotorVehiclesWorkflowResponse' from content with media type 'text/html'.
Any ideas on how to fix this?
Apparently the server returns HTML where you expect JSON, and obviously there is no way to deserialize a TResponse from HTML...
I suspect the server is actually returning an error code, and the HTML is just a visual representation of the error.
You should call response.EnsureSuccessStatusCode() to make sure the response indicates success (typically 200 OK). If it's not the case, it will raise an exception.
Ok, the problem was that the application pool's .NET version was set to version 2.0 while the web API was written for .NET version 4.0, I changed the version and it is now working as expected.
It is worth while to note that it is a good idea to call response.EnsureSuccessStatusCode() as mentioned in the answer below.
Since ASP.NET Web API RC I was using some approach based on declaring void API controller's operations.
I was customizing a response object DTO (instead of using HttpResponseMessage) using AOP and PostSharp, and finally this was sent to the client using HttpContext.Response.Write(...) serializing the DTO into a JSON string.
When I upgraded my solution to ASP.NET Web API RTM, this approach didn't work anymore.
Whenever I send a response from the Web API and I receive it in the client-side, I find that the response is sent with a 204 status (NoContent) while I was setting a 200 status (OK) for the response itself.
Because this approach was working in the RC version of WebAPI I suspect that's an unknown breaking change when WebAPI development team transitioned to RTM version.
Am I wrong?
As far as I know, since RTM if a POST action does not return an HttpResponseMessage the default status code is 204 (and not 200 as was back in RC). There are two things, I know, we can do to keep clients from complaining about 204.
a) Change the response message from within your action:
[HttpPost]
public HttpResponseMessage DoWork(MyModel model)
{
// Do work
return new HttpResponseMessage(HttpStatusCode.OK) { Content = new ObjectContent<MyModel>(model, FormatterConfig.JsonFormatter) };
}
b) Change the response in a DelegatingHandler (dirty by generic way)
public class ResponseHandler : DelegatingHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var response = base.SendAsync(request, cancellationToken);
response.Result.StatusCode = response.Result.IsSuccessStatusCode ? System.Net.HttpStatusCode.OK : response.Result.StatusCode;
return response;
}
}
I am not aware of such breaking change but I can confirm that this doesn't work in the RTM. Anyway, that's such a wrong approach of using the Web API that it's probably a good thing that it doesn't work. You are killing the whole point of the Web API if you are going to manually write the response to the client. If you have some existing code that does this that you cannot modify then I would recommend you using a Generic ASHX handler until you are ready to upgrade.