8

I am using HttpClient class in my asp.net web api 2 application to post some information to a endpoint. I just want to post the information without waiting for a response. Is this the right syntax

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:9000/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    // HTTP POST
    var gizmo = new Product() { Name = "Gizmo", Price = 100, Category = "Widget" };
    var response = await client.PostAsJsonAsync("api/products", gizmo);
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
SharpCoder
  • 18,279
  • 43
  • 153
  • 249
  • di you try to just get rid of the "await"? You get a warning, but maybe is what you're asking for.. – marco.marinangeli Mar 23 '16 at 22:17
  • Not answer to your question. But worth sharing I think. I am using FLurl and loving it. https://github.com/tmenier/Flurl – KrishnaDhungana Mar 23 '16 at 22:23
  • Are you calling `HttpClient` from an ASP.NET WebApi app? – Yuval Itzchakov Mar 23 '16 at 22:24
  • @marco.marinangeli: I want to know if I am doing it the right way? if i remove the `await` keyword, I get following message `because this call is not awaited execution of the current method continues before the call is completed` – SharpCoder Mar 23 '16 at 22:24
  • @YuvalItzchakov:I am making call form one asp.net web api service to another asp.net web api service. – SharpCoder Mar 23 '16 at 22:25
  • what you do is correct @SharpCoder and remember if you use await in your function, then the function signature return type should be async Task. Again The async is not making your execution context to parallel rather it is not blocking the I/O operation at your end. It is depends upon the load to put to this api call. Otherwise no needed to use async/await. – Gomes Mar 23 '16 at 22:28
  • @SharpCoder if you are talking about fire and forgot then it is an api design. The target api should have designed to accept the request and put into some Queue and reply immediately using status code 202. Later in your client code you keep polling for result using another Get call to that api. – Gomes Mar 23 '16 at 22:37
  • @Gomes: The target service is inserting the request object into database. Assuming the target service will not use a queue, what is the ideal way to make the call ? – SharpCoder Jul 18 '16 at 19:12
  • @SharpCoder there are two way of looking the performance, 1) cpu bound 2)I/O bound. if your issue is CPU bound then use Queue or Multithread otherwise it is just IO bound hence just use async/await and what u do above is okey but ensure to have timeout hence you don't know the target api response behaviour. – Gomes Jul 19 '16 at 03:36

2 Answers2

4

I just want to post the information without waiting for a response

Not awaiting an async method in WebAPI will result in a runtime exception, as the AspNetSynchronizationContext is aware of any triggered asynchronous operations. If it notices a controller action completes before the async operation has, it will trigger the said exception. More on that in ASP.NET Controller: An asynchronous module or handler completed while an asynchronous operation was still pending

If you want to use a fire and forget semantics, you need to queue the delegate via HostingEnvironment.QueueBackgroundWorkItem if you're using .NET 4.5.2 and above. If not, you can defer to using BackgroundTaskManager

Keep in mind this kind of design isn't really suitable for WebAPI. It doesn't scale if you're triggering this action call frequently. If this style happens often, consider using something more suitable such as a message broker.

Community
  • 1
  • 1
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
  • 1
    This isn't an answer to the question. It's possible to just POST to a server and terminate the HTTP/TCP connection. Servers can and will usually continue the request anyway. `PostAsync` may not be the solution here if it always reads the response. – makhdumi Oct 30 '17 at 16:55
  • @makhdumi That's not what I'm trying to say here. Since OP wants to execute this from ASP.NET, he'll need to be aware that the runtime is aware of tasks which are left unattended, and will cause responses to the user to return error codes instead of completing properly. – Yuval Itzchakov Oct 30 '17 at 18:54
  • 3
    OP says "I just want to post the information without waiting for a response." The problem here is that `HttpClient.PostAsync` will automatically read the response stream. If one wishes to just send data and not bother reading the response, there is no actual need to have any operation, async or not, to read the request stream (ie wait for the server to respond). This is different than "fire and forget" with `QueueBackgroundWorkItem`. Your answer makes total sense and your point about scalability completely holds, even if just sending the response, but isn't a real answer to the question. – makhdumi Oct 30 '17 at 19:12
  • @makhdumi OP says "without waiting for a response", not "without *reading* the reponse"*. What would you suggest as an alternative? – Yuval Itzchakov Oct 30 '17 at 19:18
  • My point is that one way or another, you're waiting for a response with `PostAsync`, e.g. in another thread. Like you said, this is not at all scalable since you can easily get a ton of threads waiting on a response. This can be avoided by simply not waiting on/reading, the response, in whatever thread it's being run in. – makhdumi Oct 30 '17 at 19:22
  • @makhdumi The only overhead you'll get when using `PostAsync` is the callback on an IO Completion thread which shouldn't be too time consuming. I would definitely not call that a scale issue, but rather a micro optimization. – Yuval Itzchakov Oct 30 '17 at 19:29
  • You will easily hit thread exhaust with thousands of people. It is definitely a scaling issue – user2455808 Jul 18 '23 at 05:42
  • @user2455808 If the operations that are kicking off are truly async, [there is no thread to exhaust](https://blog.stephencleary.com/2013/11/there-is-no-thread.html). – Yuval Itzchakov Jul 18 '23 at 08:48
0

To implement the async Task in ASP.NET refer to the following sample syntax:

    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            RegisterAsyncTask(new PageAsyncTask(LoadUrlContent));
        }
        catch {}
    }

    protected async Task LoadUrlContent()
    {
        try
        {
        // Add your code here, for example read the content using HttpClient:
        string _content = await ReadTextAsync(YourUrl, 10);
        }
        catch { throw; }
    }

Also, set <%@ Page ... Async="true" %> at page level.

Following sample code snippet shows the use of HttpClient (call this sample function from LoadUrlContent():

protected async Task<string> ReadTextAsync(string Url, int TimeOutSec)
{
    try
    {
        using (HttpClient _client = new HttpClient() { Timeout = TimeSpan.FromSeconds(TimeOutSec) })
        {
            _client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("text/html"));
            using (HttpResponseMessage _responseMsg = await _client.GetAsync(Url))
            {
                using (HttpContent content = _responseMsg.Content)
                {
                    return await content.ReadAsStringAsync();
                }
            }
        }
    }
    catch { throw; }
}

You can modify this code base pertinent to your particular task.

Hope this may help.

Alexander Bell
  • 7,842
  • 3
  • 26
  • 42
  • My application is asp.net web api. I am using HttpClient to post the information. The answer you provided does not use HttpClient class. – SharpCoder Mar 23 '16 at 22:16
  • Please refer to the extended answer w/sample code using HttpClient. Best regards, – Alexander Bell Mar 23 '16 at 22:20
  • Thank you for quick reply. But I don't want to read the response. I just want to fire and forget. Also I am making call from one asp.net web api application to another asp.net web api application. – SharpCoder Mar 23 '16 at 22:27
  • Then you may try Task.Run() because async/await is kind of antithetical to "fire and forget" (it's awaiting something per very definition). Still, you may use ConfigureAwait(false) to achieve the desirable result. Best regards, – Alexander Bell Mar 23 '16 at 22:31
  • ConfigureAwait can cause deadlocks on asp – user2455808 Jul 18 '23 at 05:43