Persist List of Objects Between Pages - ASP MVC - c#

C# - ASP MVC - .NET 4.5 - Bootstrap - Razor
I have a form wizard (http://vadimg.com/twitter-bootstrap-wizard-example/examples/basic.html) that is used to setup a complex object (obj1). A property of obj1 is a List<obj2>. On one step of the wizard I want to add multiple obj2's to the list. Since obj2 is slightly complex as well, I thought I would use another wizard to help build it. Except I need to persist this List<obj2> on wizard 1, while I'm off in wizard 2 building another obj2.
My first thought was to use a session to hold the List<obj2>, I was just wondering if that's a good option, or if there would be a better one? The user may leave from Wizard1 to go to Wizard2 and come back multiple times.

There's no perfect answer here; each approach has trade-offs. But here are some options that I can think of (and these are independent of ASP.NET/C#)
Session (as you suggest)
This will store data in web server memory (by default). If you have a lot of users, this could be a problem.
You risk the information being lost when the user gets a new cookie/the session times out.
Potentially better performance that a db, depending again on the number of users
Database (as you mentioned)
Could cause more database traffic.
Can save information for user even if they close a browser, switch computer, the power goes out, etc.
Maybe a separate NoSQL database just for transient wizard data would be worth trying.
Cookie (store data on the user's computer)
Users can potentially tamper with/view the data
There is a limit on cookie size (4 KB each?)
Local storage (HTML5)
Similar to cookies
But not such a small limit
Not every browser supports it (may need polyfill)
Form/Post/Hidden/ViewState
You could just post the data and drag the information from response to response
But this gets really annoying with back buttons & timeouts
Lots of work, and again, the user can tamper with the information

Related

How to handle multiple sessions for same website using same browser with different tabs. ASP.net C#

How to handle multiple sessions for same website using same browser with different tabs. ASP.net C#.
example like google if we open 2 account in same browser it will not effect user details.
All the tabs in a browser share the same session(i.e. identifies to the web server as the same user), this is the default behavior. There are use cases where you would like each tab to connect to the same webserver as different user, this need to be handled via your web application by adding some specific info to the query string in your URL, or hidden form fields, etc., ASP.NET provides cookieless sessions, that can be used for this scenario, see this documentation.
There are other blogs with examples out there that you can follow. One such is this one - shows using a GUID in url route to differentiate different user, and solution to use unique window name and post it back to server using hidden form fields.
Well, as noted, session() is global to the user. In fact, they can launch two different browsers, say FireFox, and Edge - and they will BOTH continue to use the same session values!
What this REALLY means is that from day one, your designs HAVE to make this assumption. If you don't make this simple assumption, then you can be in for a world of BIG hurt if you "just out of the blue" wrote code without the above concept in mind.
In other words, for global things, then session() is fine. However, if you start writing BOATLOADS of code based on using session() to persist values on a SINGLE page? DON'T!!!
And it takes a few seconds in 99% of cases to flip code from session[] to ViewState[] for a given page.
So, now then the ONLY issue is when we use session[] to pass values around from page to page.
Using session() for passing values is ok, but NOT for such information like PK row values such as booking a hotel room, or say selecting a house to buy.
However, like a lot of people, the problem is we don't really think about this issue, or don't know about this issue until it is too late.
So, this is a problem. You want the "easy" of session(), but we need a way to pass around values from page to page.
As noted, one way is to pass values around using parameters in the URL. But then again, that's rather ugly. Sure, for some things like to filter a grid by a given city, then that can be really nice, since then users can save such a URL, or often modify the URL to their liking.
However, for a simple pick of a house or say a hotel room to book, then you can't of course allow or risk doing that (since you would be exposing primary row keys and selection in plain view. Worse yet, it can be a huge security risk. (some very early credit card and other types of sites would actually let you type in values that would let you get and see OTHER USERS information!!!
So, here is how you can handle this issue:
First up, we have these simple choices:
Parameters in URL - they are ugly, high risk, but GREAT for things like city filters etc.
Session() - this is global to the user - includes separate browsers launched.
ViewState - this is per web page - ideal for what we need, and PER PAGE!!!
HiddenFields (in markup) - again, per page - ideal for what we need, but PER PAGE!!!
So, in regards the per page options, only URL parameters can work for passing.
(sans the session() option).
ViewState is great for per page, but you can't use ViewState for passing values between pages. Keep in mind that viewstate is client side, and while encrypted?
Well, for not super high security, then it ok to use. Just remember, ViewState should be kept small, since it goes with EACH button click and PostBack, ViewState becomes part of that "package" and post.
ViewState is part of the page post-back. This is certainly ok, and even better then hidden fields which appear in plain view client side. Just keep in mind ViewState increases the size of each and every post back for a page. So, keep it light, small, and don't persist LARGE amounts of data like say some large dataset.
(unlike Session() which is 100% server side).
So, we need:
Easy approach - per page, but NOT have to re-write a lot of code.
So, while you could say munge up the URL, then they start to look really ugly, and while that might get you a session for the given page, your session() code has to be changed - and it gets messy.
so, just limit using session() to pass values, but NOT persist per page - and you then quite much home free.
In effect? I am saying NEVER use Session to persist values in a page unless you have no other reasonable choice. (use ViewState).
The other issue? What good is to suggest some approach in which you have to re-write a boatload of existing code?
I find that even a page with quite a bit of Session() stuff can in less then a minute be changed over to use ViewState. In fact, you can in most cases use search + replace Session to Viewstate.
So, the only issue left is now the passing of values from page to page.
Use session freely to pass values to the next page. However, for any values that are say PK values, or row identification values, or values that will "break" or "damage" the operations of that page if MORE then one page were to be open? Then simple transfer the values in session to next page AND THEN ALWAYS on FIRST PAGE load (IsPostBack = false), you simple transfer the values to ViewState.
This works really nice, and is BOATLOADS of less work then trying to adopt some silly parameter in the URL or what ever other junk people propose. In other words, we want the LEAST DAMAGE to existing code.
And also, because session() is global? Then it starts to get REALLY messy. I want to say pass 4 values to the next page. And then on that page I might have some more values - all of sudden, while writing code, you can't even remember what session() name to use - and it piles up into a BIG MESS REALLY fast. You wind up with a boatload of session values - ever more growing in your application. It just a mess, and global values tend to be a HUGE mess in any applcation - including that of using session().
And, often, 4-5 values are for the SPECIFIC page - so do NOT create 4-5 session() values, but add a typedef or simple class to the project. And use that for passing of the values. It MUCH LESS clutter in session(), and as you about to see, it also MUCH nicer for transferring these values to Viewstate.
So, we now have this:
we adopt and use View Sate for each page.
we ONLY use session to pass values to next page.
Lets give a simple example.
We say have a grid of hotels - you pick one. As noted, for buying things, picking hotel etc, then passing that value with session is OK AS LONG as you adopt the above rule (that we transfer values to Viewstate in the target page).
The goal here is to allow multiple working tabs or copies of the browser running, and of course minimal code changes.
So, say we have a GridView, and a Hotel to book.
So, note the values we pass (hotel ID, room type, nightly rate).
As noted, we then navigate to the next page (probably additional room details, etc.) - confirm booking etc.
But, as we noted, we can't use session() anymore, since they might have two browsers open. Heck they might have the page open on both their desktop and their smartphone.
So, when we land on the 2nd page, if two pages land using session, we in huge trouble? No, not with our above approach.
So we can still use session() to pass values, BUT we do NOT persist values on that target page. In other words, we break down the two issues:
a) - we using session() to pass values to the next page
b) - we now are NOT using session() to persist values on CURRENT page <<--- this we fix!!!
So, by making our goal here CRYSTAL CLEAR then you as a developer can deal with the above with a SIMPLE change to your existing code. As I stated, you the developer have to code, build, and design your web pages with the above concepts in mind.
So, for persisting values on a given page, just start using ViewState in place of session() - such code will work un-changed in most cases, and all and any values you save ONLY BELONG to the current page.
Only major difference is a user refresh of the page can re-set the ViewState for that page (but session() would and did persist - so some caution is required here - but not much).
So do this:
Pass values by session(), but on FIRST PAGE load (IsPostBack = False), transfer the value(s) to view state, and you are done!!
So, while session() can and is and will be shared between even two browsers running? Well, you click on some row, get PK into session(). Now, say you jump to the next page, on page load (IsPostBack = false), you transfer session value(s) to ViewState, and now you have full operational page - not dependent on Session().
The above is the best solution I have found, and you don't in most cases have to change your code, or introduced some mucked up URL which I find is even more of mess.

How are ViewStates accessible everywhere without being declared?

I was always under the impression that to access a variable in multiple methods, you'd either have to declare it as a class member or pass it in as an argument.
However, I was looking over some sample code recently to learn .NET, and I came across something called a ViewState. I understand it's meant to track some Pages and Control Properties, but I don't understand how it's being used here.
The code looks somewhat like this:
private void RowValidating(object sender, EventArg e) {
ViewState[Backup] = ViewState["TestId"];
// more code that does not include ViewStates
}
private void UpdateBox() {
// some code that does not include ViewStates
int box_id = ViewState[Backup];
// ...
}
How is ViewState accessible everywhere? It is not declared anywhere in the class or in any of the other class files, and this [Backup] key is just sort of created without initializing it. As far as I can tell, ViewState[Backup] does not exist until RowValidating is called.
Would it be possible to set ViewState as a global variable? Or could I always just make my own key that is accessible anywhere? It seems to behave like a dictionary, but I thought the notation was dict.Add(item, value), not dict[item] = value when working with a new item. It must be initialized somewhere, perhaps in some imported library?
Both Session() and ViewState are and can be used to persist values in your code. You don't have to declare them, they are built in features of asp.net
Session() is per user and thus is often used to persist values or even pass values between pages. However in some cases ViewState is preferable.
So for example if you have a productID or maybe even a house you are about to buy? Well, if you have two tabs open or even two different browsers open then Session() applies to all instances of the browser(s) in question open. So if a user has two seperate browsers opened, then the "ID" value you persist in session() will apply to both (so, be carefull, which house ID are you about to buy when you have 3 browser pages open to 3 differnt houses open? So session() is global to the user.
So for say "persisting" a row of data to pass to the next web page/form, Session() can be great - but keep in mind it is shared among all pages opened and in operation by that user. So session() is still per user - but global to that user.
Session() can be server "in memory" (the default). However, if you are using a server farm, then each of those multiple servers can't share their memory, and as such you have to adopt what is called SQL server based session. So in place of holding these values in memory, the session() state is shuffled from a serialized "blob" stored in SQL server. So if you hosting your site say on a cloud based system like Azure (as opposed to regular hosting), then session() can't persist on these so called "large services" based systems (or you are using a server farm with load balancing in which you have multiple-servers hosting the site for scalability reasons). Since multiple copies of the hosted web site can exist at the same time, then a means to have a common session() is required (so they shove a blob thing into SQL server). So you can still use session(), but it actually stored in sql server. It is noted that in some cases session() based on SQL server can cost performance. As high as 10% - perhaps a bit more. I find that in most cases you not notice this performance hit. But it works seamless() and in fact adopting SQL server based session will mean that session() is not frequent lost due to site execution errors. I had all kinds of issues with a site losing session(). If the web hosting and management system puts the server to sleep, or even .net code errors occur, it can (and will!!) often cause a application pool re-start - and that blows out session() (but not with SQL server based ones - they are rock solid).
ViewState is often preferred since it is by EACH NEW web page. And this is stored 100% in the browser. So to persist that houseID or product you about to purchase, then this occurs by page, and not all web pages in use by the user (so in this case, VieweState would be a far better choice). ViewState is thus stored by the browser and is much the SAME mechanisum used when you enter bunch of values in text boxes, and then do a post back. The web page travels up to server - page is processed and sent back down. But you will notice that MOST controls on the page retain their value. To achieve this then ViewState is used. And this applies to hidden text boxes (or hidden fields - much the same as a hidden text box). So this encrypted blob lives in the browser client side. And this blob thing thus goes along for the post-backs and round trips to keep those controls values in-tact.
So you can use session(), or ViewState But, as noted, you don't want to stuff too much into that ViewState, since it becomes part of that round trip life cycle. But ViewState as noted is often preferred since it is per page operation. However, since each new browser page opened creates a new local per page ViewState? Then ViewState can't as a general rule be used to pass values between web pages like Session() can.
However, you CAN pass all values of all controls to the next page. You can do this by using the post-back URL of a button. When you do this, then on FIRST page load, you can use the page.previous property in the on-load event. This will give you use of ALL values from the previous page - and you don't need Session() to do this. You can also use page.Previous if you do a server.TransferRequest as opposed to a Response.Redirect().
Last but not least? You see a lot of sites have a whole bunch of parameters in the URL. So this is often used and has a long history of use. Of course users can mess and change with these values - but they are still often used and often make the URL's rather ugly. For this reason I do like asp.net sites, since then URL's don't expose a bunch of stuff in the URL as parameters and keeps such information out of site and mind. You see a lot of shopping site still using parameters and values in the URL - and they do this for reasons of scalability - (they don't have to store the persisting values server side - it saves resources).

Check status of user during (server) interaction in MVC

I have somewhat of a thought problem, where I'm not sure if what I already built can be done a lot more efficiently, so that's why I'll share my 'problem' here. (to be clear, everything I have built works, I'm just looking to make it more efficient).
I have a webapp made with MVC & SQL which has a log-in system etc for users.
A user has a status, which is an enum, and can be active, blocked etc and is stored in the database (along with other user-data).
Within my webapp I have made a custom AuthorizeAttr. for authorizing users on every call made (applied as a global filter).
However, the 'normal' authentication is based on the cookie, which does not change when I would change the user-status in the database. For instance, users can de-activate another user in the same group (when being Admin). These database changes are not taking immediate effect since by default the authorization only verifies the cookie, and the cookie is based on the status when logging in.
To fix this issue, I added some additional logic to my authorizationAttr, which on every request calls the database for the current user status (the enum), and then simply does some checks whether the user is allowed to continue, or a redirect is required.
Calling the database on every request seems (even just for 1 enum) seems to be a bit taxing on the server/db especially when the webapp would grow in popularity (= lots of users).
One idea I thought of was to cache the enum in session cache but for short periods of time (like 60 seconds), this would save some database calls, but obviously the user can still use the webapp for max 60seconds after being de-activated.
I could be wrong in thinking that these database calls are actually that taxing of course.
Any ideas for improvement?
how do you know that checking status per request is too expensive? did you measure performance cost of checking user status in the database? have you created your custom cache without actually measuring the cost of simple solution? do you use ORM like hibernate? they have 2nd level cache built in so often there will be no roundtrip to the database.
i think it's way better to stick to the KISS principle rather than creating custom solution for a difficult problem. even if your database will be the bottleneck then usually buying additional hardware once is cheaper than maintaining overcomplicated solution for years
if your application grow, first thing you throw away is relation database
Have you considered using ADO.NET DataSets for your requirement? If you don't have multiple front-ends you could possibly read the login statuses initially into the dataset. All read/write operations could be made to this and you could later save your changes to the actual database. In case you have multiple front-ends, would it be possible for you to restrict all read/write/modify operations of one group to a single front-end instance? Because I guess you could use the dataset approach in that case as well.

MVC: Html.Serialize vs Session

I'm currently implementing a wizard for making an order, it consists out of a few steps, but this differs per product.
I have to save state between steps, so the user can jump back and forth and make adjustments.
To do this, and after some browsing, it seems there are two ways to do this:
Have a main ViewModel with child-models for each Step, then Html.Serialize the models in your page
Just store the whole object in Session
I am wondering why I would choose either method. The first one has been introduced in MVC2 in 2009, and that's also about as old as all posts regarding Html.Serialize date back, so I'm wondering if its still an accepted way. Especially given it has a lot away from ViewState, which was far from secure in ASP.NET.
Session seems the most logical choice after that, but I wonder what the downsides are. Will my session be lost if the app-pool decides to recycle? Session is server-side right?
Thanks!
Little side-note: Not interested in doing it with Javascript at this point, I'd like to keep this serverside. Hence I didn't list it as a third option.
A Session has a limited lifetime and won't work properly if the user has multiple tabs opened on your wizard.
Keeping data in hidden fields is cleaner as it is truely stateless unless it's too big or you have to keep it server side for security reason.
I advice you to try with hidden fields and switch to session only if there is an issue.

Best state-management for multi language support?

I have a small web application that has multi-language support (en, de, it, fr, nl, sl, hr). This application is accessed constantly from a lot of users that use it for a short time (the time to fill their data to get an internet access code).
I have a problem with setting the culture similar to this thread:
InitializeCulture change language of domain
I know how to do it, it's just that I'm not sure which state-management to use. I wanted to ask for suggestions which method to use. Those are my thoughts:
Session - the easiest way and the more elegant, but it's server side and I have a lot of requests so I fear that the server can get too overloaded
Cookie - easy to implement and it's client side, but some users have cookies disabled in their browser
QueryString - not so easy to implement in this phase, but it's client side and can be easily tested because the application has only 3 forms (3 URLs to add query string parameters)
I'd like to hear your ideas and suggestions.
Thank you in advance!
Actual persistence store would actually depend upon the scope/life-time of culture selection. For example, if it's user specific selection that has to be persisted over sessions then you can use database or persistent cookie where cookie will remember for a machine and database will remember across machines. The retrieval (from database) will happen when it's needed - and the value can be cached into ASP.NET cache (will need different key per user) or session or view-state (if its single page application) etc.
You shouldn't worry too much about putting that into session if you are already using session state for something else. In such case, it doesn't really consume any significant memory. If you have log out function then you can explicitly clear the session state and release that little bit of memory. If you don't have log out functionality then you can use small value for session timeout.

Categories