Post HTTP request without awaiting the result - c#

I have the following endpoint:
[HttpPost("Submit")]
public String post()
{
_ = _service.SubmitMetric("test", MetricType.Count, 60, 1);
return "done";
}
And the service implementation:
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return httpClient.PostAsync(<params>);
}
}
When I run the code and call the endpoint, the HTTP POST is not triggered. However, if I change my code to:
public async Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return await httpClient.PostAsync(<params>);
}
}
the POST is submitted as expected. Why is that happening, and what can I do if I don't really care about the HTTP response? I just want to submit it and continue my flow. Shouldn't I be able to use it without awaiting the result? For example:
public void SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
httpClient.PostAsync(<params>);
}
}

There are two problems with this code. If either was fixed, there would be no problem:
The HttpClient is used incorrectly. An HttpClient object is thread-safe and meant to be reused, not disposed. Disposing it like this leaks sockets and can result in application crashes or worse, instability. An HttpClient resolves the URL's Host to a socket and caches that socket. The OS also caches opened sockets because opening them is expensive. They're kept alive for a while even if an application closes them because some packets may still be in transit
By not awaiting PostAsync execution exits the using block and the HttpClient instance is disposed before the request had a chance to even start.
In any case, making a POST doesn't take long so there's no need to make the method fire-and-forget. Besides, few applications are OK with losing metrics, especially when things go wrong. That's when metrics are most useful.
Which is why ASP.NET Core 6 adds built-in support for OpenTelemetry tracing and metrics. More on that at the end, but the supporting packages can be used in ASP.NET Framework as well. You may be able to replace your current service with a built-in one.
Use await - not enough
One way to fix this is to use await but that doesn't solve the HttpClient usage problem.
public async Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
using (var httpClient = new HttpClient())
{
return await httpClient.PostAsync(<params>);
}
}
At the very least the HttpClient should be stored in a field. Once that's done though, there's no longer any reason to await, provided the service itself is still around :
HttpClient httpClient = new HttpClient();
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
return httpClient.PostAsync(<params>);
}
Long lived services
Which brings us to keeping the service around. In ASP.NET and ASP.NET Core each request is served by a separate thread, in a new instance of the Controller class. The request itself is used as a GC scope so anything created during a request is disposed once this concludes, including the HttpClient instance.
To keep the Metrics service around we need to either register it as Singleton in ASP.NET Core's DI, make it a BackgroundService or ensure it's a singleton in ASP.NET Framework. We could make the field static, but that leads to the next issue.
Proper HttpClient usage
HttpClient can still cause problems if used as a singleton. The HttpClient caches sockets to specific machines. If that machine goes away, the HttpClient will still try to communicate with it causing errors. This can happen easily when the remote services uses a load balancer or fails over to a new server. To fix this, the HttpClient instance or rather the sockets, need to be recycled periodically.
That's the job of the HttpClientFactory. This class caches and recycles SocketClientHandler instances, the classes that do the actual work in an HttpClient. These are recycled periodically, eg every 10 minutes. When asked for a new HttpClient instance, it creates a new instance wrapping one of the already available handlers.
When you use services.AddHttpClient in ASP.NET Core you're actually configuring an HttpClientFactory. When you add an HttpClient dependency in a controller, the instance will be created by the configured HttpClientFactory.
This means that the following action would work properly :
HttpClient _client;
public MyController(HttpClient client)
{
_client=client;
}
[HttpPost("Submit")]
public String post()
{
await _client.PostAsync(<params>);
return "done";
}
A scoped service with an HttpClient dependency would also work:
MyService _service;
public MyController(MyService service)
{
_service=service;
}
HttpPost("Submit")]
public String post()
{
await _service.SubmitMetric("test", MetricType.Count, 60, 1);
return "done";
}
where MyService is :
class MyService
{
HttpClient _client;
public MyService(HttpClient client)
{
_client=client;
}
public Task<HttpResponseMessage> SubmitMetric(<params>)
{
// build payload
return httpClient.PostAsync(<params>);
}
}
In this case there's no real need to await inside SubmitMetric, that's taken care of by the action.
Using the built-in OpenTelemetry tracing and metrics
ASP.NET Core 6, the upcoming Long-Term-Support version, adds native support for the OpenTelemetry standard for logging, tracing and metrics. This allows using a standard API to push metrics to a lot of different observability applications like Prometheus, Jaeger, Zipking, Elastic and Splunk.
Instead of rolling one's own metrics infrastructure it's better to use the standard API. OpenTelemetry for .NET supports this in ASP.NET Framework 4.6 and later. ASP.NET Core 5 and later are instrumented to publish metrics and tracing to OpenTelemetry providers through the built-in System.Diagnostics namespace and the Activity class.
In fact, Controller is already instrumented so you could get rid of the metrics service, adding any Tags and Baggage to the request's current activity:
[HttpPost("Submit")]
public String post()
{
Activity.Current?.AddTag("test");
...
return "done";
}
Metrics were added in ASP.NET Core 6 Preview 5:
Meter meter = new Meter("my.library.meter.name", "v1.0");
Counter<int> _counter;
public MyController(...)
{
_counter = meter.CreateCounter<int>("Requests");
}
[HttpPost("Submit")]
public String post()
{
counter.Add(60, KeyValuePair.Create<string, object>("request", "test"));
return "done";
}

Don't do it. Await for it even though you discard the result.
Fire and forget is an anti pattern and the context that you are performing the request can be invalidated/killed before the request could be completed, terminating the connection. Just await it, and don't do anything with the result.

httpClient will be disposed while the POST operation is running, probably resulting in killing the socket. If you use await, the object will remain inside the using clause while the operation is running, and it won't be terminated before it finishes.
Note that in your current implementation, you're creating a new connection on each API request, which might eventually lead to socket exhaustion. A better approach would be injecting IHttpClientFactory, which manage the lifetime of network connections for you, and reuses connections from the pool:
public class MyService
{
private readonly IHttpClientFactory _httpClient;
public MyService(IHttpClientFactory httpClient)
{
_httpClient = httpClient;
}
public async Task<HttpResponseMessage> SubmitMetric(/*<params>*/)
{
var httpClient = _httpClient.CreateClient();
return await httpClient.PostAsync(/*<params>*/);
}
}
Note: You need to add services.AddHttpClient() in ConfigureServices in your Startup.cs to enable injection.

Related

Reuse httpClient created via the HttpClientFactory in different methods of the same class? (C# / .NET)

I have a class into which the IHttpClientFactory is injected via the constructor. There's also a HttpClient private field in this class.
Are there any issues with creating the HttpClient in the constructor, using the factory, and then reusing that HttpClient in two/multiple methods within that one class to make two/multiple different api calls? (Same Api, different endpoints)
Or would it be better to use the factory in each method to create a new client. What are the implications/pros & cons of each approach? Is any one inherently better or doesn't it matter?
private readonly HttpClient _httpClient;
public RestClient(IHttpClientFactory httpClientFactory)
{
_httpClient = httpClientFactory.CreateClient();
}
public async Task<SomeResponse> Method1(SomeRequest request)
{
...
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, url))
{
httpRequestMessage.Headers.Add("Accept", "application/json");
httpRequestMessage.Headers.Add("Authorization", "Basic " + credentials);
httpRequestMessage.Content = new StringContent(jsonBody, Encoding.UTF8, "application/json");
using (var response = await _httpClient.SendAsync(httpRequestMessage))
{
...
}
}
...
}
public async Task<SomeOtherResponse> Method2(someInput)
{
...
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri.ToString()))
{
httpRequestMessage.Headers.Add("Accept", "image/png");
httpRequestMessage.Headers.Add("Authorization", "Basic " + credentials);
using (var response = await _httpClient.SendAsync(httpRequestMessage))
{
...
}
}
...
}
Edit: have looked at this post Should I cache and reuse HttpClient created from HttpClientFactory? but it doesn't answer my questions. If there is something to be derived from there please explain.
I think you are looking for this guidance from Microsoft: Guidelines for using HttpClient
I copy here the related part
Recommended use
In .NET Core and .NET 5+:
Use a static or singleton HttpClient instance with PooledConnectionLifetime set to the desired interval, such as two minutes, depending on expected DNS changes. This solves both the socket exhaustion and DNS changes problems without adding the overhead of IHttpClientFactory. If you need to be able to mock your handler, you can register it separately.
Using IHttpClientFactory, you can have multiple, differently configured clients for different use cases. However, be aware that the factory-created clients are intended to be short-lived, and once the client is created, the factory no longer has control over it.
The factory pools HttpMessageHandler instances, and, if its lifetime hasn't expired, a handler can be reused from the pool when the factory creates a new HttpClient instance. This reuse avoids any socket exhaustion issues.
If you desire the configurability that IHttpClientFactory provides, we recommend using the typed-client approach.
In .NET Framework:
Use IHttpClientFactory to manage your HttpClient instances. If you create a new client instance for each request, you can exhaust available sockets.
Tip
If your app requires cookies, consider disabling automatic cookie handling or avoiding IHttpClientFactory. Pooling the HttpMessageHandler instances results in sharing of CookieContainer objects. Unanticipated CookieContainer object sharing often results in incorrect code.

Why using HttpClient in a using block IS WRONG in WebApi context?

So, the question is why the usage of HttpClient in using block is WRONG, BUT in WebApi context?
I've been reading this article Don't Block on Async Code. In it we have the following example:
public static async Task<JObject> GetJsonAsync(Uri uri)
{
// (real-world code shouldn't use HttpClient in a using block; this is just example code)
using (var client = new HttpClient())
{
var jsonString = await client.GetStringAsync(uri);
return JObject.Parse(jsonString);
}
}
// My "top-level" method.
public class MyController : ApiController
{
public string Get()
{
var jsonTask = GetJsonAsync(...);
return jsonTask.Result.ToString();
}
}
The comment // (real-world code shouldn't use HttpClient in a using block; this is just example code) just triggered me. I've been always using HttpClient in this way.
The next thing I've checked is Microsoft's documentation on HttpClient Class.
In it, we have the following statement with provided source sample:
HttpClient is intended to be instantiated once and re-used throughout
the life of an application. Instantiating an HttpClient class for
every request will exhaust the number of sockets available under heavy
loads. This will result in SocketException errors. Below is an example
using HttpClient correctly.
public class GoodController : ApiController
{
private static readonly HttpClient HttpClient;
static GoodController()
{
HttpClient = new HttpClient();
}
}
So isn't the constructor called on each request and thus a new HttpClient will be created every time?
Thanks!
There's a bit of a long answer to this...
Originally, the official recommendation was to use HttpClient in a using block. But this caused problems at scale, essentially using up lots of connections in the TIME_WAIT state.
So, the official recommendation changed to use a static HttpClient. But this caused problems where it would never correctly handle DNS updates.
So, the ASP.NET team came up with IHttpClientFactory in .NET Core 2.1, so code (or at least code running on modern platforms) can reuse HttpClient instances (or, more properly, the message handlers of those instances), avoiding the TIME_WAIT problem, but also periodically closing those connections to avoid the DNS problem.
But, at the same time, the .NET team came up with SocketsHttpHandler also in .NET Core 2.1, which also does connection pooling.
So, on modern platforms, you can either use IHttpClientFactory or a static/singleton HttpClient. On older platforms (including .NET Framework), you would use a static/singleton HttpClient and either live with the DNS issue or use other workarounds.
Actually writing this question I noticed the static constructor in the code sample provided from Microsoft. This all makes sense now.
The Static Constructors are used to initialize any static data, or to perform a particular action that needs to be performed only once. It is called automatically before the first instance is created or any static members are referenced.
In the context of WebAPI the static constructor is called one time only thus creating only one HttpClient and reusing it for all other requests.
I'll never use using(HttpClient....) in production code again.
This is a great article on the wrong usage of HttpClient - YOU'RE USING HTTPCLIENT WRONG AND IT IS DESTABILIZING YOUR SOFTWARE

Loop HTTP Request in Background?

I'm pretty new to working with HTTP stuff so I'm rather confused as to what would be the best approach to request data from a HTTP address every few seconds or so.
The API I'm using has - at least to my knowledge no webhook support. So I imagine the way to update my data would be a rather crude way of doing so.
I want this to happen in the background so the GUI does not freeze and become unresponsive. So I know I (probably) need to fiddle with threads.
Best results I've had has been with a async/await Timer. I'm not entirely sure how to work with this and the only way for me to get it to work is to throw an exception after it has elapsed. If I don't - it says that not all nodes return a value and I can't even use return which really, really confuses me.
How should I be doing this?
If it's of any use, I'm working on creating my own RCON tool for a game which has all kinds of server data available via a HTTP API - but documentation for this API is very lackluster.
if you go to .net core you can see my previous answer on: Start multiple background threads inside Self Hosted ASP.NET Core Microservice
for .net framework you have to do a little more yourself. But still very do-able!
in your global.asax you have (or should I say: should) have your dependency injection. Something like:
protected void Application_Start()
{
Bootstrap();
//and do something more
}
private static void Bootstrap()
{
var container = new Container();
container.Register(() => new HttpClient());
container.RegisterSingleton<IApiCaller, ApiCaller>();
container.RegisterInitializer<IApiCaller>(ApiCaller=> apicaller.StartCallingAsync());
// Suppress warnings for HttpClient
var registration = container.GetRegistration(typeof(HttpClient)).Registration;
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent, "Dispose is being called by code.");
registration.SuppressDiagnosticWarning(DiagnosticType.LifestyleMismatch, "Every HttpCient is unique for each dependency.");
container.Verify();
GlobalConfiguration.Configuration.DependencyResolver = new SimpleInjectorWebApiDependencyResolver(container);
}
In this case, I let SimpleInjector start my background thread to do a lot of work.
In the apicaller you can do your httpcalls.
something like:
public async Task StartCallingAsync(CancellationToken cancellationToken = (default)CancellationToken)
{
while(true)
{
var response = await _httpClient.GetAsync(url);
if (response.IsSuccessStatusCode)
{
//do work
}
await Task.Delay(10000, cancellationToken);
}
}
for the GetAsync there are extension methods that can cast it directly to your object.
can you work with this?

C# IHttpHandler and the use of httpclient for a web service

I have been tasked with maintaining an C# web service that pretty much boils down to the following code that is used in conjunction with IIS 8:
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// here we process the request and return it after fetching some data
}
}
Now I need to create another web service, which in turn will request another web service for fetching data. What I've gathered is that the HttpClient() in C# is the new shiny, however finding out how to implement it in my case is not so easy (or if that would be a good solution).
My solution would something like
public class Handler1 : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
// make sure that the incoming request is valid
HttpClient client = new HttpClient();
// do stuff with ^client and request the other service
[..]
// return the data from the response from ^client to the first request
}
}
Am I on the right track or would this be a catastrophe? I would gladly take tips or pointers to relevant documentation.
There are two issues with your approach.
First, as others have said, HttpClient must not be created for each request, as this would result in your server creating one new TCP connection for each request and not dispose it from your connection pool until they reach their MaxIdleTimeout.
This is because each instance of HttpClient (or rather, each instance of HttpClientHandler) creates a unique ConnectionGroup within the ConnectionPool, so two HttpClient (created in such a way) will not share the same connections.
You can quite easily exhaust your ports (because connections are kept alive for quite some time), and even without that, you'll have all the performance issues you might find when deactivating keepalive (typically when connecting on a HTTPs server).
As for a solution, you might add a private readonly HttpClient field in your handler that you would initialize as you've done in your code (I believe HttpHandlers are instanciated once by IIS, not per-request, as long as it says it's reusable). (Edit: note that HttpClient instances are thread-safe).
The other problem you'll find is that IHttpHandler are synchronous by design. This means you'll have to return task.Result in your code. This will block the current thread (let's call it A), and all subsequent processing of the outbound request (sending the body of the request, reading the header of the response and reading the body of the response) will spawn use a thread from the thread pool to process this (let's call them B, C, and D, though they can all be the same thread since no step overlap in time).
But in Asp.net, you cannot safely do that. When your main thread A is processing an Asp.net inbound request, it will, simply put, lock the current context. And when threads B, C and D will be spawn to process the outbound request, they too, will try to acquire and lock the current context. But because your main thread A is blocked, the context has not been released. This will effectively result in deadlocks (A locks the context and wait for B/C/D, B/C/D wait for the context).
To work around this, I would advise you to use instead a IHttpAsyncHandler. Async process are not made to be used synchronous, and HttpClient can only be used in an async way.
However, this might prove much more challenging for a first usage scenario. It would be much more easier to use a HttpClient from the context of a WebApi server. However, without any knowledge as to why you have to use a HttpHandler, I do not know if this would be in the realm of acceptable answers.
There are other way to run asynchronous tasks and wait synchronously for them (such as changing temporary the CurrentContext), but they're all very dangerous.
As a side note, HttpClient is the new shiny thing, and works quite well with other new shiny things such as "all-the-way async infrastructure". But trying to use it HttpClient in an older infrastructure is not as easy.
Better solution example:
public class YourApp
{
private static HttpClient Client = new HttpClient();
public static void Main(string[] args)
{
Console.WriteLine("Requests about to start!");
for(int i = 0; i < 5; i++)
{
var result = Client.GetAsync("http://www.stackoverflow.com").Result;
Console.WriteLine(result);
}
Console.WriteLine("Requests are finished!");
Console.ReadLine();
}
}

Stubbing or Mocking ASP.NET Web API HttpClient

I am using the new Web API bits in a project, and I have found that I cannot use the normal HttpMessageRequest, as I need to add client certificates to the request. As a result, I am using the HttpClient (so I can use WebRequestHandler). This all works well, except that it isn't stub/mock friendly, at least for Rhino Mocks.
I would normally create a wrapper service around HttpClient that I would use instead, but I would like to avoid this if possible, as there are a lot of methods that I would need to wrap. I am hoping that I have missing something—any suggestions on how to stub HttpClient?
As an alternative to the excellent ideas already presented by #Raj, it may be possible to go a step lower and to mock/fake the HttpMessageHandler instead.
If you make any class that needs an HttpClient accept it as a dependency injection parameter in the constructor, then when unit testing you can pass in an HttpClient that has been injected with your own HttpMessageHandler. This simple class has only one abstract method that you need to implement, as follows:
public class FakeHttpMessageHandler : HttpMessageHandler
{
public HttpRequestMessage RequestMessage { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
RequestMessage = request;
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
}
}
My trivial example just saves the HttpRequestMessage in a public property for later inspection and returns HTTP 200 (OK), but you could augment this by adding a constructor that sets the result you want returned.
You'd use this class like this:
public void foo()
{
//Arrange
var fakeHandler = new FakeHttpMessageHandler();
var client = new HttpClient(fakeHandler);
var SUT = new ClassUnderTest(client);
//Act
SUT.DomSomething();
//Assert
fakeHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get); // etc...
}
There are limitations to this approach, for example in a method that makes multiple requests or needs to create multiple HttpClients, then the fake handler might start to become too complicated. However, it may be worth consideration for simple cases.
I released a library a few months ago called MockHttp which might be useful. It uses a custom HttpMessageHandler with a fluent (and extensible) API. You can inject the mocked handler (or HttpClient) into your service class and it will respond as it was configured.
Below shows basic usage. The When and Respond methods have a bunch of overloads, including running custom logic. The documentation on the GitHub page goes into a lot more detail.
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localhost/api/user/*")
.Respond("application/json", "{'name' : 'Test McGee'}"); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
var response = async client.GetAsync("http://localhost/api/user/1234");
// or without async: var response = client.GetAsync(...).Result;
var json = await response.Content.ReadAsStringAsync();
// No network connection required
Console.Write(json); // {'name' : 'Test McGee'}
I use Moq and I can stub out the HttpClient. I think this the same for Rhino Mock (I haven’t tried by myself).
If you just want to stub the HttpClient the below code should work:
var stubHttpClient = new Mock<HttpClient>();
ValuesController controller = new ValuesController(stubHttpClient.Object);
Please correct me if I’m wrong. I guess you are referring to here is that stubbing out members within HttpClient.
Most popular isolation/mock object frameworks won’t allow you to stub/setup on non- virtual members
For example the below code throws an exception
stubHttpClient.Setup(x => x.BaseAddress).Returns(new Uri("some_uri");
You also mentioned that you would like to avoid creating a wrapper because you would wrap lot of HttpClient members. Not clear why you need to wrap lots of methods but you can easily wrap only the methods you need.
For example :
public interface IHttpClientWrapper { Uri BaseAddress { get; } }
public class HttpClientWrapper : IHttpClientWrapper
{
readonly HttpClient client;
public HttpClientWrapper() {
client = new HttpClient();
}
public Uri BaseAddress {
get
{
return client.BaseAddress;
}
}
}
The other options that I think might benefit for you (plenty of examples out there so I won’t write the code)
Microsoft Moles Framework
http://research.microsoft.com/en-us/projects/moles/
Microsoft Fakes: (if you are using VS2012 Ultimate)
http://msdn.microsoft.com/en-us/library/hh549175.aspx

Categories