how i can make asynchronus result in ASP.NET MVC 3? - c#

i want a thing in JsonResult that they respond after the got request from the browser [client side] and respond them quickly before done the task.
means request come respond before task done and run a thread to done the task.
can anyone show me the code for doing that in asp.net MVC

Isn't AJAX sufficient for your scenario?
$.getJSON('#Url.Action("Foo")', function(result) {
// once the task completes this callback will be executed
});
// flow continues to execute normally
and on the server side:
public ActionResult Foo()
{
// TODO: some task
return Json(someResult, JsonRequestBehavior.AllowGet);
}
If this task is I/O intensive you could take advantage of asynchronous controllers and I/O Completion Ports.
If you have a fire-and-forget scenario you could simply start the task and return immediately from the controller:
public ActionResult StartTask()
{
// Fire the task
Task.Factory.StartNew(() =>
{
// TODO: the task goes here
// Remark: Ensure you handle exceptions
});
// return immediately
return Json(
new { Message = "Task started" },
JsonRequestBehavior.AllowGet
);
}

Related

Owin self hosting - limiting maximum time for request

How to efficiently limit request length timeout on server side ? I'm using Microsoft.Owin.Host.HttpListener and there are cases when (due to call to external service) serving request takes ridiculous amount of time. This is not a problem - but web server should give up sooner than - well never (I did some tests, but after 5 minutes I stopped it).
Is there a way how to limit time for serving single request (similar to <httpRuntime maxRequestLength="..." /> in IIS ecosystem) ?
Sample controller code:
public async Task<HttpResponseMessage> Get() {
// ... calls to 3pty services here
await Task.Delay(TimeSpan.FromMinutes(5));
}
Starting web server:
WebApp.Start(this.listeningAddress, new Action<IAppBuilder>(this.Build));
Note: I've read about limiting http listener, but that just limits incoming request properties, it doesn't cancel request that is slow due to slow server processing:
var listener = appBuilder.Properties[typeof(OwinHttpListener).FullName] as OwinHttpListener;
var timeoutManager = listener.Listener.TimeoutManager;
timeoutManager.DrainEntityBody = TimeSpan.FromSeconds(20);
timeoutManager.EntityBody = TimeSpan.FromSeconds(20);
timeoutManager.HeaderWait = TimeSpan.FromSeconds(20);
timeoutManager.IdleConnection = TimeSpan.FromSeconds(20);
timeoutManager.RequestQueue = TimeSpan.FromSeconds(20);
Related:
https://github.com/aspnet/AspNetKatana/issues/152
Conceptually "older" web server solutions - i.e. IIS are using one-thread-per-request separation and ThreadAbortException to kill slow requests. Owin is using different philosophy - i.e. it fires new task per request and forcibly cancelling task is best avoided. There are two sides of this problem:
shus client away if it takes too long
cancel server processing if it takes too long
Both can be achieved using middleware component. There also is a cancellation token provided directly by owin infrastructure for cases when client disconnects (context.Request.CallCancelled where context is IOwinContext)
If you're interested only in cancelling server flow ASAP when it takes to long, I'd recommend something like
public class MyMiddlewareClass : OwinMiddleware
{
// 5 secs is ok for testing, you might want to increase this
const int WAIT_MAX_MS = 5000;
public MyMiddlewareClass(OwinMiddleware next) : base(next)
{
}
public override async Task Invoke(IOwinContext context)
{
using (var source = CancellationTokenSource.CreateLinkedTokenSource(
context.Request.CallCancelled))
{
source.CancelAfter(WAIT_MAX_MS);
// combined "client disconnected" and "it takes too long" token
context.Set("RequestTerminated", source.Token);
await Next.Invoke(context);
}
}
}
And then in controller
public async Task<string> Get()
{
var context = this.Request.GetOwinContext();
var token = context.Get<CancellationToken>("RequestTerminated");
// simulate long async call
await Task.Delay(10000, token);
token.ThrowIfCancellationRequested();
return "Hello !";
}
Shusing the client away is more complex. The middleware will look like this:
public static async Task ShutDownClientWhenItTakesTooLong(IOwinContext context,
CancellationToken timeoutToken)
{
await Task.Delay(WAIT_MAX_MS, timeoutToken);
if (timeoutToken.IsCancellationRequested)
{
return;
}
context.Response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
}
public async Task ExecuteMainRequest(IOwinContext context,
CancellationTokenSource timeoutSource, Task timeoutTask)
{
try
{
await Next.Invoke(context);
}
finally
{
timeoutSource.Cancel();
await timeoutTask;
}
}
public override async Task Invoke(IOwinContext context)
{
using (var source = CancellationTokenSource.CreateLinkedTokenSource(
context.Request.CallCancelled))
using (var timeoutSource = new CancellationTokenSource())
{
source.CancelAfter(WAIT_MAX_MS);
context.Set("RequestTerminated", source.Token);
var timeoutTask = ShutDownClientWhenItTakesTooLong(context, timeoutSource.Token);
await Task.WhenAny(
timeoutTask,
ExecuteMainRequest(context, timeoutSource, timeoutTask)
);
}
}

How to get result from async Task<> when I cannot Run()? [duplicate]

This question already has answers here:
An async/await example that causes a deadlock
(5 answers)
Closed 5 years ago.
I'm trying to make a call to another API using POST methods through Asynctask.
Everything works fine (the request is correctly executed because it launches my SQL request) but I can't get any response from the external server.
I can see that I don't need to run the task to make it execute but I don't have any result.
[HttpPost]
public string Post([FromBody]JObject value)
{
if (MesureController.CheckJsonIntegrity<Mesure>(value))
{
var task = MesureAsync(value);
return task.Result;
}
return null;
}
static async Task<string> MesureAsync(JObject value)
{
using (client)
{
string url = ConfigurationManager.AppSettings["internalserver:url"];
var json_string = new Dictionary<string, string>
{
{"json_string", value.ToString() }
};
var content = new FormUrlEncodedContent(json_string);
var response = await client.PostAsync(url + "Mesure/Index", content);
string resultContent = await response.Content.ReadAsStringAsync();
return resultContent;
}
}
You're seeing a common deadlock that I describe in more detail on my blog. In summary, ASP.NET (full, not Core) code runs within a "request context" that only allows one thread to work on a request at a time. When MesureAsync sends the POST to the other API, it returns an incomplete task. Your Post method then blocks the current thread, waiting for that task. Later, when the POST to the other API completes, MeasureAsync attempts to resume executing within that same request context, but it can't because Post has blocked a thread within that request context, and the request context only allows one thread at a time.
So, you end up with Post taking up the request context waiting for MeasureAsync to complete, and MeasureAsync waiting for Post to give up the request context so that it can complete. Classic deadlock.
The best solution is to go "async all the way", i.e., don't block on async code. In this case, replace Result with await:
[HttpPost]
public string Post([FromBody]JObject value)
{
if (MesureController.CheckJsonIntegrity<Mesure>(value))
{
return await MesureAsync(value);
}
return null;
}
If you try to compile this now, it will give you a compiler error that tells you exactly what to do with Post to get it to work:
[HttpPost]
public async Task<string> Post([FromBody]JObject value)
{
if (MesureController.CheckJsonIntegrity<Mesure>(value))
{
return await MesureAsync(value);
}
return null;
}
...and you're done!
No result was return in the original code because of the mixing of blocking and async code.
The actions syntax should be updated to be async all the way and also to allow better content negotiation.
Assuming this code is for Asp.Net-Core, the actions would be updated to
[HttpPost]
public async Task<IActionResult> Post([FromBody]JObject value) {
if (MesureController.CheckJsonIntegrity<Mesure>(value)) {
var measure = await MesureAsync(value);
return Ok(measure);
}
return BadRequest();
}
If using WebAPI 2.* then change IActionResult to IHttpActionResult and it will work the same way.
You have to ensure Task will run.
Use this snippet:
Task.Run(()=>MesureAsync(value)).Result;

Using 'await' but still receiving this error: A second operation started... Use 'await' to ensure that

When the user session ends, a popup shows up in my application and when the user clicks "Stay in the system", the RefreshTheUserSession action of the Account controller is evoked.
public async Task<ActionResult> RefreshTheUserSession(string UserId)//this will be called from the ajax timeout
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ApplicationCookie);
var myuser = await UserManager.FindByIdAsync(UserId);
if (myuser != null)
{
await SignInManager.SignInAsync(myuser, false, false);
}
return null;
}
Here is the AuthenticationManager property of the Account controller that comes by default by MVC application.
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.GetOwinContext().Authentication;
}
}
However, when the RefreshTheUserSession action is executed, I receive the following error:
A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
It recommends me to use await and I am using await. I have no idea why this is happening. Any ideas or leads?

ASP.NET MVC workaround for ajax.abort()

I have a rest endpoint on asp.net mvc:
[HttpGet]
public List<SomeEntity> Get(){
// Lets imagine that this operation lasts for 1 minute
var someSlowOperationResult = SomeWhere.GetDataSlow();
return someSlowOperationResult;
}
On the frontEnd I have a next javascript:
var promise = $.get("/SomeEntities");
setTimeout(function(){promise.abort()}, 100);
How to force Thread to die after abort call, to prevent slow calculation to be done?
Thanks in advance.
I found that Response have isClientConnected property. So we can use next approach:
[HttpGet]
public List<SomeEntity> Get(){
var gotResult = false;
var result = new List<SomeEntity>();
var tokenSource2 = new CancellationTokenSource();
CancellationToken ct = tokenSource2.Token;
Task.Factory.StartNew(() =>
{
// Do something with cancelation token to break current operation
result = SomeWhere.GetSomethingReallySlow();
gotResult = true;
}, ct);
while (!gotResult)
{
if (!Response.IsClientConnected)
{
tokenSource2.Cancel();
return result;
}
Thread.Sleep(100);
}
return result;
}
Can we? Or I miss something?
UPDATE:
Yes, it works
The backend has no idea that you have called abort() and if the request has already been sent then the server-side logic will run until it completes. In order to stop it from running you will have to send another request to your controller which notifies that controller that you've aborted the request and the controller will have to access the instance that is currently running you slow operation and this instance should have a method which forces the calculations to cancel.

Asp MVC and Web Api Async Controllers

I was working with Asp MVC 3, and in my application was created Async controller with some methods like:
public void ActionAsync()
{
AsyncManager.OutstandingOperations.Increment();
AsyncManager.Parameters["someResult"] = GetSomeResult();
AsyncManager.OutstandingOperations.Decrement();
}
public JsonResult ActionCompleted(SometResultModel someResult)
{
return Json(someResult, JsonRequestBehavior.AllowGet);
}
And now, when I'm working with MVC4 and Web Api I need to create controller with async actions like in mvc 3. At current time it's looks like:
public Task<HttpResponseMessage> PostActionAsync()
{
return Task<HttpResponseMessage>.Factory.StartNew( () =>
{
var result = GetSomeResult();
return Request.CreateResponse(HttpStatusCode.Created, result);
});
}
Is it a good idea to make async actions in web api like this or there some better way is exist?
UPD. Also, if I will use
public async Task<HttpResponseMessage> ActionAsync()
{
var result = await GetSomeResult();
return Request.CreateResponse(HttpStatusCode.Created, result);
}
will this full action work in background thread? And how to make my GetSomeResult() function be awaitable? It's return that Task<HttpResponseMessage> is not awaitable.
There is a big difference with your original action in MVC 3 where you are basically releasing the client after the ActionAsync method is invoked (The client thread is released, and it has to call the ActionCompleted action afterward to get the results). If that's what you are looking for, you need to implement async code with tasks on the client side.
Your second version is to make the server code async but the client thread will still wait for a response synchronously. await GetResult will make the server thread to return to the ASP.NET thread pool until the GetResult method returns something, so that thread can be reused with another request. It does not have anything to do with background work. If you want to use a fire and forget approach, you need to use the Task.Factory.StartNew(() => your code) or ThreadPool.QueueUserWorkItem(() => your code)

Categories

Resources