I have an ASP.NET MVC 3 site that connects to a WCF service. The WCF Service is independent from the site and is hosted in a Windows Service.
Most of the calls are synchronous, so it's not a problem to wait for the WCF to do it's thing.
However, one of those (already implemented) calls takes a bit too long, and, as it essentially does not output anything directly, I wanted to spin it on the service and forget about it.
So I changed my code from:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
ViewBag.Started = true;
return View();
}
to
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
Task.Run(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
which, as I understand should start an asynchronous request, and return immediately. Still, the execution is completely synchronous, and the UI is frozen until the operation concludes.
What obvious thing am I missing?
Update:
Also, note that I would prefer not to change the server implementation to an async one, just to de-synchronize the call to the service on the call-site.
Moreover, I've noticed that the StartSlowCalculation method finishes executing, but the server does not return a response until the service method finishes executing.
The WCF Service Proxy just does:
public void DoSlowCalculation(CalculationOptions calculationOptions)
{
//some logging code
Channel.DoSlowCalculation(calculationOptions);
}
so it's completely synchronous, however that shouldn't matter as it should be executed on an independent thread.
A task operation can run in the calling thread, it depends on taskScheduler decision. To help TaskScheduler make a right decision regarding long running call you can specify task creation option TaskCreationOptions.LongRunning.
And you can check whether task operation is running in a separate thread:
int launchedByThreadId = Thread.CurrentThread.ManagedThreadId;
int launchedInThreadId = -1;
Task.Run(() =>
{
launchedInThreadId = Thread.CurrentThread.ManagedThreadId;
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
// then compare whether thread ids are different
BTW, are you using any kind of Task.Wait() operation? It will block calling thread as well.
EDIT:
You might find following post interesting Is Task.Factory.StartNew() guaranteed to use another thread than the calling thread?
So try out using Task.Factory.StartNew() and specify cancellation token even you do not need it, sounds weird but it seems this guarantees that task will not be run eventually in the calling thread. Correct me If I wrong.
I've done this before.
The most robust way would be to use Asynchronous Controller's, or better yet an independant service such as a WCF service.
But in my experience, i've just needed to do "simple", one-liner task, such as auditing or reporting.
In that example, the easy way - fire off a Task:
public ViewResult StartSlowCalculation(CalculationOptions calculationOptions)
{
//Some Synchronous code.
Task.Factory.StartNew(() =>
{
WcfServiceProxy.DoSlowCalculation(calculationOptions);
});
ViewBag.Started = true;
return View();
}
That's a simple example. You can fire off as many tasks as you want, synchronize them, get notified when they finish, etc.
For more details you can see this links.
https://msdn.microsoft.com/en-us/library/dd321439(v=vs.110).aspx
Related
I have the following action in my controller:
[HttpPost("run")]
public Task<object> Run([FromBody] ResearchRequest researchRequest)
{
researchService.RunAsync(researchRequest);
return new{ queued = true };
}
The controller needs to handle a task that takes several minutes.
Is this the correct way to release researchService.RunAsync to handle its job?
Or is there a better approach.
Thanks
If you are wanting to check that a process is already running, you could mark it as in progress somewhere on the server side (in a task in the database or such) and then when displaying the UI call a method on the server to check the state of your in progress flag.
that way the UI could navigate away from that page and return to still see that the process had been started
You can do that if RunAsync is making I/O requests, but you wouldn't return a Task:
[HttpPost("run")]
public object Run([FromBody] ResearchRequest researchRequest)
{
researchService.RunAsync(researchRequest);
return new{ queued = true };
}
That will start running RunAsync on the same thread, just like any other method. At the first await in RunAsync that acts on an incomplete Task, RunAsync will return its own incomplete Task, at which point control returns back to your Run action and your object is returned. You won't be waiting for whatever I/O operation RunAsync makes.
If RunAsync is taking a long time because of CPU calculations (not I/O), then that won't do anything for you because, remember, it starts running on the same thread. You will have to start it on another thread, which you can do using Task.Run:
[HttpPost("run")]
public Task<object> Run([FromBody] ResearchRequest researchRequest)
{
Task.Run(() => researchService.RunAsync(researchRequest));
return new{ queued = true };
}
But!
In both cases, ASP.NET will have no idea that RunAsync is running in the background. If the IIS app pool is shut down or recycled for any reason, that job will be killed part way through. Note that by default, IIS is configured to shut down an app pool after 20 minutes of no HTTP requests coming in.
If that is unacceptable to you, then you're better off writing the job to a queue in a database or something and doing that background processing in a Windows service.
I am writing a MVC5 app that has a controller with a function say Method1
I have a third party function that is async Task, let's call it DoMethodAsync (it essentially makes a POST call).
I want to call it right before returning from Method1 but I don't really care about the result of the async task, if it fails, it fails. How can I fire and forget and have it execute in the background so that it does not block the controller from responding to other requests?
How can I ensure that DoMethodAsync is only executed after Method1 has returned?
I don't really care about the result of the async task, if it fails, it fails.
Really? Just asking, because this is an extremely rare use case.
How can I fire and forget and have it execute in the background so that it does not block the controller from responding to other requests?
I have a blog post that looks into various approaches to "fire and forget" tasks on ASP.NET.
You don't want to just call the method and ignore the returned task, because that method will inherit the request context for the initiating request. Then after the request is completed, the request context is disposed, and that method can end up in an "interesting" place - some things will work, but others will not.
So, the minimum viable solution is to wrap it in Task.Run:
var _ignored = Task.Run(() => DoMethodAsync());
However, note that ASP.NET is completely unaware of this "extra operation". If you want DoMethodAsync to have more of a chance of actually executing to completion, then you'll want to register it with the ASP.NET runtime, either using HostingEnvironment.QueueBackgroundWorkItem (4.5.2+) or my own BackgroundTaskManager.Run (4.5.0/4.5.1).
Also note that none of these options will guarantee that DoMethodAsync will run to completion; they just give you a "best effort." For a truly reliable system, you'd need a proper distributed architecture, i.e., reliable storage with an independent processor.
I know this is old, but after hours of searching and trying different things myself, I came across this thread. Combining some info here with other resource, I was able to implement what I wanted which I believe is the same thing the OP wanted.
I wanted to call a URL like /API/Start and I wanted that URL to instantly return a view that said "Thank you for starting, check back later". However it needed to then simply kick off a background job.
This is with MVC 5 so not sure if it makes a difference, but...
Side Note: To see this in action, use 2 URL's
/Default/Index <-- will report back ~5 seconds
/Default/IndexAsync <-- will report back ~0 seconds (well sort of .. you'll see)
public class DefaultController : Controller
{
// GET: Sync
public ActionResult Index()
{
System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
myStopwatch.Start();
DoTask();
myStopwatch.Stop();
ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
return View("Index");
}
// GET: Async
public ActionResult IndexAsync()
{
System.Diagnostics.Stopwatch myStopwatch = new System.Diagnostics.Stopwatch();
myStopwatch.Start();
Task.Factory.StartNew(DoTaskAsync);
myStopwatch.Stop();
ViewBag.Message = ($"Process took {myStopwatch.Elapsed.TotalSeconds.ToString()}");
return View("Index");
}
// "the Sync Task"
private void DoTask()
{
System.Diagnostics.Debug.Print($"DoTask Started at {DateTime.Now.ToString()}");
System.Threading.Thread.Sleep(5000);
System.Diagnostics.Debug.Print($"DoTask Finished at {DateTime.Now.ToString()}");
}
// "the Async Task"
private async Task DoTaskAsync()
{
System.Diagnostics.Debug.Print($"DoTaskAsync Started at {DateTime.Now.ToString()}");
System.Threading.Thread.Sleep(5000);
System.Diagnostics.Debug.Print($"DoTaskAsync Finished at {DateTime.Now.ToString()}");
}
}
Calling an asynchronous method means that the calling method (your code) will not be blocked while the async method is executing, at least not by default (you can make your code block via the 'await' keyword or via calling one of the task's blocking methods like 'Result' or 'Wait', etc...).
That means that if you just call that method, the method will run asynchronously and your code will not wait for it to end. I think that exactly what you want.
public ActionResult Index()
{
DoMethodAsync(); // if you do not await and simple call this task it will run in backround as you want
return View();
}
async Task DoMethodAsync()
{
// calculate something
}
In an Asp.Net MVC application if an Asynchronous Controller's Session behavior is Read only, its Action method is also Asynchronous and within it we create a Task Thread that does some long running stuff, example:
[SessionState(SessionStateBehavior.ReadOnly)]
public class UploadController : AsyncController
{
public void UploadFilesAsync(IEnumerable<HttpPostedFileBase> assetFiles,
string filesMetaInfo)
{
var postedFiles = assetFiles;
var fInfo = filesMetaInfo;
AsyncManager.OutstandingOperations.Increment();
Task.Factory.StartNew(
() => ProcessUploadedFile(postedFiles, fInfo),
CancellationToken.None, TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
}
public ActionResult UploadFilesCompleted(object result)
{
return Json(new
{
status = "OK"
}, "text/plain");
}
private void ProcessUploadedFile(IEnumerable<HttpPostedFileBase>
assetFiles, string filesInfo)
{
// Do some long running stuff here like file processing.
// ......................
// ..................................
AsyncManager.Parameters["result"] = "success"
AsyncManager.OutstandingOperations.Decrement();
}
}
Two questions now:
Will this Controller Action method UploadFilesAsync(), release this Controller for other Requests once the inside Task thread work completes fully or be available to other Requests right after when the Task just starts executing?
Also what will happen if I make this UploadFilesAsync() method behave in a synchronous manner by applying "Synchronized" attribute on it? example:
[MethodImpl(MethodImplOptions.Synchronized)]
Will this Controller Action method UploadFilesAsync(), release this
Controller for other Requests once the inside Task thread work
completes fully or be available to other Requests right after when the
Task just starts executing?
By "release this controller" I'm assuming you mean release the ASP.NET threadpool thread currently occupied with processing your message. If so, the answer is the latter. It will release the current thread immediately without waiting for the inner task executed to complete.
Also what will happen if I make this UploadFilesAsync() method behave
in a synchronous manner by applying "Synchronized" attribute on it?
MethodImplOptions.Synchronized does not make the method run synchronously. It merely is like wrapping your whole method executing with lock (this). This would mean the that multiple callers won't be able to use the same instance of your Controller, but that doesn't happen anyway, as a new Controller is spun up for every request made. That means it will make no difference whatsoever.
As a side note - You should not be using Task.Factory.StartNew nor Task.Run inside ASP.NET, because any work offloaded to that threadpool thread will not be registered with IIS, which means your thread could be abnormally aborted due to IIS recycling. Instead, look into HostingEnvironment.QueueBackgroundWorkItem if you're using .NET 4.5.2, or look into Stephan Clearys AspNetBackgroundTasks
I would need your help in the following. For nearly a month, I have been reading regarding Tasks and async .
I wanted to try to implement my new acquired knowledege, in a simple wep api project. I have the following methods and both of them working as expected:
public HttpResponseMessage Get()
{
var data = _userServices.GetUsers();
return Request.CreateResponse(HttpStatusCode.OK, data);
}
public async Task<HttpResponseMessage> Get()
{
var data = _userServices.GetUsers();
return await Task<HttpResponseMessage>.Factory.StartNew(() =>
{
return Request.CreateResponse(HttpStatusCode.OK, data);
});
}
So the question. I have tried to use fiddler and see what is the difference between these two. The async one is little faster, but apart from that, what is the real benefit in implementing something like that in a web api?
As others have pointed out, the point of async on ASP.NET is that it frees up one of the ASP.NET thread pool threads. This works great for naturally-asynchronous operations such as I/O-bound operations because that's one less thread on the server (there is no thread that is "processing" the async operation, as I explain on my blog). Thus, the primary benefit of async on the server side is scalability.
However, you want to avoid Task.Run (and, even worse, Task.Factory.StartNew) on ASP.NET. I call this "fake asynchrony" because they're just doing synchronous/blocking work on a thread pool thread. They're useful in UI apps where you want to push work off the UI thread so the UI remains responsive, but they should (almost) never be used on ASP.NET or other server apps.
Using Task.Run or Task.Factory.StartNew on ASP.NET will actually decrease your scalability. They will cause some unnecessary thread switches. For longer-running operations, you could end up throwing off the ASP.NET thread pool heuristics, causing additional threads to be created and later destroyed needlessly. I explore these performance problems step-by-step in another blog post.
So, you need to think about what each action is doing, and whether any of that should be async. If it should, then that action should be async. In your case:
public HttpResponseMessage Get()
{
var data = _userServices.GetUsers();
return Request.CreateResponse(HttpStatusCode.OK, data);
}
What exactly is Request.CreateResponse doing? It's just creating response object. That's it - just a fancy new. There's no I/O going on there, and it certainly isn't something that needs to be pushed off to a background thread.
However, GetUsers is much more interesting. That sounds more like a data read, which is I/O-based. If your backend can scale (e.g., Azure SQL / Tables / etc), then you should look at making that async first, and once your service is exposing a GetUsersAsync, then this action could become async too:
public async Task<HttpResponseMessage> Get()
{
var data = await _userServices.GetUsersAsync();
return Request.CreateResponse(HttpStatusCode.OK, data);
}
Using async on your server can dramatically improve scalability as it frees up the thread serving the request to handle other requests while the async operation is in progress. For example in a synchronous IO operaton, the thread would be suspended and doing nothing until the operation completes and would not be available to serve another request.
That being said, using Task.Factory.StartNew starts another thread so you don't get the scalability benefits at all. Your original thread can be reused, but you have offloaded the work to another thread so there is no net benefit at all. in fact there is a cost of switching to another thread, but that is minimal.
Truly asynchronous operations do not start a thread and I would look to see if such an operation exists, or if one can be written for Request.CreateResponse. Then your code would be much more scalable. If not, you are better off sticking with the synchronous approach.
It makes more sense where the call is happening with major IO operations.
Yes, Async is faster because it frees up the request thread for the time that the operations is being performed. Thus, from Web server point of view, you are giving a thread back to the pool that can be used by the server for any future calls coming through.
So for e.g. when you are performing a search operation on SQL server, you might want to do async and see the performance benefit.
It is good for scalability that involves multiple servers.
So, for e.g. when the SearchRecordAsync 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.
Even if you are not using, SQL operations, let say you want to send an email to 10 people. In this case also async makes more sense.
Async is also very handy to show the progress of long event. So user will still get the active GUI, while the task is running at the background.
To understand, please have a look at this sample.
Here I am trying to initiate task called send mail. Interim I want to update database, while the background is performing send mail task.
Once the database update has happened, it is waiting for the send mail task to be completed. However, with this approach it is quite clear that I can run task at the background and still proceed with original (main) thread.
using System;
using System.Threading;
using System.Threading.Tasks;
public class Program
{
public static void Main()
{
Console.WriteLine("Starting Send Mail Async Task");
Task task = new Task(SendMessage);
task.Start();
Console.WriteLine("Update Database");
UpdateDatabase();
while (true)
{
// dummy wait for background send mail.
if (task.Status == TaskStatus.RanToCompletion)
{
break;
}
}
}
public static async void SendMessage()
{
// Calls to TaskOfTResult_MethodAsync
Task<bool> returnedTaskTResult = MailSenderAsync();
bool result = await returnedTaskTResult;
if (result)
{
UpdateDatabase();
}
Console.WriteLine("Mail Sent!");
}
private static void UpdateDatabase()
{
for (var i = 1; i < 1000; i++) ;
Console.WriteLine("Database Updated!");
}
private static async Task<bool> MailSenderAsync()
{
Console.WriteLine("Send Mail Start.");
for (var i = 1; i < 1000000000; i++) ;
return true;
}
}
i have a Problem in MonoAndroid calling a WCF Service async.
I followed this Tutorial and created the Portable Class Lib. http://nullskull.com/a/10476775/xamarin-cross-platform-application-consuming-wcf--part-1.aspx
Here is my Service Method which is calling the WCF Service:
public async static Task<KeyExchangeModel> GetPublicKeyFromServer(KeyExchangeModel model)
{
try
{
ISyncService client;
client = new SyncServiceClient(_binding, _endpointAddress);
var res = Task<KeyExchangeModel>.Factory.FromAsync(client.BeginGetServerPublicKey, client.EndGetServerPublicKey,
model, null);
await res;
return res.Result;
}
catch (Exception e)
{
return null;
}
}
An here i call the Method and wait till it´s executed.
Task<KeyExchangeModel> task = SyncServiceAgent.GetPublicKeyFromServer(keyModel);
task.Wait();
KeyExchangeModel serverModel = task.Result;
The Problem is that on Android i never get the Result. It stuck´s in a Loop. No Exception is logged in the Device Log or is thrown.
This code Perfectly works on a Windows Unit Test and on a Windows Phone Project.
I hope anyone can help me.
Thanks a lot.
Your problem is this line here: task.Wait(); Blocking on asynchronous code can cause deadlocks.
By default, await will capture the current "context", and use that context to resume the async method. In this case, it's probably capturing the UI context, which is tied to the UI thread. So, GetPublicKeyFromServer will start the WCF call, capture the UI context, and return an incomplete task. The calling code then calls Task.Wait on that task, which blocks the UI thread until that async method completes.
Later, the WCF call returns, and GetPublicKeyFromServer attempts to resume in the same context (on the UI thread). However, the UI thread is blocked waiting for GetPublicKeyFromServer to complete. This is a classic deadlock situation.
The reason it work in a unit test is because the async method captures a thread pool context instead of the UI context, so it is able to block one thread pool thread in the Wait and another thread pool thread can complete the async method. Normally, a Windows Phone app would have the same problem with UI context as the Android app, so I suspect that there's something different with the test code, and that's why it's not deadlocking on WP.
I describe this problem in more detail on my blog, in an MSDN article, and in my book.
The best resolution for this problem is to use await instead of Task.Wait or Task<T>.Result. I.e., your calling code should be:
Task<KeyExchangeModel> task = SyncServiceAgent.GetPublicKeyFromServer(keyModel);
KeyExchangeModel serverModel = await task;
This will require your calling code to be async, which in turn requires its callers to be async, etc. This "growth" of async through the codebase is natural and normal.