ASP.Net - Persistent shopping cart across sessions - asp.net

What would be considered best practice for implementing a persistent shopping cart in an ASP.net Web Forms(*) based application? The only built-in way seems to be involving the Session state, which is not ideal because once you close the browser... it's gone. One way seems to be involving the localStorage via Javascript, but that creates awkward client/server mixups, as the data processing is meant to be done server side.
(* please pay attention to that part - MVC or Blazor based solutions will not work for this particular case)

Well, I can't imagine any practical application that involves database operations having ANY kind of suggesting that some kind of session, or view state will have ANY kind of relevance to database operations?
Be it a person filling out an invoice, or making orders or anything?
Not at all different then if you were writing a desktop application.
If a user is building up a list of items or "things" for/in an order?
Then as they build up such an order, then a database "order" record and structure will be built up. No different than say even building an invoice system say for the desktop with ms-access.
The only "use" of say session in most cases allows you to pass information from one page to another. (In place of say using parameters in the URL).
So, person might have a shopping basket of items (in your database, right!!!!).
They browse/search for more things to add to that shopping cart.
So say while on some items page, they choose to buy/select. When they make that choice, then you might say shove the ProductID into session, and then jump back into the current basket of items page, check session for a new product, and then insert/add that new item to the basket (which was being saved in the database).
If they log off, then fine. When they log back on, then you can load the current basket of items for display, and then allow them to continue shopping.
the only thing you going to use session for (or viewstate) is to allow the person to jump around looking at items, and then upon selection, you get/grab that particular product ID into session, jump back to the basket page, and add this new item from session, and then display their list of selected items.
So, in your database you have their current active order/basket, and thus when the user logs on, you can jump to that most recent or only "active order" page, and pull that order from the database. And then display all the details etc.
No session or viewstate would be required nor used at that point in time.
Not really any different than building up a invoice in a accounting package, then closing the program, and then next day, you launch the accounting package, load up the invoice, and thus can continue working on that invoice until you are done.
So, they look at the order, and go, "hum", I want to browse some more. So, they go look at/buy/choose/select another product. When they do, then you can now jump back to the current orders/basket page, and check session for the value just passed, add to order/basket, and now display the items in the basket, and that one "product id" in session can be pulled out, and is no longer required.
so session is not some kind of "magic" database system but is really only a feature to allow you to persist some values for a very short time, and only a simple "id" or simple variable in code for a rather short time. So session is ideal for passing a few values for use in code behind variables from one page to another.
Thus things like an address, name, products selected? That goes in the database, and not session.
For the most part, such software really not much different then desktop software.
You save and build up the list of items attached to a given order, and that order going to exist in the database.
So no real development approach here suggests saving their name, billing address, their past orders, the current new basket/order they have? That all going to be saved in a database.
So, session() is only relevant in most cases to "pass" some values, or "hold" some values for code behind.
So, if they select some product from a grid, you would shove productID into session, jump to the basket, add the new item in code behind to that order, and then let the page pull the information from the database to display items in that order.
So "session" persisting of data? That really only for a few variables that your code might need for some data operations, but your data for that order is not persisted in session - it goes into the database.
Session has VERY little to do with using a database system to "manage" and "hold" and "have" the order saved in the database system.
Session is not some kind of database - only a "active" storage of some variables you might need during program operation.

Easy, store it in database for logged in user.
use local storage or cookies for guess.

Related

I have multiple users, can i lock the web page so that only one user at a time can update a record?

Can anyone help or provide me with some suggestions for the below query.
I have a web form (Minutes of Meeting) and 8 users that need to access this web page and update their area. A user may have more than one area to update and essentially i would like to some how lock down the web page if possible when a user is using it so that no other user can update this web page till joe bloggs has finished with it.
I have a Active Directory security group set up to restrict the site to that group of users only, but i need to think of a solution to the above?
Is there a way i can do this via a web control or via SQL?
There must be better ways to do it. However, Is it possible for you to introduce a sql table column similar to "UpdateInProgress" (bit). Any update process sees that column, If 0 then It updates to 1 and after It saves the changes and updates back to 0 so that the form is available for other to update. If update process sees 1, It can't update the web form because update is in progress.
I also suggest to introduce another column named "UpdateInProgressBy" to check who has opened it for editing.
First of all we must note that there is a big time from the moment the user reads the data, get it in a page, change them and then try to write them back. So we are not talking for the lock command on SQL, nether any other lock that happens in milliseconds and help to synchronize threads, but here we must synchronize people and what they write.
There is also a problem if the user leave the page for any reason and this can make the data lock for ever.
This problem can solve with two approaches.
the easy one, when a user try to save data you must check if the same data have been change in the middle, and warn him, or show a merge dialog, or merge programmaticall, or something similar - I do not know what you won.
the difficult way is to constantly monitor the page that read and change the data, and keep this monitor results on a common table in the data base, and there if a user have been and stay on page, the rest users get a warning and read only data, until the user go.
This monitor must be made with javasript and must know even if a user abandon the page.
SET TRANSACTION ISOLATION LEVEL as SERIALIZABLE
for more information check this link:
http://msdn.microsoft.com/en-us/library/ms173763.aspx

How to break up a list of items to edit among multiple web users

I have an ASP.NET 4 application where I have a list of items and users need to do some work on each item. Since the list can be very long, I want this review process for each item to occur as efficiently as possible. My idea is to have a web page that displays one item, the user does what they need to do, then clicks on a Next Item button. The system automatically picks the next item from the list. So far so good...if only one user needs to do this.
The difficulty is in coming up with a reliable and effective solution for allowing multiple users to work through the list. If a user clicks Next, I don't want the system to bring up the same item that another user is working on.
It's not the end of the world if two users work on the same item (the last to save wins), but it's a waste of time and should be kept to a minimum.
Some techniques that I can think of:
1) Pick the next item randomly from the list. The chance of two users getting the same item goes way down. The bad is that users can't predict what they will get next and can't really work sequentially through the list.
2) Use some kind of optimistic locking to lock the record. This is generally bad for web applications since the user can go to any page or kill the connection, potentially leaving the lock there until some kind of expiration. The good part about this is that users can work through the list or parts of it sequentially and the system will simply skip records that somebody else is working on.
However, does anybody have any other suggestins?
Update:
Assuming that a user is only allowed to edit ONE record at a time (i.e. no opening other browser pages or sessions on the same list) one possible solution for using optimistic locking is as follows:
For each record, (as #Shai suggested) keep track of: Edit status (Available, InProgress), User currently editing, Date edit was started.
When a user wants to get the next record, lock the table, scan for the next Available record, change it's status to InProgress, unlock the table. Update the user and date information.
When a session expires (perhaps the user closed their browser), set any records associated with this user to Available. Sessions last a few hours in order to support extended editing timeframe.
If the same user logs on again before the other session is expired, again set any records associated to this user to Available.
Now, this is where it gets a bit complicated. What if the user goes home but didn't finish with a record (or a list of records, if we allow more than one), how do we get other users to be able to take over without waiting? We could add a special UI to list all current user sessions and allow somebody (who knows the user is no longer working) to explicitly unlock any records.
Any suggestions on improving this?
It seems that the items should potentially have 3 statuses (statusi?): Open, InProgress and Completed. When the user requests an item you return the first item with a status of Open, and at the same time set that item's status to "InProgress". And when they save the item, you can set it's status to "Completed". Rinse. Repeat.
To make sure that no two users get the same open item, you can lock the table during a quick sproc that selects the open item and set's its status to "InProgress". This sproc can have the item id as it's return value. By only returning the id rather than the entire record, you will be locking the table for a shorter amount of time. Then you can select the actual record without worrying about another user retrieving ownership of the same record.
You might also want to consider recording the user who took ownership of the item. This might come in handy if you ever need to perform auditing.
Is this the direction you were going for?

Is there a way in either sql or web developer to all deleting say from a gridview all but the last row?

I have a web portal set up where customers can add company contacts, etc to a sql database thru gridviews and detail views i created with microsoft Web Developer. I need to have it set up, where although customers that have rights can edit and delete contact records, they cannot delete the last one. There must be one left in the system. I know this sounds like a strange request, but it is a needed one. Is this something that can be done thru VB, SQL, or thru one of web developers objects such as the Details View?
Thank you!
Not a strange request, as I understand the need. The solution we employed is the actual default Admin account did not show up on the delete list, as it was "system generated". That may not be a retooling you can do.
What you can't do is use the automagic drag and drop crap and institute this type of functionality. You will have to either pair down the request to remove the last requested item, write a trigger on the database or write custom code to not delte the last item.
As an example of pairing down: with datasets, since they are disconnected, you can remove the last row prior to sending your delete request. With LINQ and EF, you have similar options to shaping the return data.
Then, if you desire to explicitly control your code (good), you can roll through the items and ensure the last one does not delete.
If you want to make this as "safe" as possible, you might consider a trigger on the table that checks if the delete is last administrator user for a particular organization and abort if so. Then the user might say "delete all" on the web, but the database protects them.

Primary keys on webforms (load initially or on save)?

This is just a general question irrespective of database architecture.
I am maintaining an ASP.NET web application. The structure is such that,
Say on 'Add a new employee' webform
The primary key (or the record id to
be saved with) is initially loaded on form
load event & displayed as a label
So when the form loads, the record id to save with is shown to the user
Positives:
End user already knows what the id/serial of the form is (even before he saves the form)
So on form save when he is directed
to gridview screen (with all entries)
he can search records easily
(although the most recent one is at
the top anyway)
Negatives:
If he does not save the form, say he
just cancels after loading the data entry form,
the id/key initially fetched is
wasted (in my case it is a sequence
field fetched on form load from database)
What do you guys do in these scenarios ? Which approach would you recommend for 'web applications'? And how to facilitate the user with a different approach ? Is our current approach recommended (To me,it wastes the ids/sequence from database)
I'd always recommend not presenting the identity field value for the record being created until the record has been created. The "create a temporary placeholder record first to obtain the identity field value ahead of time" approach can, as you mention, result in wasted IDs, unless you have a process in place to reclaim them.
You can always pop-up a message box when the user presses save that tells them the identity field value of the newly created record.
In this situation you could use a GUID created by the application itself. The database would then only have the PK set to be a Unique Identifier (GUID) and that it must not be null. In this situation you are not wasting any unique keys as each call to get a new GUID should be definition produce a (mathmatically) unique identifier. It is worth noting that if you use this method, it is best to make sure your PK is not set up to be clustered. The resulting index reorganisation upon insert could quickly result in an application that suffers performance hits.
For one: I wouldn't care so much about wasted id values. When you are in danger of running out of int32 values (and when has that happened to you last?), use int64. The user experience is way much more important than wasting a few id values.
Having said that, I would not want the primary key to be anything the user would want to type in. If you are having a primary key that users need to type in, chances are it then is (or will be requested to be) more than just an int32/64 value and carries (will carry) meaning in its composition and/or formatting. Primary keys should not have that. (Tons of reasons google for meaningless primary keys or other such terms).
If you need a meaningful key, make it a secondary index that is in no way related to the primary key. If a part of that is still a sequential number taken from some counter value in your database. Decide whether functionally it is a problem for gaps to appear in the sequence. (The tax people generally don't want gaps in invoice numbers). If functionally it is no problem, then certainly don't start worrying about it technically. If functionally it is a problem, then yes, you have no option but to wait for the save in order to show it to the user. But, please, when you do, don't do it in a popup. They are horribly intrusive as they have to be dismissed. Just put up an informative message on the screen where the user is sent after (s)he saves the new employee. Much like gmail is telling you about actions you have performed just above the list of messages.

Storing shopping cart in session

I know the general consensus for information like shopping cart items is to store them in session. But what about objects that belong to a user that can be altered by other users? Say, for instance, an eBay-like site. If you store a user's "items" in session, which contain the current bid amount, and another user comes in and places a bid on that item, you would have to update both the item in the database as well as the item in session, wouldn't you?
In cases like these, are the only options to store in session and refresh whenever any action another user takes affects a person's session values or store everything in the database and retrieve it every time (could get expensive if, say, you have the bids displayed on the side panel of every page).
I would store it all in the database and retrieve it everytime. Depending on the volatility of the data caching for a few seconds may be in order. The biggest problem is keeping the two consistent.
I think that it isn't as expensive as you think to retrieve the data every time. Databases are very efficient if you are looking up based on a key. I'd err on the side of simplicity (store in DB and retrieve) until performance problems show up under load (ie in Load Testing).
If there is only going to be a handful of times, you may be able to use the Application Cache (unless you have more than one worker process/server) and make sure the DB and cache stay in sync.
I would personally store it in a database. Firstly, because your data is a lot safer there, and it makes it easier to share in the case where you need a web farm. Also, you don't need to have the data on every page. Just when the user goes to the shopping cart. The other plus of storing it in the database is that you can analyze later, the stuff that people are adding to the cart, but not actually purchasing.

Resources