Dimo
Dimo

Reputation: 3280

Storing value in Session in Thread in MVC

I'm pretty new to MVC so forgive me if I'm missing anything.

In one of my controllers, I initiate a class that does some processing and outputs a string like this:

[HttpPost]
public ActionResult Check(string reg)
{
    string sCarmodel;
    GetRegInfo gri = new GetRegInfo(reg, out sCarmodel);
    Session["test"] = sCarmodel;

    return View("Check");
}

So far so good, and the output of sCarmodel is correctly stored in Session where it can be accessed later in the View. However, I need to put the class in a separate thread, since it takes some time to finish it and I want to return the View aschyncronosly. So I tried this:

[HttpPost]
public ActionResult Check(string reg)
{
    var getreginfoThread = new Thread(
        () =>
        {
            string sCarmodel;
            GetRegInfo gri = new GetRegInfo(reg, out sCarmodel);
            Session["test"] = sCarmodel;
        }
        );

    getreginfoThread.Start();

    return View("Check");
}

I know that I can store the value of "sCarmodel" in a database from within the class itself, but I was looking for a way to skip using a database. Using a thread, the value of sCarmodel is not stored in Session, and the Session is null later when I try to retrieve it.

Can anybody offer some advice on how I can access a value from a Class while in a thread?

Thanks!

Edit: Problem solved, thanks everybody for their suggestions!

Upvotes: 3

Views: 5247

Answers (7)

Stephen Cleary
Stephen Cleary

Reputation: 456527

However, I need to put the class in a separate thread, since it takes some time to finish it and I want to return the View aschyncronosly.

Wrong. This is the completely wrong way to solve this problem. In an ASP.NET application, you should never return when there is more work to do unless you have already saved that work to persistent storage.

Keeping the work in memory (i.e., with a thread or task) is an incorrect solution.

The correct solution is to use persistent storage (e.g., Azure Queue, MSMQ, or WebSphere MQ) to store the work to be done and then have a separate service which reads that queue, takes the appropriate action, and stores the results in another persistent data structure. You can then have the client poll (e.g., HTTP request) the "result" data structure and/or notify the client (e.g., SignalR) when the result is saved.

I go into more details on my blog, and also have some example code to use there if you are absolutely sure that you want to take the unsafe route.

Upvotes: 0

Dimo
Dimo

Reputation: 3280

I have solved my problem by storing an instance of the class in TempData. Also, instead of Thread, I use Task which is much better. Here is my solution:

[HttpPost]
        public ActionResult GetRegInfo(string reg)
        {
            var gri = new GetRegInfo(reg);
            TempData["GetRegInfo"] = gri;

            Action<object> action = (object obj) => gri.Start();
            var t1 = new Task(action, "GetRegInfo");   
            t1.Start();

            return View("bilforsakring");
        }

Later I use a JavaScript timer with Ajax and get the value like this:

[OutputCache(NoStore = true, Duration = 0)]
        public ActionResult GetRegInfoAjax()
        {
            if (TempData["GetRegInfo"] != null)
            {
                var g = (GetRegInfo)TempData["GetRegInfo"];  
                return Content(g.sCarmodel);
            }
            else
            {
                return Content("null");
            }
        }

Upvotes: 0

Alexey Raga
Alexey Raga

Reputation: 7525

I would advice you not to use Session object in threads as it is not thread safe. In ASP.NET each request has its own thread and its own session.

You never described a real problem (unfortunately) so I don't really know what you are trying to solve, but spinning up a new thread manually and putting data in Session is not a solution anyway.

If you want to do things asynchronously to let the web server serve other clients while doing something in background, then look perhaps at the asynchronous controllers: http://www.asp.net/mvc/tutorials/mvc-4/using-asynchronous-methods-in-aspnet-mvc-4

Again, it would be really useful to know what is it you try to achieve to suggest a proper solution.

Upvotes: 0

to StackOverflow
to StackOverflow

Reputation: 124706

Put an custom object in Session during processing of a request.

Pass a reference to this custom object to the background thread.

Set a property of the custom object in your background thread.

Make sure you do any necessary synchronization.

Upvotes: 4

ghord
ghord

Reputation: 13807

It's not that the value is not stored in Session. It is. The problem is your code continues execution in parallel to the thread your created, and when it is accessing the Session["test"] it is not yet assigned by your thread. You have to reorganize your code somehow. Also, it is not recomended to launch threads in asp.net application, as it is very resource intensive.

EDIT

It seems that it really doesnt set the Session variable. If you really want to do it this way, you can use CallContext for that:

CallContext.LogicalSetData("CurrentSession", Session);

var getreginfoThread = new Thread(
    () =>
    {
        string sCarmodel;
        GetRegInfo gri = new GetRegInfo(reg, out sCarmodel);
        var session = (HttpSessionState)CallContext.LogicalGetData("CurrentSession");

        session["test"] = sCarmodel;
    }
    );

getreginfoThread.Start();

return View("Check");

You would have to somehow wait for this data not to be null and then get it using Session["test"]

Upvotes: 0

Tamim Al Manaseer
Tamim Al Manaseer

Reputation: 3724

HttpContext the parent/owner object of Session object is not transported to new threads, therefore your Session is not accessible in threads other than the main one.

I suggest that you return sCarmodel from your thread using async/await and set it to your Session in the main thread.

Upvotes: 0

zmbq
zmbq

Reputation: 39013

You need to somehow pass the session to the background thread. See here for example.

By the way, why aren't you using the Task Parallel Library?

Upvotes: 1

Related Questions