Trouble getting CORS working with Web API 2 - c#

I'm having a heck of a time getting Cors working with Web Api. I just created the Web Api with the default template that comes with visual studio 2015. The only changes i made are:
Install-Package Microsoft.aspnet.webapi.cors
In WebApiConfig.cs::Register(HttpConfiguration config):
var cors = new EnableCorsAttribute(
origins: "*",
headers: "*",
methods: "*");
config.EnableCors(cors);
I made the POST method in the values controller async:
public async Task Post(Guid id)
I added a small amount of logic to the post method.
I'm calling the Web Api from another project in my solution:
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Add("My-GUID",streamProvider.Guid.ToString());
var response = await client.PostAsXmlAsync("http://localhost.fiddler:2010/api/values", myXmlString);
if (response.StatusCode != HttpStatusCode.Created)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
Request:
POST http://localhost:2010/api/values HTTP/1.1
TRS-GUID: 2ca71b41-9e78-4216-a013-e45c6fd6cb4c
Content-Type: application/xml; charset=utf-8
Host: localhost:2010
Content-Length: 183
Expect: 100-continue
Connection: Keep-Alive
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/"><?xml version="1.0" encoding="utf-8"?>
<root>
<MbrId>22</MbrId>
</root></string>
Response:
HTTP/1.1 405 Method Not Allowed
Cache-Control: no-cache
Pragma: no-cache
Allow: GET
Content-Type: application/xml; charset=utf-8
Expires: -1
Server: Microsoft-IIS/10.0
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?Qzpcc291cmNlXEFzeW5jRmlsZVVwbG9hZERlbW9cc3JjXEFwcFxhcGlcdmFsdWVz?=
X-Powered-By: ASP.NET
Date: Thu, 08 Oct 2015 14:33:08 GMT
Content-Length: 93
<Error><Message>The requested resource does not support http method 'POST'.</Message></Error>
Like i said i've made minimal changed and am running this through IIS express locally. I've been googling around and trying a few things but nothing seems to work. I tried adding the cors options as attributes but it resulted in the same thing. I also seen one post suggesting '*' wasn't in the original spec so i tried by using the methods specfically (POST, PUT, GET) but that didn't work either.
Edit:
Does this have anything to do with the 'preflight' request? I only notice the POST request in fiddler. I don't see it sending an 'options' request across. If this is the issue shouldn't httpclient handle this automatically?
Answer
Thanks goes out to Darrel for the answer. As you can tell the error message coming back was really misleading and definitely sounded like a CORS problem but it wasn't. I never realized CORS was only for the browser. Like Darrell said it was a routing problem. I put a Guid as a POST parameter which caused no route to be matched. To bad the error message coming back couldn't be a little more useful.

There are no cross-origin restrictions for HttpClient. It is purely a web browser constraint. You do not need to implement CORS for HttpClient requests.
Try making the POST request via fiddler and see if that works. I suspect you may just have a routing problem.

Related

Why is Refit with custom handlers converting my GET requests into POST requests? (405 Method Not Allowed)

I have a Xamarin app in which I am using Refit to call my ASP.NET Core Web API backend (.NET 6). On the iOS side of things, I use a custom System.Net.Http.HttpClientHandler to add the api key and bearer token to the requests. On Android, I do something very similar, but the handler inherits from Xamarin.Android.Net.AndroidClientHandler. The code in each file is identical, line for line, except the base classes that each inherits from, which are the standard base handler classes that are typically prescribed for iOS and Android when using Xamarin.
One of the primary GET endpoints on my API takes a content body, which contains some potentially large filters. I realize that it's not standard to put a content body in a GET request, but I'm doing it because my query filters can be large and complex, and the filters are not suitable for placing in the query string of the request URL.
In the iOS app, these requests work just fine: the requests are issued with the GET verb, and the backend processes the request and inspects the body content successfully, and returns a successful 200 OK response.
On the Android side of things, I'm getting a 405 Method Not Allowed. The weird thing about this is that the debug output from my handler clearly shows that the request verb is GET, but the response from the backend indicates that a POST is being sent.
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request]======= Request Begin =======
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] GET /api/v1/event/lite?pageIndex=1&pageSize=25 https/2.0
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] Host: [omitted]
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] apiKey: [omitted]
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] Authorization: Bearer
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] Content-Type: application/json; charset=utf-8
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] Content:
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] {"includeUnpublished":false,"includeOnlyOwnedItems":false,"includeDeleted":false,"startDate":"2022-03-04T00:00:00","duration":"1.00:00:00","isFree":null,"favoriteOption":2,"ageGroupIds":[],"eventIds":[],"venueIds":[],"partyIds":[],"tags":[]}...
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request] Duration: 00:00:01.1710510
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Request]======= Request End =========
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response]======= Response Start ======
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] HTTPS/1.1 405 Method Not Allowed
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] api-supported-versions: 1.0
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Connection: keep-alive
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Date: Fri, 04 Mar 2022 16:42:42 GMT
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Request-Context: appId=cid-v1:8968a593-b085-4979-81da-5c5918483840
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Server: Microsoft-IIS/10.0
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] X-Android-Received-Millis: 1646412160790
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] X-Android-Response-Source: NETWORK 405
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] X-Android-Selected-Protocol: http/1.1
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] X-Android-Sent-Millis: 1646412160706
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] X-Powered-By: ASP.NET
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Allow: GET, DELETE
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Content-Length: 225
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Content-Type: application/json; charset=utf-8
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Content:
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] {"error":{"code":"UnsupportedApiVersion","message":"The HTTP resource that matches the request URI '[omitted]' with API version '1' does not support HTTP method 'POST'.","innerError":null}}...
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response] Duration: 00:00:00.0284520
[7de9dcf3-79c2-4b76-a03e-f51af36b1a7d - Response]======= Response End ========
EventApiClient.ReadLite failed: Response status code does not indicate success: 405 (Method Not Allowed). Retying in 0 ms...
Response status code does not indicate success: 405 (Method Not Allowed).
Error: Response status code does not indicate success: 405 (Method Not Allowed).
So, I fired up Charles Proxy and intercepted the request, just to make sure. And sure enough, the outbound request is a POST, even though I'm telling Refit to send a GET. It's as if Refit is seeing that I've specified body content, and is automatically (and silently) changing the verb of the request from GET to POST.
I have even manually composed the request in Postman, and I am able to successfully get back data with a 200 OK, just as I do in my iOS scenario.
Is there something specific to the AndroidClientHandler that mangles requests by changing the verb when a content body is present? Or is there something inside of Refit itself that causes this behavior?
UPDATE:
After narrowing it down to being something within AndroidClientHandler, I opened an issue Xamarin.Android team here:
https://github.com/xamarin/xamarin-android/issues/6813
UPDATE UPDATE:
Both AndroidClientHandler and NSURLSessionHandler don't like when a body exists in a GET request. So, I simply decided to make my endpoints respond to the POST verb instead of GET. The entire impetus for this is that my query filters can be so large that they're not friendly for putting in a query string, which is typically where filter params go. So, I decided to pass the filters in the request body. That's where problems arose. So, now I'm just using POST for making my queries (because I control both the client and the server), even though that goes against convention. But I don't care...as long as the HTTP calls succeed, I'm not going to be a stickler for HTTP conventions.
Scratch all this. It appears that on the iOS side of things, NSUrlSessionHandler also does the same thing: it essentially doesn't allow a body in a GET request. I guess perhaps the most straightforward way for me to deal with my issue is to change my GET endpoint to a POST endpoint...even though that feels dirty because it violates the principles of what POST is intended for.

How to make simple async action method returning content return actual content and not type

here is a very simply MVC asynchronous action:
[HttpPost]
public async Task<ContentResult> Trial()
{
ContentResult contentResult = await new Task<ContentResult>(()=>new ContentResult{Content="Hi"});
return contentResult;
}
I would expect a post to this action to respond with the content "Hi". But it does not. It responds with the content "System.Threading.Tasks.Task`1[System.Web.Mvc.ContentResult]".
Here is the full response:
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store
Pragma: no-cache
Content-Type: text/html; charset=utf-8
Content-Encoding: gzip
Expires: -1
Vary: Accept-Encoding
X-UA-Compatible: IE=Edge
Date: Mon, 23 Nov 2020 17:02:37 GMT
Content-Length: 166
System.Threading.Tasks.Task`1[System.Web.Mvc.ContentResult]
Would love some insights into why, and how to get the content "Hi" as expected, using an Async function. Thanks.
This can happen if you're using a very old version of MVC. You must be running (at least) ASP.NET 4.5 on .NET Framework 4.5 for Task-returning action method to work. Microsoft.Bcl.Async does not work for ASP.NET projects.
If you have .NET Framework 4.5 or newer on your web servers, you can upgrade your project to ASP.NET 4.5. After upgrading, you must turn off "quirks mode" for async to work properly. I prefer to do this by setting httpRuntime.targetFramework in your web.config to 4.5 (or whatever version you upgrade to).

ASPNETCore 2 POST method not returning a payload

I upgraded a .net core 1 project to .net core 2. Everything is working great however my POST method won't return any data. There is no payload. I must be missing something simple.
The API does receive what I send it, so no issues there. But there is nothing in the response (using Chrome and IE dev tools), no matter what I try.
Here are the response headers:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: application/json; charset=utf-8
Content-Encoding: gzip
Server: Kestrel
Access-Control-Allow-Origin: *
X-SourceFiles: =?UTF-8?B?
For instance this returns no payload:
[HttpPost]
public IActionResult PostOrder([FromBody]OrderDto dto)
{
return new OkObjectResult(dto);
}
Caching policy was setting "Location" to none and "NoStore" to true. Removing this policy solved the issue.

Azure Update Scheduled Job API - Malformed Job Object

I am attempting to use the Azure Rest API to update a Scheduled Job. I've successfully been able to get a list of the of the Jobs properties, so I know the authentication is working. I'm basing this on their example here:
https://msdn.microsoft.com/en-us/library/azure/dn528934.aspx
Here is what I see in Fiddler when preforming the PATCH request.
REQUEST:
PATCH https://management.azure.com/subscriptions/[[mysub]]/resourceGroups/CS-WebJobs-NorthCentralUS-scheduler/providers/Microsoft.Scheduler/jobCollections/WebJobs-NorthCentralUS/jobs/[[myjob]]?api-version=2016-01-01 HTTP/1.1
Authorization: Bearer
[[my token here]]
Content-Type: application/json; charset=utf-8
Host: management.azure.com
Content-Length: 20
Expect: 100-continue
{"state":"disabled"}
RESPONSE:
{"error":{"code":"BadRequest","message":"Malformed Job Object"}}
Based on their example the JSON passed should work.
Any idea what's going on here? I'm hoping its something simple.
Try the following payload:
{
"properties": {
"state": "disabled"
}
}

WCF IClientMessageInspector and the incoming SOAP headers

I'm responsible for updating a client-side API using WCF. This is because of changes to the API on the server (an outside company). When I get the response, my client-side throws an exception. Using Fiddler, I came up with the following problem: a duplicate Content-Type.
HTTP/1.1 200 OK
Date: Thu, 05 Jan 2012 21:15:16 GMT
Connection: close
Content-Type: text/xml; charset=utf-8
Content-Type: text/xml; charset=UTF-8
Content-Length: 538
...
Using Fiddler, I removed the extra Content-Type, and the client continued happily. So, I wrote an IClientMessageInspector, with the intention of capturing the response and removing the duplicate. And therein lies my issue. My IClientMessageInspector gets a call to BeforeSendRequest, but not one to AfterReceiveRequest.
Is there some place other than AfterReceiveRequest that I should be handling my task of removing the extra Content-Type? Am I barking up the wrong tree altogether?

Categories

Resources