besides TempData, which I believe isn't the best thing to use nowdays, what are some best practices in how you can persist user data from page to page?
Do you usually just go back to the DB every time...ajax or not...do you make a request every time or do you store it in lets say the Request object or some other in process object instance?
I'm just looking for a broad range of ideas as I am overwhelmed with looking this up on the net...there's a LOT out there and it would be easier for me to get some insight via stack as well.
There are several options. If we're talking about intrarequest, then of course ViewBag is the best choice. Intrapage (across requests) then the best choice is probably hidden fields, unless it's sensitive data.
Between pages, then there are several options. You can of course pass data as query string parameters. Session also makes a convenient option, so long as the data size is small, and it's ok if the session gets lost (ie, you can get it again or regenerate it). In certain other situations, you can post data to another page using hidden fields, but this should largely be discouraged since you should prefer to use PRG (Post/Redirect/Get) pattern.
Some other options are using the context cache HttpContext.Cache (Which i feel is misnamed, but oh well) or saving it in temporary tables in the database. Any "in-memory" option will have scalability issues if you decide to move to a web farm (Session can be made to be backed by database, but it slows things down).
It also depends on what data you're talking about. If it's user data, then another option is to store it in a cookie, or to use the user data portion of the Forms Authentication cookie, and create a custom IIdentity object.
Finally, there's just rebuilding the data from its source on every request.
Related
In my current project, I am building an object list from multiple database tables. I am currently storing them in the user session (Global.asax/Session_Start) as showed below.
protected void Session_Start()
{
Session.Add("listeOF", new ListOf());
}
This is working and I can use the data, but I was wondering if there's a better way to store it (by better I mean faster access). I call this data in my controllers.
You need some other data store to keep it across postback requests, so if it's global to the application, you can use application cache, but if it's specific to the user, then session is fine. If there isn't that much data involved and it's not that intensive as a read, you may want to consider whether there is a benefit to caching a chunk of data vs just re-querying it when needed.
To get more advanced and present another alternative that is more involved, a CQRS implementation is a possibility (also see this); the idea there is one data container is for transaction data, and another for reads (whether that is a separate database or table, or even a document database as some possibilities).
I have an existing web-forms website that runs on a web-farm (multiple web servers, each request is NON-sticky).
One of the tasks is to retrieve a lot of data from a 3rd party webservice. This is an expensive process (in terms of time taken to respond). The optimal solution has been to initially grab all the data and stick it in the page's ViewState (as a List<Product>. We then have a grid that allows us to page through this list of products. For each request for the next page we don't have to re-visit the slow web service because we've already cached the data in the ViewState.
So, how would I accomplish this using MVC? If I were using classic ASP, I would serialize the list and hold it in a hidden field in the form.
But what is the preferred approach when using MVC? As mentioned, I'm using non-sticky sessions so can't rely upon caching on the server.
If I am to hold it in a hidden-field, then is it sensible to compress the data first (zip) to reduce the size of the page? Again, what's "best practice" here?
Many thanks for any/all advice
Griff
PS - I know there are similar posts out there (e.g. ASP.NET MVC and ViewState), but they don't quite provide the detail I require.
Caching, in my humble opinion, is the best way to deal with this; hit the webservice, cache the data, and use that for each subsequent request.
It is possible to share a cache across many web servers. The default behaviour is to hold it InProcess, but this is by no means fixed and can be configured to store it in a remote InProc cache, a database, or any other method of semi-persistant storage. AzureAppFabric caching comes to mind.
Second to that, as you mentioned is to dump all the data in a hidden field, but I dont like this idea for a number of reasons
Page bloat - you're submitting this data every time the page is changed
Lost data - you must submit a form for every navigation, forgetting to do this means loosing your data
To name 2.
Your strategy should depend on how volatile the data retrieved from the 3rd party service is going to be and how expensive it is to call it.
Volatile and expensive. I would go down the road of caching the data in a distributed cache such as Appfabric Velocity, or Memcached.
Non-Volatile and expensive. Cache a copy of it in memory on each server node.
Cheap. Hit the call every time you need it. Don't bother caching.
If the data set returned from the service is large, I would not pass this up and down every time you page through your grid data. Only retrieve the data for the current page and render it in your grid. Telerik have a good implementation for this or you could try and roll your own.
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.
This sounds like a contradiction in terms, or flamebait, but I'm hoping its not actually.
Background:
I need to maintain a few preferences across the entirety of a user's log in. These preferences mostly affect how something is viewed, although they may be passed to the controller layer to accomplish this. At no time should any of these user/session preferences affect data directly.
Question:
How do I temporarily store data across pages/controllers in an MVC setting, so that the controllers can use it (not depend on it) when convenient.
I am thinking session but searches on session and asp.net MVC turn up lots of material on tempdata, which is not what I need. Rather a dictionary per user session of non-essential data would be ideal.
Thanks
Adam
Option 1. You store it on the client-side. Put these settings in cookies, they will be available at each following request.
Option 2. You store it server-side. Put it in session but bind it to user id, it can also be easily accessed.
Option 3. You store it in database. Consequently, load these settings from the db on each request. Alternatively, cache it.
I don't believe there's any good reason not to use session. I'd be tempted to say that the moment something is required across pages then it's no longer 'temporary'.
You could use MS's distributed cache velocity, backed by a database table if necessary. Maintaining your settings this way only requires some extra memory, and shouldn't bog down your server with extra requests. The settings will also expire when they haven't been used recently, or when enough new settings are placed in the cache.
There is also a session provider within velocity which may do what you want.
Using the Session object on the controller/viewpage is probably what you want to do. Normally, what I would do is persist the user choices to a database (preferences table), then use the Session as a cache for the user's Preferences object. I often make this a property on a base controller that is lazy-loaded from the Session, if it exists, or the database, populating the Session as needed.