I'm calling a WebAPI controller from jQuery AJAX to request an item be deleted via a REST API.
The WebAPI controller returns a 204 (No Content) response, which then invokes a second request (GET). For this example I expect both requests to receive a 204 (No Content) response.
When viewed in Chrome both responses are fully recognised.
However, Firefox can't seem to cope with a 204 if it contains no content.
To obtain both the Chrome (above) and Firefox (below) screenshots the same requests were sent to a WebAPI controller from both browsers. The screenshot below shows that Firefox only recognises the first 204 response.
The response to these two requests is created differently:
The first response uses...
return Request.CreateResponse(HttpStatusCode.NoContent);
...which returns an instance of HttpResponseMessage.
The second response uses...
return new NoContentResult();
...which we've defined as an implementation of IHttpActionResult...
public class NoContentResult : IHttpActionResult
{
private readonly HttpRequestMessage _request;
public NoContentResult(HttpRequestMessage request)
{
_request = request;
}
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
var response = _request.CreateResponse(HttpStatusCode.NoContent, new StringContent("{}"));
return Task.FromResult(response);
}
}
The new StringContent("{}") on the 4th-from-last line is an attempt to provide some content to help Firefox. I've also tried new StringContent("null") with the same result.
Also, if that second response is inspected in Firefox, the following error message is found:
SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 of
the JSON data
It seems that Firefox is trying to parse this problematic 204, but it apparently makes no attempt to parse the first 204 response.
Furthermore, the request type (DELETE vs. GET) doesn't seem to matter: if I return 204 as an IHttpActionResult from the first call then Firefox still doesn't like it.
Firefox also displays the first response as containing 168 bytes and the second as containing 0 bytes even though it will happily display the headers (below). Firefox is clearly upset at something.
Can anyone explain why Firefox has a problem with a 204 response when delivered as an implementation of IHttpActionResult but not when it's delivered as an HttpResponseMessage?
[The reason that the first request returns an HttpResponseMessage while the second returns an IHttpActionResult is that the first method has been in place for a long time whereas the second method is only now being added. And as IHttpActionResult is easier to test, we'd like to use that.]
Related
public async Task<E.Translations> LoadTranslations(int Id)
{
using (HttpClient client = new HttpClient())
{
E.Translations Translations = new E.Translations();
Translations = await client.GetJsonAsync<E.Translations>(Config.GetEndpointURI($"{TRANSLATION}{Id}")).ConfigureAwait(true);
return Translations;
}
}
When using the pattern above to load JSON data into a class, in this case Translations, the method works as expected when a set of data is received with an HTTP 200 OK.
However, when an HTTP response of 204, 'No Content', is returned from the API the process appears to proceed no further with no examinable value of the class to be populated.
I've attempted examining the class for null and also tried wrapping a try/catch block around the GetJsonAsync part of the method to no avail. The process seems to halt at the GetJsonAsync call and with debugging being rather thin on the ground with Blazor it's not easy to determine what's actually happening at this point.
What I'd ideally like to accomplish would be to test the class to be populated for null or any other property value but this doesn't seem possible at the moment?
First of all, my English is not so good, I hope you understand what I am trying to say.
I'm new with WebApi's. I created one and all seems good. In my function I return a string, but when I test the web api with Postman it returns a status code 204 no content.
I looked for this status and apparently my request was succeded, but when I look at my database nothing happend. (my function saves some data in my database and returns a string when it is succeded or not).
So, my question is, Why am I receiving this status code when my function must to return a string? Or why when I test the Web Api with Postman it returns a 204 No Content code (that means my request was succeded) when is not true (because nothing was saved in my database)?
Here is my function in my web api:
[HttpPost]
public string IncomingPO(string request)
{
//do some stuff
return "response as a string";
}
My parameter "string request" is a string that cointains a xml. I read the string as a xml and do some stuff with it. (save some nodes from the xml in a database, for example).
If all the function is succeded or not I expect the output of my string, but I'm no receiving anything. Only the status code 204 No Content. (when content should really be returned).
Any suggestion is welcome.
It can solve my problem.
The only thing I had to do was specify the route with which my Api website will be invoked.
In addition I also had to modify the data type of my parameter and my function.
Something like this:
[HttpPost]
[Route("api/Controller/IncomingPO")]
public HttpResponseMessage IncomingPO(HttpRequestMessage request)
{
//do some stuff
return new HttpResponseMessage()
{
Content = new StringContent("My response string", System.Text.Encoding.UTF8, "application/xml"),
StatusCode = HttpStatusCode.OK
};
}
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
I am testing an ASP.NET MVC application. There is a contoller with a method that looks like:
[HttpPost]
public async Task<ActionResult> Login(LoginForm loginForm)
{
// Do some work
return RedirectToAction(nameof(Admins));
}
The signature of Admins method looks like:
public async Task<ActionResult> Admins(ExtendedPagingForm form)
and I try to invoke it like this:
var url = $"{TestConfig.Instance.ServerUrl}/{actionMethod}";
var sendForm = GetFormContent(new MultipartFormDataContent(), sendData); //login and password
HttpResponseMessage response = await httpClient.PostAsync(url, sendForm);
The response contains Internal server error with info:
IOException: Unexpected end of Stream, the content may have already
been read by another component.
On MSDN it is said that RedirectToAction returns an HTTP 302 response to the browser, which causes the browser to make a GET request to the specified action. So it must not work neither in browser, nor in Postman, but it works fine there. Can I force my httpClient to send POST request with data or some mock request body?
I've solved the problem.
I changed MultipartFormDataContent to FormUrlEncodedContent and it works
In my case I was already using FormUrlEncodedContent but it was still happening. Mine was a Xamarin project.
Restarting Visual Studio and Emulator helped me.
Strange one here, code calls the method, and the method grabacat is executed on the server (I debug it and step through right to the end). The code returns to the client, but the response it received was 500 Internal Server Error with the above message. So it's saying it couldn't find the web API method that it just called successfully.
using (var response = await client.PostAsXmlAsync("cats/grabacat", mycatprefs))
{
if (response.IsSuccessStatusCode) // 500 cats/grabacat not found
Controller code:
[Route("~/api/cats/grabacat")]
[HttpPost]
public async Task GrabACat()
{
}
After debugging, if I change it to public async Task<SomeObject> GrabACat() then it works OK. This lets me return an object back to the client. However I don't want to return anything back; I want it to be equivelent to calling a void method. It will examine the status code to determine if it was successful.
I have got it working by changing GrabACat to Task and returning new object(); but I am not sure why this is required. It seems crude to return an empty object just to get it to work.
Any ideas?
The WebAPI method has a Route attribute like this:
[Route("~/api/cats/grabacat")]
Which means the URL is wrong in the POST request - you are missing the /api prefix:
using (var response = await client.PostAsXmlAsync("api/cats/grabacat", mycatprefs))
//snip