Home > Mobile >  How do I separate data in browser sessions when my form is using a gridview in asp.net
How do I separate data in browser sessions when my form is using a gridview in asp.net

Time:11-23

I am not sure if my question is clear but let me explain. First off I am not a professional programmer and I know that I am doing things wrong. I have created a form to collect contact information which has a gridview. My page does a few postbacks while I am collecting info. When there is one user and one browser everything works great. When I have multiple users trying to input data my app doesn't work as I want. So the first problem which I know is a problem is that I am using some static variables to store info. Point me in the direction I need to go in order to program correctly. The second issue and probably related; the gridview will display all information across browsers. Meaning if user A inputs info it will show in the gridview of user B across the globe. How do I make each person to have their own instance of the app? This is my real question. Any resources or guidance would be greatly appreciated.

Well I was trying to localize my variables so that they are not static but I am not sure if this is the only problem. I am thinking about viewstate but I am just not sure.

CodePudding user response:

As you found out, using static variables will not work. Not only will it mess up your code with other users, those static variables "sort of" and "hope on a wing and prayer" will persist, but sometimes they do not!!!

so, static varabiles not only don't work with multi-user, but they can un-expected go out of scope.

The only use of a static class in .net and webforms?

For a shared code module. So in vb.net that means my "genreal" set and hodge podge of routines, or in c# we use a static class, and this is 100% fine as long as you NEVER use class varibles in those static classes (or code modules in vb.net), then you are fine.

So, for all kinds of general shared code, then a vb code module, or a c# static class is 100% fine. (Those routines can be passed values, and have local vars, but NEVER class scoped variables (since you never have to create an instance of such classes, then take off variables scoped to that given class, and you are just fine.

Ok, next up, what about persisting values in each page?

Well, first up TOP GOAL is to reduce the amount of persisting you have, and only persist things that you absolute must.

Now, most controls, including the grid view have automatic persistance built in.

However, this introduces our first design rule and pattern:

In the web form's page load, you are 100% free to load up the gridview, listbox(s), combo boxes (dropdown list) etc., but you ONLY want to load these things up ONE time and ONLY on first page load.

That means and results in the last 200 web pages I have built, that EVERY page has a "real" first load code stub.

That means this:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then
        LoadGrid()
    End If

End Sub

Sub LoadGrid()
    Dim strSQL = "SELECT * FROM tblHotelsA ORDER BY HotelName"

    GridView1.DataSource = Myrst(strSQL)
    GridView1.DataBind()

End Sub

So, in above examle, I wanted to load up the GV with data.

Note the if not IsPostBack stub. EVERY one of my pages has such a code stub.

So, what this means is the page can survive post-backs, and a dropdown list etc will correctly save/persist their values.

However, so far, that does not cover variables and things say like a PK value.

So, the next two choices that are the bread and button choices are:

Session() - server side - per user.

ViewState() - client side browser - per web page.

Grasping when to use session() vs ViewState is quite much the Rossetta stone that un-locks how you can persist values, but not have values over write or clash with other web pages that a SINGLE user might have open.

So, I tend to follow this design pattern

Session() - use that to pass values to another page, but on the above first page load, transfer those values to ViewState().

Why?

Because session is global to teh one user.

lets take a typical super simple example.

I have a list of hotels, user will click on a row - say to book a room in that hotel. When they select the one row from the GV, then we will jump to the next (differnt) web page that shows details about the hotel room etc.

So, I can use session() to PASS the hotel PK id to the next page, but I cannot use session() for that page to "operate" based on that PK session value.

Why?

Because what happens if they have two copies of the browser open, or have two tabs open on the list of hotels page, and then click on a row.

if they have two browsers (or 2 tabs - same case in regards to session(), then I can now have two web pages open on the hotel details/information.

But, if the code behind uses/assumes/operatates based on that session("HotelPK") value, then I have two pages open running that same code!!

Now, if you buying a house, you may well wind up buying the wrong house!!

Or you have two web pages open, code assumed each has HotelID, but session() is global to the one user.

So, session is great for persiting values global to the one user, but NOT for code that needs some values persited for the ONE page.

So, I will (and do) use sesison all the time to pass values to the next web page, but FIRST task is to then transfer that value to viewstate(), and hten all code on that page operates/uses/consumes ViewState to function.

So, say I have this GV of hotels:

    <asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
        DataKeyNames="ID" Width="100%" CssClass="table table-hover"  >
        <Columns>
            <asp:BoundField DataField="FirstName" HeaderText="First Name" />
            <asp:BoundField DataField="LastName" HeaderText="Last Name" />
            <asp:BoundField DataField="City" HeaderText="City" />
            <asp:BoundField DataField="HotelName" HeaderText="Hotel Name" />
            <asp:BoundField DataField="Description" HeaderText="Description" />
            <asp:TemplateField>
                <ItemTemplate>
                    <asp:Button ID="cmdEdit" runat="server" Text="Edit" CssClass="btn myshadow"
                        OnClick="cmdEdit_Click" />
                </ItemTemplate>
            </asp:TemplateField>
        </Columns>
    </asp:GridView>

Above page load code is used, and I now have this:

enter image description here

Ok, so now we click on that View button, and we will grab the PK value (Which by the way is NEVER exposed to the client-side browser for reasons of security).

Now, when you hit view, we have to store/save/have use of/pass the Hotel PK id selected from above. So, we will "need" to persist that value in the code that operates on that ONE hotel we selected.

As noted, we have several options:

HiddenField - this actually uses viewstate, but is OFTEN handy for persisting values, and nice is client-side JavaScript (js) can use (or even set) such values, they persist and the values in a hidden field can be used by both client-side code, and server-side code. This of course is a "per page" persisting. This choice can't (should not) be used for things like row PK values, but for "low" security values and variables, a HiddenField can be a great choice.

The other way to persist values is to place/put them in the URL as paramaters. I think that looks ugly as can be, but worse, once again, this only works for values that of "low" value.

So, to pass a value to the next page, we can use several approaches, but session() is really good, per user, but ONCE we have that new page loaded, then we use ViewState.

So, the code for above "view" button can/will look like this:

Protected Sub cmdEdit_Click(sender As Object, e As EventArgs)

    Dim btn As Button = sender
    Dim gRow As GridViewRow = btn.NamingContainer

    Dim HotelPK As Integer = GridView1.DataKeys(gRow.RowIndex).Item("ID")

    ' Now jump to our hotels edit page:

    Session("HotelPK") = HotelPK

    Response.Redirect("EditHotel")

End Sub

So, we can use session() to pass the HotelPK.

But, as noted, we ONLY use session for passing the value, NOT persisting.

So, now on the hotel edit page (hotel.aspx), then our all important load event will have this:

Dim intHotelPK As Integer = 0

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Not IsPostBack Then

        intHotelPK = Session("HotelPK")

        ViewState("HotelPK") = intHotelPK

        ' Load up our form to edit hotel
        Dim strSQL As String = "SELECT * FROM tblHotelsA WHERE ID = " & intHotelPK

        Dim rstHotel As DataTable = Myrst(strSQL).Rows(0)

        Call fLoader(Me.EditHotelDiv, rstHotel)
    Else
        intHotelPK = ViewState("HotelPK")
    End If

End Sub

Now, for any button click, any code that runs in this page?

Any variable, including any post-back button can use intHotelPK.

so, my save button code would/could be this:

Protected Sub cmdSave_ServerClick(sender As Object, e As EventArgs)

    Dim strSQL As String = "SELECT * FROM tblHotelsA WHERE ID = " & intHotelPK
    Dim rstData As DataTable = Myrst(strSQL)
    Call fWriterW(EditRecord, rstData.Rows(0))
    Call MyRstSave(rstData, "tblHotelsA")

    Response.Redirect("ChooseHotel")

End Sub

Note how any button click, and any code now has a persisted value of HotelPK, and any code, post-back code etc. is now free to use that persisted value.

And EVEN if the user will have two browser tabs open, or two copies of the browser?

The code will still work fine, since they can't really click on two open web pages at the same time. So, we can (safe) pass the pk id, shove into session, and now that page will operate correctly, have a persisted "hotel PK id", and it will not matter even if they have 2 or 5 pages open (more then one time). the code will work, since ViewState is per page.

However, use caution with ViewState. ViewState is client side storage, and each button click (post-back) means that ViewState travels and makes the round trip. (thus increasing the size of the post back). So, don't go shoving in some large dataset or datatable - since it will cost dearly in terms of response time.

So hopefully the above gives you some ideas here.

This also means in some cases, you will "often" re-pull data from the database, and in 99% of cases, a re-pull of some data for code behind is BETTER than attempting to persist a dataset/datatable in code behind.

And in fact, unless only a few rows of data, I don't recommend using ViewState for persisting datasets/datatables. Session() is much better if you must do this, but while session() is 100% server side, it also per user, and not per page - so as noted, use session () for passing values to the next page.

And if you need to pass 5 variables to the next page? Build a little class, since then you can "group" sets of values required for a given page operation, and they also facilitate passing of values to the next page with great ease.

  • Related