How to avoid using Session - asp.net

i have an interface that contains data-grid. When i add element to data-grid, i add it also into List property that is the data-source of my Data-grid. Here the declaration of my list in code-behind:
Public Property listeSpecialite() As List(Of RECSPECIALITECONCOURS)
Get
Return Session("specialite")
End Get
Set(ByVal value As List(Of RECSPECIALITECONCOURS))
Session("specialite") = value
End Set
End Property
and here is the code when i add element to Data Grid :
Protected Sub gridsecialite_ItemCommand(source As Object, e As System.Web.UI.WebControls.DataGridCommandEventArgs) Handles gridsecialite.ItemCommand
If e.CommandName = "Insert" Then
Dim dropSpecialite As DropDownList = CType(e.Item.FindControl("txtSpecialite_Footer"), DropDownList)
Dim specialite As New RECSPECIALITECONCOURS
specialite.CODESPECIALITE = IGS.ChercherParIdInt(Of GENSPECIALITE)(CInt(dropSpecialite.SelectedValue))
listeSpecialite.Add(specialite)
gridsecialite.DataSource = listeSpecialite
gridsecialite.DataBind()
End If
End Sub
and in user click save, i save all element in my list to database.
how can i save element of the list without the use of session. (my boss say that it's not good to store list of element in session-performance reason)

You can use ViewState to store listeSpecialite. Just make sure to understand how it works to ensure that match what you need.
Viewstate has its own drawbacks. More process time for serialization/deserialization, encoding/deocding in B64 and for the page lifecycle in load/restore viewstate of the page, etc. Also, by default, viewstate is sent to the client in a hidden field. This increase bandwidth.
Anyway, if your list has not to be persisted out of your current view I would use Viewstate.
EDIT:
With list of 1000 items viewstate will be hurge. How about read from data base persisted items and keep in viewstate just the added items?. You could retrieve items of database, retrieve items from viewstate, combine and bind to datagrid. It is another strategy to avoid session and hurge viewstate at the cost of read database every postback.
As I said, there is no silver bullet... :-P

Related

Is there a way to directly use a property of an enclosing usercontrol in a sqldatasource?

I have a user control. In that control I have a data view that uses a sql data source. I would like to have one of the parameters to that sql data source be a property of the enclosing user control. The idea is that I want the page that includes the user control to set the property on the user control to the ID of a record, make the user control visible, and now the user sees the data for that record.
I'm thinking that I should be able to have a ControlParameter that references the enclosing user control. But what's the control ID?
I came up with something of a work-around by using a plain Parameter and writing
Public Property record_id As Integer
Get
Return dsRecord.SelectParameters.Item("rid").DefaultValue
End Get
Set(value As Integer)
dsRecord.SelectParameters.Item("rid").DefaultValue = value
DetailsView1.DataBind()
End Set
End Property
That works and it isn't all that much code, but it seems kind of ... crude. Is there a cleaner way?
Assuming YourDetailsView.DataSourceID="dsRecord" and it is visible at the time of binding, this may be all you need:
Public WriteOnly Property record_id As Integer
Set(value As Integer)
dsRecord.SelectParameters.Item("rid").DefaultValue = value
End Set
End Property

PagedDataSource not working with previous/next pages

I'm having a hard time with this scenario and hoping someone can help me clarify where I'm missing a step/logic. I tried searching online but I couldn't find an example that addressed this issue.
We are setting up a search page that when first loads shows a bunch of options (e.g., textboxes, checkboxes, etc). The user will fill out the form and submit the form back to itself. Once posted back, the page will build and run a SQL query (e.g., SELECT ID FROM Customers WHERE Company = 'Acme' AND AmtDue = 3) against the database with the user's options and then the results will show up. This part works ok.
The part that breaks down is when I am trying to add pagination. The result set is a DataTable bound to a Repeater. I am using a PagedDataSource to add pagination. Pagination works great for the first page but for subsequent pages, it does not work. Basically, instead of returning the next page of the result requested (e.g., SELECT ID FROM Customers WHERE Company = 'Acme' AND AmtDue = 3), the results returned is the SQL query before appending the user's search options (e.g., SELECT ID FROM Customers).
I think my basic problem is that I'm not sure how to distinguish a normal Page.IsPostBack and paginating through results. The reason why this is causing problems is because I don't want to be regathering form data, rebuilding query, and requerying the DB.
The examples that I found online involved pagination of a DataTable that is rebuilt every time the page loads (e.g., Not Page.IsPostBack).
Here is a rough outline of our code:
Public dtCustomers As DataTable = New DataTable()
Sub Page_Load(ByVal Sender As Object, ByVal E As EventArgs) Handles Me.Load
' When the page first loads, show the search form with search options.
If Not Page.IsPostBack Then
ShowSearchForm()
' Once the form is submitted, show the search results.
Else
' ----------------------------------------
' This is the part that I'm having trouble with. How do I skip the following two steps (GatherFormData() and BuildDT()) when the user requests a subsequent page?
GatherFormData()
dtCustomers = BuildDT()
' ----------------------------------------
BindData()
End If
End Sub
Sub BindData()
Dim objPDS As PagedDataSource = New PagedDataSource()
objPDS.DataSource = dtCustomers.DefaultView
objPDS.AllowPaging = True
objPDS.PageSize = intNumPerPage
objPDS.CurrentPageIndex = Me.ViewState("_CurrentPage")
rptSearchResults.DataSource = objPDS
End Sub
' Subroutine called when the previous page button is pressed.
Sub GoToPrevPage()
' Set viewstate variable to the previous page.
Me.ViewState("_CurrentPage") -= 1
BindData()
End Sub
' Subroutine called when the next page button is pressed.
Sub GoToNextPage()
' Set viewstate variable to the next page.
Me.ViewState("_CurrentPage") += 1
BindData()
End Sub
Note: I understand that the DataTable will have to be put into cache or a session variable, but haven't decided the best method.
Please excuse the code outline but the actual code is massive so the simplification is to make it easier to get to the heart of the issue.
Let me know if any of that was unclear. Thanks in advance!
I am assuming that you are going to store your data in session/cache (I would prefer the later but there can be use case for storing it in session) - you can store the key in the view-state and presence of key could be use to determine if post-back is for pagination or not. For example,
if (ViewState["dataKey"] == null)
{
// first form submittal, do the search
GatherFormData();
dtCustomers = BuildDT();
// store it in cache
ViewState["dataKey"] = Guid.NewGuid().ToString(); // create a key
Cache.[ViewState["dataKey"].ToString()] = dtCustomers; // TODO use Add method to control expiration etc
}
Its important that you clear the view-state when the search is reset (or similar condition)
Lastly, it is also possible to do the paging from database/data-store (for example, using ranking functions in SQL Server) so that you need not have to store the search results into the session/cache but rather do a database trip at each post-back. Such approach is useful when the complete result set size can be huge.

Loop through Dynamically Created Controls

What I am trying to do is dynamically create a bunch of dropdown lists and then I want to loop through them and update the database with those values, but the problem I am facing is that I create the dropdown lists, but then when I go back to loop through them they are no longer in the panel. I don't know why but when I am debugging I have a count of 50 controls in pnlTeacherSelect right up until I press the button that calls prcChoose.
Called on Page Load
Sub prcSetTeachers()
For Each Subject In ds.Tables("Subject").Rows
Dim Temp As New DropDownList
pnlTeacherSelect.Controls.Add(Temp)
Temp.ID = "drp" & Subject.Item(0) & "s" & Child.Item(0)
Next
End Sub
Called on Clicking a button
Sub prcChoose()
For Each DropDownList In pnlTeacherSelect.Controls.OfType(Of DropDownList)
'This is never executed
Next
End Sub
Any ideas what's causing it? Thanks in advance!
You have to recreate all dynamically created controls on every postback(in load event at the latest).
You also have to ensure that they get the same ID as before to trigger events and maintain ViewState.
If you know the number of controls to create(which could be stored in ViewState) you can derive the ID from the counter variable by appending it to the control-id. Then you can recreate them with the correct ID in page's init event.
Recommandable readings:
TRULY Understanding Dynamic Controls
Page-Lifecycle
Or you use one of the builtin Data-Bound Control like Repeater that do this automatically. You only have to set their DataSource and call DataBind().
Here are answers of me on similar questions with implementations:
C#
VB.NET (+ C#)

when using datasource and databind to set items in a dropdownlist - index is always the value of first item

I am trying to use datasource and bind in my application to set a dropdown list to the results of a query. The dropdownlist populates correctly (shows each different type_name in the set) but later when I use ddltype.selectedvalue - I am always getting the value from the first item in the dataset. Here is the code.
if ds.hasRows = true
ddlType.DataValueField = "type_id"
ddlType.DataTextField = "type_name"
ddlType.DataSource = ds
ddlType.DataBind()
end if
Then later on I use the following code to try to get teh selected value
Dim typeID = ddlType.SelectedValue
I have ran the query to get the dataset on my SQL server and get the below results - but every time I use the above dim statement, the value is set to 812 even when type 2 is selected. Below is the results from the query that fills the sqldatareader named ds.
type_id : type_name
___________________
812 : type one
813 : type two
Thanks in advance.
Based on the information in your question, I don't see anything wrong.
But based on common mistakes people make with this pattern, I am guessing you are probably running ddlType.DataBind() on every postback. So the user clicks a button or something similar to fire the postback, and the DDL is re-bound before your click handler checks the value. Re-binding sets the selectedvalue back to default.
Edit: Your databinding code in Page_Load should only run once. One way to do this is to wrap the databinding code...
If Not IsPostBack Then
If ds.hasRows = True Then
ddlType.DataValueField = "type_id"
ddlType.DataTextField = "type_name"
ddlType.DataSource = ds
ddlType.DataBind()
End If
End If
This will cause the databinding to occur only the first time the page is requested, but not after a button click or other postback action.

Pre-Select Items in a dynamically populated CheckBoxList

I've been experimenting with this and trying to understand the Page Life Cycle for hours upon hours. I'm completely stumped at this point :'( Any help would be GREATLY appreciated.
Below are my methods. My _PrefillWizard method actually works for all the controls on my page except for those which are dynamically populated. The CheckBoxLists are such because they are automatically generated based on selectable values in a table in my DB. I already have this control in my markup like so... how do I force this to load and be ready before running my other code?
<asp:CheckBoxList ID="MyLanguagesCBL" runat="server" RepeatDirection="Vertical"
RepeatColumns="4" Width="100%" DataSourceID="LanguagesSDS"
DataTextField="Language" DataValueField="ID">
</asp:CheckBoxList>
<asp:SqlDataSource ID="LanguagesSDS" runat="server"
ConnectionString="<%$ ConnectionStrings:ConnectionString1 %>"
SelectCommand="select ID, [Language] from LanguagesListTable"
DataSourceMode="DataReader">
</asp:SqlDataSource>
Obviously these particular controls are not yet generated or on the page by the time my _PrefillWizard has been called, resulting in none of the CheckBoxes being pre-filled. How do I make them generate before my prefill method is called? Thanks ;)
The click event that kicks things off.
'On "Load" Button click, clears a Wizard control and Prefills it with the
' data from the clicked record based on the primary key stored in SessionState.
Protected Sub RowClick(ByVal sender As Object, ByVal e As GridViewCommandEventArgs) Handles GridView2.RowCommand
If e.CommandName = "Select" Then
Session.Add("ClickedPrimaryKey", GridView2.DataKeys(e.CommandArgument).Value.ToString)
'This is the main function which calls "_SetCheckBoxes" among others.
_PrefillWizard(Session.Item("ClickedPrimaryKey"))
End If
End Sub
Here's my function for populating the my CheckBoxList control, but it obviously depends on the control having already been loaded on the page.
'Parse a CSV String from the Database back into CheckBoxList Selections
Protected Sub _SetCheckBoxes(ByRef cbl As CheckBoxList, ByRef dt As DataTable, ByVal row As Integer, ByVal csv As String)
'Do something if there is a value in the cell
If Not IsDBNull(dt.Rows.Find(row)(csv)) Then
For Each item As ListItem In cbl.Items
item.Selected = False 'Reset the checkbox first
'Then, if the ID value of the checkbox corresponds to a value
' in the CSV string, then tick the checkbox.
If csv.Contains(item.Value) Then
item.Selected = True
End If
Next
End If
End Sub
Here is a potential idea, and one that we have used before in a similar situation:
Because the Page Init event is fired before the click handler, you can actually examine Request.Form("__EventTarget") and, if it is your row click, add the new CheckBoxList to the appropriate container (page, tab, etc).
If you are adding multiple controls, you will have to be sure that you track the added items somewhere in the page so that they can be automatically re-created each time Page Init is fired.
You guys will probably get a kick out of this, but the answer was so obvious that I didn't even catch it all this time. Of course I was preoccupied with about 10 other functions too >.<
Here's the answer. You'll notice that in my _SetCheckBoxes method, I first checked to ensure that a value existed for the particular csv string, but also notice, that I failed to actually SET it to the corresponding value string afterward. This isn't immediately apparent, but what I was actually passing in as csv was the name of the Column in my DataTable where the string actually lived.
csv = dt.Rows.Find(row)(csv).ToString
That line added immediately after my IsDBNull check, fixed my problem. :)

Resources