1

I am creating an ASP.NET MVC 5 Web site, where I have one operation, which requires a lot of time to be executed(importing e-mails from exchange with EWS2.0 Managed API). The problem is when a client triggers Import action method, the whole site is blocking and no one can open /Home/Index for example or can't make any request to the server, after while exception is throwed(Timeout) if no one interracts with site during the import process - import is successful otherwise it is not guaranteed because of the timeout exception. How can I manage to start Importing and then redirect users to /home/index and continue importing on server side..? Here is what I've tried:

public ActionResult Exchange(DateTime? id)
    {
        string url = ....;

        try
        {
            ExchangeToDatabase etd = new ExchangeToDatabase(username, password, domain, url, id);
            etd.ExportFromExchange();
        }
        catch (InvalidDateException ex)
        {
            return RedirectToAction("Display", "Error", new { returnUrl = "/", Message = ex.Message });
        }

And tried with threads also:

        /*System.Threading.Tasks.Task.Factory.StartNew(() =>
        {
            ExchangeToDatabase etd = new ExchangeToDatabase("cbstest", "ch@rteRsmarter", "vlaeynatie", url, id);
            etd.ExportFromExchange();
        });

or: doesn't work..

        new Thread(() =>
        {
            ExchangeToDatabase etd = new ExchangeToDatabase("cbstest", "ch@rteRsmarter", "vlaeynatie", url, id);
            etd.ExportFromExchange();
        }).Start();*/

        return Redirect("/");
    }
M.Veli
  • 519
  • 1
  • 6
  • 15
  • 2
    Have you heard of `async` controllers?? – Ehsan Sajjad Mar 04 '15 at 14:22
  • I forgot to mention it is also not helped.. or maybe I've missunderstood the usage of them.. etd.ExportFromExchange() is with return type of void.. but in all async controller examples they use some kind of async return result.. but I do not have something to return to clients.. Just want to finish te importing, no need of informing them, clients already know that.. – M.Veli Mar 04 '15 at 14:25
  • Want you start an import and redirect user to /Home/Index immediately? Is it correct? – Mark Shevchenko Mar 04 '15 at 14:28
  • Yes, but also continue importing(on the server) – M.Veli Mar 04 '15 at 14:29
  • Effectively you need to either trigger the import from an asynchronous JS call (hit the controller / action from a client side javascript button) or you need to create a `async` method with a `void` return type. – THBBFT Mar 04 '15 at 14:38
  • I am already using javascript to trigger the import, just the action doesn't immidiatly returms.. Also in the below answer have a some kind of proggress for solving the issue.. – M.Veli Mar 04 '15 at 14:41
  • @EhsanSajjad: Async doesn't help in this scenario. It doesn't make the controller action return quicker; it merely allows the thread to be returned to the pool to field other requests while the action is waiting to finish. – Chris Pratt Mar 04 '15 at 15:14
  • 2
    @M.Veli: A web application is designed to return a response quickly and move on. They are particularly unsuited to long-running tasks like what you describe here. Instead, you should off-load it to a background process and let your server return the response immediately. See: http://www.hanselman.com/blog/HowToRunBackgroundTasksInASPNET.aspx – Chris Pratt Mar 04 '15 at 15:19
  • Also I am wondering why after some long task have been initiated, the client couldn't browse the rest of the web site..? He should be able to do that according to Microsoft's documentations.. – M.Veli Mar 05 '15 at 07:30

2 Answers2

3

After days of research and trying whatever possible to prevent blocking of the UI, I found an answer: make the user session readonly. An answer from @SamStephens in this post gave me the result that I want. Here it is:

[SessionState(SessionStateBehavior.ReadOnly)]
Community
  • 1
  • 1
M.Veli
  • 519
  • 1
  • 6
  • 15
  • this helped me for another issue, but i think in your case you should look in to something like signal R, – CMS Jul 28 '16 at 12:39
2

I've done this recently for a project and I used Task.Run()

Task.Run(() => SomeMethod(someVariable));
ediblecode
  • 11,701
  • 19
  • 68
  • 116
  • I receive from Intellisense: async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread. – M.Veli Mar 04 '15 at 14:28
  • @M.Veli with async in method definition you have to use await on method call which takes time – Ehsan Sajjad Mar 04 '15 at 14:31
  • @M.Veli Apologies, it's where I copied my code which calls `async` methods – ediblecode Mar 04 '15 at 14:33
  • This partially resolves problem, because of I'm using NHibernate, to store data in DB, it now throws exception: NHibernate session is not available. – M.Veli Mar 04 '15 at 14:39
  • @M.Veli That's a separate question – ediblecode Mar 04 '15 at 14:40
  • I know, but any thoughts how to resolve it, cuz from what I know NHibernate session is not a thread safe... – M.Veli Mar 04 '15 at 14:42
  • @M.Veli In mine, I'm using `EntityFramework` and I initialise a new `ApplicationDbContext` within `SomeMethod` – ediblecode Mar 04 '15 at 14:43