C# HttpClient not handling 304/307 redirects - c#

I'm trying to get a HttpClient to pull favicons from websites, and for 99% of cases this code is working as expected:
var httpClient = new HttpClient();
httpClient.Timeout = TimeSpan.FromSeconds(10);
var response = await httpClient.GetAsync("https://www.tesco.com/favicon.ico");
response.EnsureSuccessStatusCode();
I've been finding with a couple of websites that my GetAsync method is just timing out, and I believe it is to do with it's redirect. If you run the above code in a console app, the following exception is thrown inside a TaskCanceledException and an IOException after 10 seconds:
SocketException: The I/O operation has been aborted because of either a thread exit or an application request.
This request works completely fine on Postman, and I've tried https and http without success. When visiting the site and using Chrome's dev tools, it looks like if you use http rather than https, it returns a 307 and redirects you to the https site, which then returns a 304. I don't understand why the HttpClient is just timing out rather than giving a useful response.
Is there any way to get this to work? Am I missing something simple?
Update - 2021-01-29
I've tried this on multiple different .NET versions, and found that this could be a bug with HttpClient, as this code works for .NET Core 2.0 but not for .NET Core 2.1.
Versions Tested
.NET Framework 4.8: Works
.NET Core 1.0: Works
.NET Core 1.1: Works
.NET Core 2.0: Works
.NET Core 2.1: Does not work
.NET Core 2.2: Does not work
.NET Core 3.0: Does not work
.NET Core 3.1: Does not work
.NET 5: Does not work

It turns out this is not a .NET issue at all. I raised this issue on GitHub as all evidence was pointing towards the HttpClientHandler breaking after .NET Core 2.1. Stephen was able to point out to me that before .NET Core 2.1, a Connection: Keep-Alive header is set by default in the HttpClient.
The culprit URLs that I have been testing against seem to require one of the following things to work:
A Connection: Keep-Alive header
An Accept: */* header, or something more specific to what is being requested
The request to be sent using the HTTP/2 protocol.
For reference, to apply one of the Header fixes, use httpClient.DefaultRequestHeaders.Add(string, string), and to set the HTTP protocol, use httpClient.DefaultRequestVersion = HttpVersion.Version20;
This issue turns out to not be a direct issue with C#, but that the default headers that are sent changed after .NET Core 2.1. I found the issue to be reproducible on Postman if you disable all headers (including the Postman token header).

Related

.Net 7 ServiceStack 6.4 breaking api route that has just "/api"

Trying to provide more info and not sure how much is relevant.
One of our webapi is deployed to IIS : abcdomain.com/xyzweb. We started upgrading our env to .net 7 from .net 5. Web api also uses ServiceStack 6.4.
One of the route defined in the c# Webapi, ServiceStack plugin is "/api". Until recently requests to endpoint abcdomain.com/xyzweb/api was fine. But now (.net 7 upgrade?) we noticed that the calls to endpoint does not reach the (http get/post method) handler. We have a small middleware defined in startup.cs configure method and see the execution flow through the middleware code when the abcdomain.com/xyzweb/api request is made and the middleware ends by calling next() and after which execution flow lost (webapi is still live).
After much trials, something I read but could not put my fingers on the content, went ahead and changed the route definition to "/apihello" instead of "/api" and then the requests started working as before.
Any pointers what made it break or what made it work?
Searching is difficult with "api", brings only irrelevant results.
I would like to add that before changing /api to /apihello, the http request would return HTTP status 200 (though it did not go to the handler) and Raw response "Error: System.NotImplementedException: The operation '' does not exist for this service".
You can disable (or change) ServiceStack's JSON /api pre-defined route with:
ConfigurePlugin<PredefinedRoutesFeature>(feature => feature.JsonApiRoute = null);

Stream behaviour when no body in HTTP request

Using Azure Functions .Net 5 and the Microsoft.Azure.Functions.Worker.Http SDK, what is the expected behaviour of HttpRequestData.Body property when the request has no body? Is it null, is it a Stream.Empty, something else?
The documentation is unhelpful, as it simply says: "A Stream containing the HTTP body data."
Azure Functions Core 5 were released this year, there is little information available.
There is information on how to read body requests with ASP Core 3 but this is not .NET 5, and I am not sure Azure Functions are expected to behave in the same way as ASP.
I was so far unable to attach the debugger to the published Function Host, which complicates diagnostics.
what is the expected behaviour of HttpRequestData.Body property when the request has no body?
The raw HTTP request body as a bytestring. This is useful for processing data in different ways like loading the data, parsing etc.
The presence of a message-body in a request is signaled by the inclusion of a Content-Length or Transfer-Encoding header field in the request's message-headers.
If content-length is nothing, then the request read return nothing to read. Sometimes throws errors if the EOF (Function) return type is not valid.
To read http request body from asp.net core 5 using azure functions
Create Asp.Net Core 5 Project and Azure Functions isolated environment
Add each of their references in packages/dependencies.
You need to change the target framework of Microsoft SDK version from 3.1 to 5 because by default it is create in 3.1 in Azure Functions csproj.
And We need to do changes in the local.setting.json file as well as Program.cs file in Core project for reading the Http Request Body. Refer this and this for step by step process!
In HttpRequestBody, Content-length : some numeric value (but not zero) specifies the end of the HttpRequest and its length.
If Content-Length: 0, then HttpRequestData contains empty body like { }.
if neither ("Content-Length" / "Transfer-Encoding: chunked") are present, "the end of the connection" signals the end of the request.
The majority of HTTP queries are bodyless GET requests. To test different hooks that interact with such requests and to adequately stress the proxy code, it is crucial to simulate requests containing bodies. POST or PUT requests are the most common types of HTTP requests with bodies.
For more information on HttpRequestBody - Refer this

How to reject requests in a .NET Core API based on the values sent in the Accept header?

Reading about how to return status code 406 in a .NET Core API for requests that require a response in a format not supported by my API, I found that I need to set the following option in the AddMvcCore method:
services.AddMvcCore(options =>
{
options.ReturnHttpNotAcceptable = true;
});
However, I noticed that even if a client requests for an unsupported format, the request is forwarded to the endpoint and only after processing done in Controller that the status code 406 is returned.
I would like to know if .NET Core has a ready-made solution that blocks the request, that is, returns the status code 406 without having to execute the endpoint code. I have found solutions in which Middleware can be written to perform such a task, but I would really like to know if there is an alternative built into the framework itself.

Best option to interface a Xamarin.Forms app with Azure SQL Server

I'm trying to study a use case where I have a Xamarin.Forms application which interfaces with the Azure platform; in particular, with an SQL Database.
I followed this guide for the Xamarin part, and created a Web App and a SQL Database (with a SQL Server) for the Azure part, like shown here.
So I created a table in the database and modified the .NET backend of the guide
replacing the TodoItem class with the new class that represents my table.
After the deployment, nothing seemed to be changed.
The Xamarin code, by the way, with the class Microsoft.WindowsAzure.MobileServices.MobileServiceClient, seems to be calling a REST API; the connection to the web app is successful, but there's an error on a request like this:
Invalid sync operation: The request could not be completed. (Internal Server Error)Method: GET, RequestUri: 'https://myapp.azurewebsites.net/tables/Address?$filter=not(complete)', Version: 2.0, Content: <null>, Headers:
{
X-ZUMO-FEATURES: TT
X-ZUMO-INSTALLATION-ID: 3d018c77-7c83-4635-9592-31cdbbb4c21a
Accept: application/json
User-Agent: ZUMO/4.1
User-Agent: (lang=Managed; os=Windows Store; os_version=--; arch=X86; version=4.1.1.0)
X-ZUMO-VERSION: ZUMO/4.1 (lang=Managed; os=Windows Store; os_version=--; arch=X86; version=4.1.1.0)
ZUMO-API-VERSION: 2.0.0
Accept-Encoding: gzip
}
Accessing https://myapp.azurewebsites.net/tables/Address from a Web browser, in fact, returns an error.
Have you ever experienced something like this? I cannot find any REST service in Azure. The MobileServiceClient seems very good, it provides a very good level of abstraction, so I would prefer something like this than a custom REST client.
Thank you.

C# httprequest headers wiht a colon .Net 4.0

When inspecting a third party api using chrome browser's F12 tool I found there are several interesting headers listed:
:authority:m.somedomain.com
:method:GET
:path:/api/somevalues
:scheme:https
Along with some headers I'm familiar with, such as accept, accept-encoding, etc.
I'm using .Net 4.0 to make http/https requests. When trying to add these headers starting with a colon, an error is thrown on the first item:
httpRequest.Headers.Add(":authority", "m.somedomain.com");
httpRequest.Headers.Add(":method", "get");
httpRequest.Headers.Add(":path", sPath);
httpRequest.Headers.Add(":scheme", "https");
Error message:
Specified value has invalid HTTP Header characters.
After some searching I found article talking about http/2. However in .NET 4.0 there are only http/1.0 and http/1.1 available.
Does that mean I need to upgrade to newer .NET version?
Thanks in advance.
Possibly. http/2 is supported from .NET version 4.6.2.
Click on the Project tab and select properties at the bottom. And then change your .NET version to 4.6.2.
Also I am 99.9% sure that you shouldn't include semi colon in your headers.
Further:
httpRequest.Headers.Add(":method", "get");
The request-method should not be defined in the header. Do it like so.
httpRequest.Method = "GET";
The scheme is usually indicated by the prefix of your url. ie:
string webAddr = "https://www.google.com/";
HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);

Categories

Resources