REST-Call with async server implementation - c#

In my application I have a server which provides a REST-Api where my UI can communicate with.
Now I have to start a long running Process on the Server but I want the client not to wait for the response of the server.
I know I could just fire and forget the Post-Call and not await the response but I need to know at the client that the Process on the server was startet correctly.
So I thought about the following:
[HttpPost]
[Route("startscan")]
public HttpResponseMessage StartScan()
{
Task.Factory.StartNew( () =>
{
//Do long running things here
});
return Request.CreateResponse(HttpStatusCode.OK);
}
So my question now is: Will the task I started be executed to it's end? Background of the question is, that as far as I knwo a controller-instance is created for each call to it. So will the instance of the controller be terminated when the requested finished or will the Task I started run to it's end. The task can take up to 10 minutes or longer sometimes.

A simple approach would be to just use an asynchronous method without awaiting the Task result like so:
[HttpPost]
[Route("startscan")]
public async HttpResponseMessage StartScan()
{
DoLongRunningThings();
return Request.CreateResponse(HttpStatusCode.OK);
}
public async Task DoLongRunningThings()
{
// Do Stuff here
}
However, if you Processing is more complex and requires more resilience you should look into how to use background jobs. Here is a good collection of what you can use: https://stackoverflow.com/a/36098218/16154479

Will the task I started be executed to it's end?
Probably yes, but also possibly no. Sometimes it won't be executed completely. This is the result of misusing an ASP.NET app (which handles HTTP requests) as a background service (which runs outside of a request context).
There is a best practice that avoids possibly-partial execution: a distributed architecture (as I describe on my blog). The idea is that your controller enqueues a message describing the work to be done into a durable queue and then returns. Then there's a separate background service that reads from the queue and does the actual work.

Related

Is a return ViewAsync in MVC an advantage and why doesn't it exist?

I hope this is still on-topic. In this post here I saw how to create an await ViewAsync():
Returning a view with async keyword
So my consideration was: okay, I want to make my application use multithreading, let's make a BaseController that contains those methods for ViewAsync:
just a part of it:
public class BaseController : Controller
{
[NonAction]
public virtual async Task<ViewResult> ViewAsync()
{
return await Task.Run(() => this.View(null));
}
[NonAction]
public virtual async Task<ViewResult> ViewAsync(string viewName)
{
return await Task.Run(() => this.View(viewName, this.ViewData.Model));
}
// the other implementations....
}
now I could always call like this in the inheriting class:
[HttpGet]
public async Task<IActionResult> DoSomething()
{
// maybe we need to do something here, maybe not
return await ViewAsync(new DoSomethingObject());
}
imho, my advantage/target is performance since I always can use multithreading now.
Am I right with my consideration?
In the post, a comment to an answer started with I wouldn't do this. But there aren't many votes/comments/answers.. Where are risks or disadvantages of such an implementation? And maybe, why doesn't Microsoft.AspNetCore.Mvc.Controller come with the method ViewAsync?
Any web app already uses multithreading. When a request comes in, a thread from the thread pool handles it. Your app already handles multiple requests at the same time, without you using Task.Run.
Async/await stuff is useful so that you don't block threads from the thread pool while you wait for async operations to complete (like querying a DB).
Starting new tasks Task.Run on the default thread pool is pretty much useless, unless you are doing some CPU intensive work. Let's say you have an endpoint that calculates the prime numbers up to n on each request, in that case you could delegate a new task on the default thread pool that returns the prime numbers, and have a view that renders them to some html.
Rendering a view has nothing asynchronous about it, so a ViewAsync is not needed. Preparing the data for a view probably is async, but the rendering is not. Also, having a ViewAsync would probably over complicate the template syntax.

Best Practice for I/O Heavy Async Task with WebApi

I have async action responding to a HTTP POST via web api 1.0. I need to do 2 things when I receive this request:
Do a database insert and return the identity of that new entry to the WebApp that called the function.
Using that identity to do a whole bunch work that is I/O heavy, that they WebApp and the user don't immediately care about.
In a perfect world I would put data on a queue somewhere and have a little worker to handle the queue. Since I can't immediately do that, what is the best way to make sure this work gets done without impacting the user.
[HttpPost]
public async Task<int> Post([FromBody]Object myObject)
{
return await new ObjectLogic().InsertObject(myObject);
}
public async Task<int> InsertObject(Object myObject)
{
var id = await new ObjectData().InsertObjectRoot(myObject);
Task.Run(() => new ObjectData().ObjectWork(id, myObject));
return id;
}
This is the solution I came up but I think there has to be something better since I am bascially stealing of thread from the thread pool until my work is finished. Is there a better way? I think I could use ConfigureAwait(false) in my InsertObject method since I really dont' care about the context there.
// await async function but use ConfigureAwait
public async Task<int> InsertObject(Object myObject)
{
var id = await new ObjectData().InsertObjectRoot(myObject);
await new ObjectData().ObjectWork(id, myObject).ConfigureAwait(false);
return id;
}
One question is whether your Web API should do anything other than
receive the request
place it on a queue
response with an id to indicate that the request has been received.
It's going to depend to some degree on what sort of load you're expecting or might possibly see. But if you're concerned about the number of available threads from the outset then perhaps the answer is that your Web API does nothing but the above steps.
The queue could be a literal queue, like MSMQ (or whatever is popular now.) Or it could consist of a record inserted into a table. A separate Windows service could then process that queue and do the I/O heavy work. It doesn't even have to be on the same server. You can scale it separately.
If the user does want some eventual indication then they could poll for it at intervals using the id that you returned. But for me the key is in this statement:
Using that identity to do a whole bunch work that is I/O heavy, that the WebApp and the user don't immediately care about.
The job of a web application is to serve responses - IOW, to do what the user does care about. If it's long-running, I/O heavy work that the user doesn't care about then I'd consider offloading it.

Fire and Forget method in Async Web Api hosted in OwinCommunicationListener

Recently I can across a code that we are using and is working fine and for the life of me I cannot figure out why.
We have a web API hosted in a service fabric cluster that is hosted over OwinCommunicationListener.
[HttpPost]
public async Task<HttpResponseMessage> WebApiMethod(RequestObject request)
{
string test;
SomeObject obj;
....
DoSomethingAsync(test, obj);
return this.ActionContext.CreateResponse(HttpStatusCode.OK, new { Status = "Success" });
}
private async Task DoSomethingAsync(string param1, SomeObject param2)
{
.....
await SomeOtherAsyncMethod();
.....
}
As far as I understand it should be a race condition between the method completion of DoSomethingAsync and the request disposing off and should throw an TaskCancelledException or something if later completes early, but it never does.
I am expecting some error since the task DoSomething is not awaited and yet it completes its work everytime. If I add
await Task.Delay(10000);
then the API response almost instantaneously and after the 10 seconds rest of the code is executed. Shouldn't by that time the host thread should be disposed since the original call was a Fire-and-Forget (not awaited).
What am I missing here.
There is nothing that ties request object with DoSomethingAsync. But even if you pass RequestObj reference right into DoSomethingAsync, the method will get completed with no problem as GC won't collect your RequestObj while you're referencing the object. Also, once async execution kicks off, it lives its own life meaning the callback might be completed on a different thread but the one that request-handling pipeline has been dispatched with.

Problems And Errors While Implementing Async Controller Action

It seems that I have massive problems understanding the topic regarding async-operations in C# and especially ASP.NET MVC in Controller.
I have a Controller for all of my AJAX-Requests from my Webpage. for each I have an action. Now I try to implement like a 'notification-system'. I created a class which handles the notification in a Queue, which are selected through a dictionary using the SessionID.
Because I am using Reverse-AJAX, the Thread working on the AJAX-Response needs to be hold at the Server. Therefore, I used Thread.Sleep in combination with a while to check if the queue has elements or not. Here is the part of the controller:
public class AJAXController : AsyncController
{
public async void polling()
{
if (Session["init"] == null) //so the sessionID is not changing on every request
Session.Add("init", 0);
NotificationQueue queue =
NotificationQueue.getInstance(HttpContext.Session.SessionID);
object responseObj = null;
responseObj = await Task.Run(() =>
{
while (queue.getSize() == 0)
Thread.Sleep(200);
return queue.getNextQueueElement(); //behind this is queue.Dequeue();
});
Response.Write(new JavaScriptSerializer().Serialize(responseObj));
}
}
Basically, I don't now what is incorrect with that code - neither I know with is correct.
The syntax is correct, but when I try to use the website, the Server answers with: 500 (internal Server error), Message: >>An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%# Page Async="true" %>. This exception may also indicate an attempt to call an "async void" method, which is generally unsupported within ASP.NET request processing. Instead, the asynchronous method should return a Task, and the caller should await it.<<
Do I need an AsyncController? The other methods aren't Asynchronous because these are just simple responses.
I tried to use public async void pollingAsync() in Combination with public async string pollingCompleted(string response), but the parameter was null every time.
My Questions are the above and how I can solve the problem. Is there a better solution, and when yes, how could I implement this?
I appreciate any help!
Don't use async void, use async Task instead. async void operations are generally fire and forget, as you have no way of asynchronously waiting on them. Also, there's no need to use AsyncController when using async-await. You can read more about that here
You need:
public async Task PollingAsync()
{
if (Session["init"] == null) //so the sessionID is not changing on every request
Session.Add("init", 0);
NotificationQueue queue =
NotificationQueue.getInstance(HttpContext.Session.SessionID);
while (queue.GetSize() == 0)
await Task.Delay(200);
var responseObj = queue.getNextQueueElement();
Response.Write(new JavaScriptSerializer().Serialize(responseObj));
}
Generally speaking, as a side note, you can get around the "polling" experience by using websockets, with a technology such as SignalR this is even made quite easy and friendly. I'd recommend looking into that.

Async does not work in asynchronous controller mvc 4.0

I have MVC 4.0 application targated at targetFramework="4.5".
I have to basically convert the existing functionality of file processing from synchronous to asynchronous (so that for large file user don't have to wait for other task).
My code is
[HttpPost]
public async Task<ActionResult> FileUpload(HttpPostedFileBase fileUpload)
{
Coreservice objVDS = new Coreservice ();
//validate the contents of the file
model =objVDS. ValidateFileContents(fileUpload);
// if file is valid start processing asynchronously
await Task.Factory.StartNew(() => { objVDS.ProcessValidFile(model); }, CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
return view();
}
Basically I want to call a asynchronous method which is in services which does database operations( diffrent project).
I want asynchronous process to have access to the context in services methods. Thats why I am using
TaskScheduler.FromCurrentSynchronizationContext() in Task.Factory.StartNew().
The service method is like following in which, based on file type, a second service is getting called for data operations
public async task ProcessValidFile(fileProcessDataModel model)
{
employeeWorkedDataservice service =new employeeWorkedDataservice()
await Task.Factory.StartNew(() =>
{
service .ProcessEmployeeDataFile(model.DataSetToProcess, OriginalFileName, this, model.Source);
},
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
}
ProcessEmployeeDataFile returns void and its not asynchronous method.
When the code above is executed it does not return to controller untill it completes the data processing. I think that I am missing something here.
Please guide me to solution.
Thanks,
Amol
Looks like you've misunderstood how await works.
Read this https://msdn.microsoft.com/en-us/library/hh191443.aspx#BKMK_WhatHappensUnderstandinganAsyncMethod
Setting something running in a task will allow it to run asynchronously so you can do something else while it's running.
When you need the result to continue, you use the await keyword.
By creating your task an immediately awaiting it, you're instantly blocking until the task resolves; making it effectively synchronous.
If you're happy to return to your view without waiting for processing to complete, I don't think you need await at all, since at no point do you want to wait for the result of the operation.
public task ProcessValidFile(fileProcessDataModel model)
{
employeeWorkedDataservice service =new employeeWorkedDataservice()
return Task.Factory.StartNew(() =>
{
service.ProcessEmployeeDataFile(model.DataSetToProcess, OriginalFileName, this, model.Source);
},
CancellationToken.None,
TaskCreationOptions.DenyChildAttach,
TaskScheduler.FromCurrentSynchronizationContext());
}
[HttpPost]
public ActionResult FileUpload(HttpPostedFileBase fileUpload)
{
Coreservice objVDS = new Coreservice ();
//validate the contents of the file
model =objVDS. ValidateFileContents(fileUpload);
// if file is valid start processing asynchronously
// This returns a task, but if we're not interested in waiting
// for its results, we can ignore it.
objVDS.ProcessValidFile(model);
return view();
}
Regarding your comments:
I would seriously consider not passing your controller to your service, or having your service rely on the session and context since you're tightly coupling your business logic to your API controller.
Get the bits you need from the controller while you're in it and pass them to your service.
I have to basically convert the existing functionality of file processing from synchronous to asynchronous (so that for large file user don't have to wait for other task).
That's not what async does; as I describe on my blog, async does not change the HTTP protocol.
What you want is some form of "fire and forget" on ASP.NET. I have another blog post that covers a few solutions. Note that using Task.Factory.StartNew is the most dangerous of all these solutions.
The best (read: most reliable) solution is to use a proper distributed architecture: your ASP.NET app should create a description of the work to be done and place that in a reliable queue (e.g., MSMQ); then have an independent backend (e.g., Win32 service) that processes the queue. This is complex, but much less error-prone than attempting to force ASP.NET to do something it was never meant to do.

Categories