webcontroller {
async Task<ActionResult<string>> doSomething() {
var stringResult = await doSomethingAsync();
return stringResult;
}
}
what will be control flow here? will the controller return dummy response (ActionResult) to client after reaching doSomething() method call or the control remain in the web controller and return the stringResult to client? consider doSomething() is doing some network intensive tasks which might take more time to complete. Can anyone please explain the same to me if possible? Thanks in Advance!
will the controller return dummy response (ActionResult) to client
after reaching doSomething() method call or the control remain in the web controller and return the stringResult to client
It will not return anything to the client until doSomething method finished.
consider doSomething() is doing some network intensive tasks which
might take more time to complete
In this case you will have timeout on the client.
You have to start background job. Return to the client that task has been started. Then tell somehow to the client that task is finished.
Another source of information: Long running task in WebAPI
I recommend reading an article I wrote about how async works on ASP.NET.
will the controller return dummy response (ActionResult) to client after reaching doSomething() method call or the control remain in the web controller and return the stringResult to client?
When doSomethingAsync returns an incomplete task, then the await in doSomething will also return an incomplete task. Then the ASP.NET runtime (asynchronously) waits for that task to complete before sending the response.
await in ASP.NET yields to the thread pool; it does not yield to the client.
Related
I have a web-api with mvc that's doing a bunch of startup initialization which will take a few minutes. I want the url to respond to a request during this time with a progress-indicator. My thinking was to use a middleware to accomplish this something like this:
public async Task Invoke(HttpContext httpContext)
{
await httpContext.Response.WriteAsync("Loading...");
await Task.Delay(5000); // the initialization-stuff (which is not started here but just waited on)
httpContext.Response.Clear();
await _next(httpContext); // continue to my MVC-page
}
However this does not seem to work (ERR_INCOMPLETE_CHUNKED_ENCODING). How do I properly clear/reset the respons so that I can write a new real response once the initialization is done.
I resorted to something like this instead (good enough):
public async Task Invoke(HttpContext httpContext)
{
if (!task.IsCompleted)
await httpContext.Response.WriteAsync("Loading...");
else
await _next(httpContext); // continue...
}
Once you have sent data to the client you can't take it back. You can't replace an existing page, only append.
You can therefore do two things:
You delay the response until initialization is complete (likely not feasible).
You send something else and end the request. You could make the page that you are sending poll the server using AJAX to see if initialization has been completed. Then, the page can reload itself.
Create a new API endpoint that replies with the initialization status. Make page page poll that endpoint every few seconds.
I am trying to execute an async request using resharp, however the 'response' is always null, why?
private IRestResponse response;
public IRestResponse POSTAsync(string url) {
IRestResponse response = null;
client.ExecuteAsync(new RestRequest(url, Method.POST), (r) => {
if (r.StatusCode == HttpStatusCode.OK)
response = r;
});
return response;
}
From what i see, the response will always be null, since you are calling an asynchronous service and you are not waiting for the transaction to end.
private IRestResponse response;
public IRestResponse POSTAsync(string url) {
IRestResponse response = null;
client.ExecuteAsync(new RestRequest(url, Method.POST), (r) => {
if (r.StatusCode == HttpStatusCode.OK) // This is going to a new thread and will be executing later
response = r; // eventually this will be called, but your method did not wait for that completition
});
return response; // Response will always be null because the Async method is not
// finished yet
}
So, you should not be using try to use asynchronous methods if your surrounding code does not support it, since in the end you will need to block your method to wait for the result.
That is the reason why, the async keyword was created, you need to make all your calls dependent call asynchronous also, and that is the reason why the controllers now support async and tasks as return type (As an example from a modern Net Core app):
[HttpGet("{msisdn}")]
public Task<string> Get(string msisdn)
{
return _hubUserProfileService.CallProfileService(msisdn);
}
So, update your app so your entire request speaks asynchronous, or just do not use it, since it is not bringing anything to your code, it is even now more heavy, since it has to create the task to call the method in other thread... while the calling method must wait anyway for the response.
To clarify:
Calling asynchronous methods is not magic, you want that for the request to be executed in another thread, yet, immediately after creating that thread, you are hopping to the result to be available, and that is not how asynchronous execution works, you callback will be executed somewhere in the future, you do not know when, that is why the callback method is needed, the method will just create the task and continue, but the task is not executed yet, yo the variable is still null, you could add a Thread.Sleep() before the return response to verify what i am saying, this way you could give time for the asynchronous callback to finish, that is why making it asynchronous it is not giving you anything new.
I have this very simple WebApi method:
[HttpGet]
public IHttpActionResult Foo()
{
Thread.Sleep(3000);
return Ok("Bar");
}
And I have these two methods in a console application that call it:
async Task UsingWebClient()
{
Task<string> task = new WebClient().DownloadStringTaskAsync (new Uri ("http://localhost.fiddler:63710/api/producttype/Foo"));
Console.WriteLine("WebClient - Before calling wait");
string result = await task;
Console.WriteLine("WebClient - After calling wait");
}
async Task UsingHttpClient()
{
Task<string> task = new HttpClient().GetStringAsync (new Uri ("http://localhost.fiddler:63710/api/producttype/Foo"));
Console.WriteLine("HttpClient - Before calling wait");
string result = await task;
Console.WriteLine("HttpClient - After calling wait");
}
And I am calling these methods from LinqPad like this:
async Task Main()
{
await UsingWebClient();
await UsingHttpClient();
}
I was monitoring the traffic using Fiddler and I noticed that:
when using WebClient the request to the web api is made immediately
and then execution continues to Console.WriteLine("WebClient - Before
calling wait");
when using HttpClient the request to the web api is not made until
the call to await task;
I'm trying to understand why the request is not made immediately when using HttpClient. Can anyone point me in the right direction?
This is not a duplicate question. I'm not looking for reasons to choose one option over the other - I'll use HttpClient. I would like to know specifically why the request is created at a later stage when using HttpClient.
Thanks,
David
Since both of the requests are async, none of them should delay execution of your current thread (significantly).
It is possible, though, that one of them can send the request before the current thread reaches the next line, while the other cannot.
These kinds of timing issues can happen in asynchronous/parallel environments and they're nothing to worry about as long as you don't separate logically successive operations.
I have the following async code
public async static void SendAsync(string url)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.KeepAlive = false;
request.Timeout = 5000;
var response = await request.GetResponseAsync().ConfigureAwait(false);
response.Close();
}
catch (Exception ex)
{
SendException(ex, url);
}
}
Which is called by the controller action.
public ActionResult Details(string id)
{
// DO something
SendAsync(some-valid-url);
// Do something
return View();
}
When i debug it - it runs async and hits
return View();
and exits before it is comes to
response.Close();
But in fiddler you can see that the http response is not sent by the browser and it waits for the SendAsync function to finish processing, which is not what i want. I want the http response to return back to the user right away.
What do I have to change here to achieve that?
i actually edited it and am now doing async static void since i do not
need to track the end of the task,
But you do need to keep track, as MVC will close the connection when Details returns, you need to tell MVC you are waiting for a background action.
public async Task<ActionResult> DetailsAsync(string id)
{
// DO something
var sendTask = SendAsync(some-valid-url);
// Do something else that does not depend on sendTask
await sendTask;
return View();
}
To answer your updated comment
doing an await will make it wait for the async http call to finish.
Which i do not want.
To get the behavior you are looking for you need to use AJAX, the async/await system will not give you what you want by itself. (I have never really done MVC with AJAX so I don't have a example for you how to do it)
doing an await will make it wait for the async http call to finish.
Which i do not want.
It sounds to me like you want fire and forget since you don't want to wait for the response.
There are a few negative points to bare in mind (such as no error handling, no guarantees, etc), so I would recommend reading into this a bit before dropping it into your project.
This is, in my opinion, is the easiest way to call a method with fire and forget.
ThreadPool.QueueUserWorkItem(o => SendAsync(some-valid-url));
This will request an available thread from the app pool. It will then use that thread to execute the method without blocking your current running one.
I hope this helps.
I am just looking at the default MVC5 project and how it uses async in the controllers.
I would like to know what benefit async provides here over simply using synchronous calls:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
{
ManageMessageId? message = null;
//why use an async database call here with await instead of just using a synchronous one?
IdentityResult result = await UserManager.RemoveLoginAsync(User.Identity.GetUserId(), new UserLoginInfo(loginProvider, providerKey));
if (result.Succeeded)
{
message = ManageMessageId.RemoveLoginSuccess;
}
else
{
message = ManageMessageId.Error;
}
return RedirectToAction("Manage", new { Message = message });
}
What am I missing?
Does this provide some kind of performance benefit in the type of wait that will occur here?
On the server side (e.g., ASP.NET MVC), any I/O you do (e.g., databases) should be done asynchronously. This frees up the request thread for the time that the I/O is in flight.
So, when the RemoveLoginAsync sends its SQL to the database, it returns an incomplete task, and when the request hits the await, it returns the request thread to the thread pool. Later, when the DB operation completes, a request thread is taken from the thread pool and used to continue the request.
The end result is scalability, because (in the 99.9% case at least) tasks scale better than threads. However, there isn't a big advantage if your database is just a single server and all requests hit the db, because your scalability bottleneck in that scenario is the db server, not the web server.