Question

Here is the scenario-

I have a form that uploads a file to a Action via Ajax POST. Once the file is uploaded it is processed and the data is inserted into a database. This can take some time so I would like to be able to send messages back to the user letting the user know at what step in the process the file is at. Basically what I have right now is:

[HttpPost]
public void UploadAndProcessFile()
{
   Session["UserMessage"] = "Start";
   // Do some stuff
   Session["UserMessage"] = "25% done";
   // Do some stuff
   Session["UserMessage"] = "50% done";
   // Do some stuff
   Session["UserMessage"] = "75% done";
   // Do some stuff
   Session["UserMessage"] = "Completed!";
}

[HttpGet]
putlic JsonResults GetFileProcessStatus()
{
  string returnMessage = (Session["UserMessage"] ?? "");
  return Json(returnMessage, JsonRequestBehavior.AllowGet);
}

On the client side I post the form via ajax to the UploadAndProcessFile Action and then have a function that continually does an ajax get request to GetFileProcessStatus. The problem is that when I do the ajax get reqeust to GetFileProcessStatus the Session["UserMessage"] is always null. I have also tried TempData instead of the Session with the same results. From what I understand about Session, what I am trying to accomplish here is not doable because the precedence for Session is given to the first caller. In my case the first caller would be UploadAndProcessFile. I hope this make sense and that someone can help!

Thanks - JD

Was it helpful?

Solution

class ParameterForMyProcess
    {
        public string criteria { get; set; }
        public Guid processID { get; set; }
        public HttpContext context { get; set; }
    }

    private Guid StartProcess(string criteria)
    {
        // we will use this id later to get status updates on this specific process.
        var processID = Guid.NewGuid();

        // the thread we are starting can only take one parameter,
        // so we create a container for all the data we might want to use
        // and pass that in as the single parameter into the process.

        var parameter = new ParameterForMyProcess()
            {
                criteria = criteria,
                processID = processID,
                context = System.Web.HttpContext.Current
            };

        var thread = new System.Threading.Thread(
            new System.Threading.ParameterizedThreadStart(CreateProcess));

        thread.Start(parameter);
        return processID;
    }

private void CreateProcess(object parameter)
    {
        // cast the object to our parameter type
        var myParameter = parameter as ParameterForMyProcess;

        // you now have access to some data if you wish
        var criteria = myParameter.criteria;

        // process ID to report progress with
        var processID = myParameter.processID;

        System.Web.HttpContext.Current = myParameter.context;

        // Do something

        updateStatus(processID, "Hello World");
     }

     private void updateStatus(Guid processID, string status)
    {
        // store the status in the http cache.  

        var key = "CreateProcess:" + processID.ToString();
        var cache = System.Web.HttpContext.Current.Cache;
        var oldStatus = cache[key];
        var newStatus = oldStatus + "<br/>" + status;
        cache[key] = newStatus;

        // this implementation relies on the browser to trigger an action which will clean up this data from the cache.
        // there is no guarantee this will be triggered (user closes browser, etc), 
        // but since the cache has means for eventually removing this data, this isn't a big risk.
    }

    public JsonResult GetProcessStatus(string processID)
    {
        var status = System.Web.HttpContext.Current.Cache["CreateProcess:" + processID.ToString()];
        return Json(new { status = status });
    }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top