How can I keep some values between different Views in MVC 3?
I tried using TempData and HiddenField to keep these values but in our hosting this tecnique seems to have short life so exceptions are coming out furthermore if user uses Back button every starts to fail.
I would like to understand the better way to keep values between views in MVC 3, thanks in advice!
By design, MVC3 TempData values are removed after they are used.
The most simple answer is to use the Session object directly in your controllers.
There are other related questions with detailed answers such as these:
Session variables in ASP.NET MVC
Asp.Net MVC and Session
Your question is about the lifecycle of objects in between requests. It's important to understand that webapplications are used over the HTTP(S) protocol which is a stateless protocol. This means that every request is a completely new request for the webserver and there's no state shared between requests.
However it would be foolish to send the credentials of a user to the server each and every time so a webserver can create a thing they call a Session (and session-state). This object is an object that remains available for the lifetime of the session of the current user (most of the times from logging in until logging out). You can use this object to store items that you wish to share over various requests of the same user.
If the values you're trying to keep are specific to the page you can probably use a hidden field or something like that. However if the data is more related to the user than to a specific page and it must have a lifecycle longer than a single request then sessionstate is the best place to store the data.
You could use the Session (as you mention in your title and tags). Or store a cookie on the user's machine
Related
I am building an ASP.NET application using nhibernate and I implemented the session per request architecture. Each request I am opening a session, using it, then closing it. I am using one large object across several views and I am storing the object in user session cache so it maintains state for them across several different pages. The users do not want to have to save their changes on each page, they want the ability to navigate between several pages making changes, then commit them to the DB. This works well except for when the users try to hit a page that triggers lazy loading on the proxy object (which fails due to the session per request design closing the nhibernate session in the previous request). I know that turning lazy loading off would fix it; however, that is not an option due to the performance issues it would cause in other areas. I have tried changing the session per request design but have had no luck since I do not know when it is "safe" to close the nhibernate session.
Has anyone else done anything similar to this or have any advice?
Thanks in advance!
Keeping any objects in user session - the server session, server resource is not the best approach. Just imagine, that accidently your application will be very very successful... and there will be many users... therefore many sessions == many resources.
I would suggest (based on some experience), try to re-think the architecture to avoid session. Extreme would be to go to single page application... but even some async during "...navigation among several pages..." will be better.
All that will mean, that:
we passs data to client (standard ASP.NET MVC way with rendered views or some Web Api JSON)
if needed we send data back to server (binding of forms or formatting JSON)
In these scenarios, standard NHiberante session will work. Why? Because we "reload and reassign" objects with standard NHibernat infrastructure. That would be the way I suggest to go...
But if you want to follow your way, then definitely check the merge functionality of NHibernate:
9.4.2. Updating detached objects
9.4.3. Reattaching detached objects
19.1.4. Initializing collections and proxies
Some cites:
In an application with a separate business tier, the business logic must "prepare" all collections that will be needed by the web tier before returning. This means that the business tier should load all the data and return all the data already initialized to the presentation/web tier that is required for a particular use case. Usually, the application calls NHibernateUtil.Initialize() for each collection that will be needed in the web tier (this call must occur before the session is closed) or retrieves the collection eagerly using a NHibernate query with a FETCH clause or a FetchMode.Join in ICriteria. This is usually easier if you adopt the Command pattern instead of a Session Facade.
You may also attach a previously loaded object to a new ISession with Merge() or Lock() before accessing uninitialized collections (or other proxies). No, NHibernate does not, and certainly should not do this automatically, since it would introduce ad hoc transaction semantics!
All:
I have been searching high and low for an answer to this, so forgive me if this is a dupe, I just can't seem to find the right answer.
Let's say you have an ASP.NET MVC Controller marked with the [SessionState(SessionStateBehavior.Disabled)]
attribute. Does calling actions on this controller "refresh" the session state, keeping it "alive"? Specifically, I have a AJAX request calling a controller to keep the session "alive" since the application is a single page application driven by javascript, and I don't want the users session to die, so every 30 seconds I make a call up to this controller. Similarly, would it stay alive if the controller was marked SessionStateBehavior.ReadOnly? Finally, is using an ASP.NET MVC Controller for this purpose not the best way (is there a better way)?
Thanks!
Session state will be kept alive automatically with no attributes on the action, depending on how the web.config is configured. To configure it, see here: http://msdn.microsoft.com/en-us/library/h6bb9cz9(v=vs.100).aspx
A controller should be okay, but you may want to look into Web API as it'll offer a few more features in this scenario: http://www.asp.net/web-api/overview/getting-started-with-aspnet-web-api/tutorial-your-first-web-api
i've a question regarding handling of user logon while porting an application to MVC:
in the "old" WebForm days, developers simply used the SessionState object to set a user to logged-on, by -for example- simply putting the userobject into the SessionState (and this userobject holds simple properties like name/lastlogon/etc.)
this stuff worked very well for us, and i've seen lots of applications doing it that way
yes, i know there is this MembershipProvide-thingy, but i've never used it
Now, in MVC, everybody tells me that "using SessionStat for this is bad" and "apps built that way are flawed in design" and that "there are tons of security risks" and so on.
I've used this method because it worked for the app very reliable, it was simple to implement and it covered all stuff we need.
(Sure, there is the thing with recycling web worker process and emptying the session - but thats not a problem in our case, since the app runs for each country on a dedicated machine)
I've read tutorials, telling me to put that stuff in the DB and -attention- doing a request to the DB to check if the user is logged in, per EACH request? But: Under no circumstances, this is a doable way since i want to keep DB requests on a minimum.
So my question is:
A) whats wrong using this way also in the new MVC app?
B) whats the best way to handle this scenario in a newly built MVC app?
Regarding the session-in-DB-idea: instead of doing this, i'd rater setup an additional service, like a "session-manager" thats get query over the network, but such simple requests should not go to the DB - isn't that a good idea?
Any idea, hint /etc. is highly appreciated since this scenario is really confusing me :-X
A)
A fundamental principal of the asp.net mvc framework is that its stateless. Data is passed around using http requests and sent to the views in viewmodels. Web forms tried to maintain state with viewstate etc thats why you would have seen the logged in user in session approach. Thats not to say session shouldnt be used completely in asp.net mvc, there are some circumstances when it can be useful. Like maintaining a 3 step form process that has to be persisted on the last step. But generally we already have a recommended way to handle the user logins, and thats forms authentication
B)
For accessing the user object, you can create a custom identity implementing the IPrincipal interface and add the required user fields you need. Then set the custom identity in a global filter and access it in your action results. Regarding not wanting to query the database for every request, why dont you just call it for the initial request, then cache the result until the user is updated where you then can reload the object and set it in the custom identity again.
I am using the TempData in order to preserve my model in when using a RedirectToAction. It works fine, but I have a nagging feeling that it might not be the right thing to do. I really try to avoid using Session data, and I've read that TempData uses the Session. Is it safe to use? Are there issues which might arise in using it in a load balanced environment?
Trivia Question: "Is It Safe?"-- name the movie.
Yes, TempData is backed by session storage, so if you are in a load balanced environment extra care must be taken when using it (sticky sessions, persistent session state, etc).
TempData has been the de-facto choice when using the PRG pattern, and is what it was designed for.
As to whether it's the right thing to do... it depends on your use case!
PS Marathon Man.
Well, I would argue that it depends. If you handle lot of traffic with load balancers and multiple front end server, then session objects is something to avoid because it could degrade performance and make hotizontal scaling difficult (on farm request doesn't come always to same web server).
TempData is short-lived, and if you don't put there lot of objects there and think twice about whole architecture, I think then it's safe. There's lot of sites that use it extensively and don't have problems with it (I worked on shared and dedicated hosted sites with up to avarage 50-70k visitors/day that use session, often with web and db on same server).
I would go, whenever possible, for a fully stateless approach. It's more scalable and is not affected by problems with individual servers. Typically, you can just use a cookie (properly secured against tampering) to identify the user and pull the data from the database every time.
Besides that, I also suggest you to evaluate whether you can use View instead of RedirectToAction. This:
TempData["model"] = model;
return RedirectToAction("SomeAction");
Can be replaced with:
return View("SomeAction", model);
Of course assuming "SomeAction" is a valid view that is accessible from the current controller (it's either a view in the same ctrl or one defined in Shared) and that it's not just an intermediate action that redirects to another one.
Session state can work in a clustered environment, providing that one of two things happens
Your load balancer supports "sticky" sessions (i.e. all requests in a given session are routed to the same machine)
You configure the session provider to use an out of process session provider, you can use either the ASP.NET State Service or the SQL Session State Provider
The question of whether you should use tempdata or not is a different question altogether. I would argue that there is usually a way around it. If you are trying to avoid a hit to the database to reload an object that one action has already loaded, look at using a cache instead.
I have limited the use of TempData to pass model object validation message between views and action. I haven't looked into the usage of Tempdata from security perspective but following SO thread discuss the same : HttpContext.Items with ASP.NET MVC. See the last few thread comments and related discussions.
I'm developing an ASP.NET MVC 2 application that connects to some services to do data retrieval and update. The services require that I provide the original entity along with the updated entity when updating data. This is so it can do change tracking and optimistic concurrency. The services cannot be changed.
My problem is that I need to somehow store the original entity between postbacks. In WebForms, I would have used ViewState, but from what I have read, that is out for MVC. The original values do not have to be tamper proof as the services treat them as untrusted. The entities would be (max) 1k and it is an intranet app.
The options I have come up are:
Session - Ruled out - Store the entity in the Session, but I don't like this idea as there are no plans to share session between
URL - Ruled out - Data is too big
HiddenField - Store the serialized entity in a hidden field, perhaps with encryption/encoding
HiddenVersion - The entities have a (SQL) version field on them, which I could put into a hidden field. Then on a save I get "original" entity from the services and compare the versions, doing my own optimistic concurrency.
Cookies - Like 3 or 4, but using a cookie instead of a hidden field
I'm leaning towards option 4, although 3 would be simpler. Are these valid options or am I going down the wrong track? Is there a better way of doing this?
If you do Store it in a session then you need to ensure that if you implement a web farm that the session is loaded correctly.
We have (exactly) the same question here at the moment and what we've decided to do is to implement the Repository Pattern and link it to a cookie.
Then, if this becomes an issue, we can simply slot in either a session manager, db manager or whatever and our code need not even know because of the repository pattern.
We tinkered with the idea of hidden fields but it felt too much like ViewState and we all hated it in WebForms so the idea was scrapped. But not just because we hated view state. There were issues when you pressed Ctrl F5. The contents would be cleared and then what do you do?
So at this point its a repository pattern with a cookie which may change but the implementation lends itself kindly to change.
EDIT
We also decided against hidden fields because it would be too easy to make changes to them and so you need to do some token stuff from the server to ensure it wans't tampered with.
The hidden fields just kept on adding complexity to what essentially should have been a very simple problem.
At least that was our thoughts on the matter.
I am not quite sure why Session is a bad idea, if the client dose not need that backup copy, keeping the whole thing in server memory sounds the best; since the rest of the candidates are all sending from server to place (temporary) in clients' browser, and then get it back whenever client does any action. Situation is, whenever client ping back, server will unpack the encoded data (either in hidden field, cookie, url etc) and would possibly place in server again! It also waste bandwidth IMO.
OK, if client need (to inspect) the backup, I would consider hidden field(set) or simply serialize the data in XML and put it somewhere in the HTML.
EDIT
I still vote for Session. If you plan to take care the server farm, consider implement a cross server session provider:
http://msdn.microsoft.com/en-us/library/ms178587%28VS.80%29.aspx
and simply store the state in database.