Session variable removal question. as related to a paged data source - asp.net

I have inherited some very old ASP.Net code. Written initially in 1.0 and then converted to 2.0 There is a page which uses a custom pager control. That control has the following logic in it:
Private _DataSource As PagedDataSource
Public Property DataSource() As PagedDataSource
Get
If Not IsNothing(Session("DataSource")) Then
_DataSource = Session("DataSource")
Return _DataSource
End If
Return Nothing
End Get
Set(ByVal value As PagedDataSource)
_DataSource = value
If Not IsNothing(value) Then
Session("DataSource") = value
Else
Session("DataSource") = Nothing
End If
End Set
End Property
The page which uses that pager has the following logic in it:
Private PagedData As PagedDataSource
Private Function GetData() As DataTable
Dim DT As New DataTable
Dim CategoryID As Integer = -1
If IsNothing(ddlCategories.SelectedValue) OrElse Not Integer.TryParse (ddlCategories.SelectedValue, CategoryID) Then
CategoryID = -1
End If
Dim myConnection As New SqlConnection(ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString)
Dim myAdapter As New SqlDataAdapter
myAdapter = New SqlDataAdapter("SearchResources", myConnection)
myAdapter.SelectCommand.CommandType = CommandType.StoredProcedure
If SearchText <> String.Empty Then
trFiltered.Visible = True
End If
With myAdapter.SelectCommand.Parameters
.AddWithValue("#CategoryID", CategoryID)
.AddWithValue("#SearchText", SearchText)
.AddWithValue("#CompanyID", CompanyID)
End With
If Not Security.IsSiteAdmin Then
myAdapter.SelectCommand.Parameters.AddWithValue("#UserIsAdmin", 0)
myAdapter.SelectCommand.Parameters.AddWithValue("#FTPUserID", Security.GetUserID(Context.User.Identity.Name))
Else
myAdapter.SelectCommand.Parameters.AddWithValue("#UserIsAdmin", 1)
End If
Try
myAdapter.Fill(DT)
Catch ex As Exception
ErrorLog.LogError(ex.Message, ex.StackTrace, HttpContext.Current.User.Identity.Name, HttpContext.Current.Request.Url.ToString)
HttpContext.Current.Response.Redirect("~/error.aspx", False)
Return Nothing
End Try
Return DT
End Function
Protected Sub ReloadData()
CurrentPage = 0
CheckFilters()
BindData()
End Sub
The task at hand was to remove all session variables. What would be the best way to represent this data without the use of session. Originally i was told to put all session items into a cookie, while this worked for most of the items it will not work for this due to the cookie size limitation, Im also not to keen on the idea of keeping it in ViewState or even if that is an option. Im very new to VB and dont have much expierence re-writting legacy code. Session is not an option because this is being moved into a web-farm and Sticky sessions are turned off so it must work without session.
Any suggestions are greatly appreciated. Sorry if im asking a question that has a painfully obvious answer.
thanks in advance,
-James.

Well, somebody may come by and vote me down... but I'd say your best option is ViewState.
If you are limited as you are to not use SessionState and you are running into a cookie size limitation, I can only think of two other options (Cache and ViewState) and I certainly wouldn't recommend Cache for this.
Now you know you can use a out of process session state (either a SQL Server or a StateServer)?
More info can be found here:
http://msdn.microsoft.com/en-us/library/ms178586.aspx

Related

Validation Summary

I use a login entrance in my Asp.Net project
And I use validationSummary for User Name and password.
Everything goes well but.
What I want is to know if the ValidationSummary has errors to show me or not before the appearance of the errors window
I use vb.net to build the project
I don't have any code to show. And also I can't find anything relative in on the Internet to assist me on this issue.
You are probably using the ValidationSummary method in your Razor views, which - as per MSDN
Returns an unordered list (ul element) of validation messages in the ModelStateDictionary object.
So, if you want to know if there will be any errors shown by the ValidationSummary method, you can check this ModelStateDictionary in your controller before delivering your response to the browser. Doing this is described i.e. here (in C#).
In your controller method you can access ModelState.IsValid if you want to know if there are any errors which will be displayed.
This does directly answer your question, but this might not be the optimal way to achieve what you want when looking at the bigger picture. If you want to i.e. do something special if the login fails in your controller you should check directly if the login failed, not if some other method added model errors. To provide an answer, which might be more on point, you need to clarify your question and add more details about what you specifically want to do and possibly add some of your code too.
The idea to use the code I post is finally correct.
Public Sub IsGroupValid(ByVal sValidationGroup As String, ByVal sender As Object, ByVal e As EventArgs)
For Each validator As BaseValidator In Validators
If validator.ValidationGroup = sValidationGroup Then
Dim fValid As Boolean = validator.IsValid
Dim CtrlToValidate As String = validator.ControlToValidate
validator.DataBind()
If Not fValid And CtrlToValidate = ServerHandler.UName Then
validator.Validate()
fValid = validator.IsValid
ModelState.AddModelError(CtrlToValidate, validator.ID)
ElseIf Not fValid And CtrlToValidate = "Password" And validator.ID = ServerHandler.PwdRq Then
validator.Validate()
fValid = validator.IsValid
ModelState.AddModelError(CtrlToValidate, validator.ID)
ElseIf Not fValid And CtrlToValidate = "Password" And validator.ID = ServerHandler.PwdRegEx Then
validator.Validate()
fValid = validator.IsValid
ModelState.AddModelError(CtrlToValidate, validator.ID)
End If
End If
Next
End Sub
But has condition that someone or something give him the error list from ValidationSummaryGroup
And this is done with the following code
Public Function LoadModel(ByVal sender As Object, ByVal e As EventArgs) As Boolean
Dim retVal As New Boolean
Try
If Not ModelState.IsValid Then
Dim result As StringBuilder = New StringBuilder()
For Each item In ModelState
Dim key As String = item.Key
Dim errors = item.Value.Errors
For Each [vError] In errors
ModelAnswer.Add(key & "^" & [vError].ErrorMessage)
retVal = True
Next
Next
End If
ModelState.Clear()
Catch ex As Exception
Environment.AssemblyInfo.ErrorAnswer = ServerHandler.ErrHandler.GetError(3, Nothing, Nothing, ex, Nothing)
Environment.AssemblyInfo.ErrorAnswer = Environment.AssemblyInfo.ErrorAnswer & "\r\n ifExistConsistencyRecord "
ServerHandler.ErrProperty._InnerError = Environment.AssemblyInfo.ErrorAnswer
Environment.AssemblyInfo.errorCall = True
retVal = False
End Try
Return retVal
End Function
Of course ModelAnswer is an ArrayList and declared as Public
And all this under the very basic prerequisite, all the processes to work within the main page and NOT in a "class"
Thank you very much for those who helped to solve this puzzle

.NET Framework Data Provider for Oracle multiple open connection

I have the below mentioned code in a seperate class file for establishing connection and carry out DB transactions. I have an issue where multiple connections being opened which sometime exceed the connection pool. When I stepped through the code I found that there are codes which call ConnectDB() in a loop without calling DisconnectDB(). But I expected that the condition OraConn.State = ConnectionState.Closed should handle the situation. Somehow the condition is always satisfied hence openning another set of connection. Can you suggest where am I going wrong and also what best practice can be adopted here?
Public Class Connection
Dim Str_conn As String = "Data Source=...; User=...; password=...; Min Pool Size=10; Max Pool Size=500;"
Public OraConn As OracleConnection
Dim cmd As OracleCommand
Dim dr As OracleDataReader
Dim data_adapt As OracleDataAdapter
Dim dt As DataTable
Dim ds As DataSet
Public Sub ConnectDB()
OraConn = New OracleConnection(Str_conn)
If OraConn.State = ConnectionState.Closed Then
OraConn.Open()
End If
End Sub
Public Sub DisconnectDB()
If OraConn.State = ConnectionState.Open Then
OraConn.Close()
End If
End Sub
Public Function get_dataset(ByVal query As String, ByRef ds As DataSet) As DataSet
data_adapt = New OracleDataAdapter(query, OraConn)
data_adapt.Fill(ds)
Return ds
End Function
Public Function get_datareader(ByVal query As String) As OracleDataReader
cmd = New OracleCommand(query, OraConn)
dr = cmd.ExecuteReader()
Return dr
End Function
Public Sub UpdateDB(ByVal query As String)
cmd = New OracleCommand(query, OraConn)
cmd.ExecuteNonQuery()
cmd.Dispose()
End Sub
The class is refered in other classes or directly in the aspx.vb pages like this.
Public Function InsertData(ByVal var1 As String, ByVal var2 As String) As Integer
conn.ConnectDB()
Dim qryInsert As String
qryInsert = " INSERT INTO TABLE VALUES ('" & var1 & "', "
qryInsert = qryInsert & var2 & "')"
Try
conn.UpdateDB(qryInsert)
Catch ex As OracleException
If ex.Code = 1 Then
updData(var1, var2)
ElseIf ex.Code = 2091 Then
msgprompt("Duplicate Unique Key!", "Warning")
End If
Finally
conn.DisconnectDB()
End Try
Return count
End Function
The connection is again opened in function updData(). While I understand that it has to be closed correctly but keeping tab on every developer is not possible. Hence I want to control it directly from the connection class by using the same connection but the condition If OraConn.State = ConnectionState.Closed is not helping.
UPDATE
I have put the code in UpdateDB under a Using block and removed call to ConnectDB and DisconnectDB from function like InsertData(...). It seems that the issue has been resolved. But I would like to know in case of exception will the connection remain open? and also OraConn is a public variable defined outside Using block so will it be disposed of by the GC?
Public Sub UpdateDB(ByVal query As String)
Using OraConn = New OracleConnection(Str_conn)
cmd = New OracleCommand(query, OraConn)
Try
OraConn.Open()
cmd.ExecuteNonQuery()
Catch ex As Exception
Throw
Finally
cmd.Dispose()
End Try
End Using
End Sub
You must close all the connections as soon as you are done with it, no matter what.
Suggestion:
The best practice for closing the connection is to do it in finally block. So that even if there is any error, catch it (log it if required) in catch block, and then connection will get close in finally block.
UPDATE
You can put one private static counter in your Connection class. When ever ConnectDB() is called you increment this counter and decrement it in every DisconnectDB(). Now in ConnectDB() you check the value of counter, if it exceeds a minimum threshold you throw error, by doing this way; you can come to know idle connection present in your code and refactor it. On production keep this threshold value high or ignore it in code.

Save changes to Entity model to the database

I'm new to Entity Framework and am expanding an existing codebase. I'm using jQuery to pass the needed info back to the server ajaxy style, so I can't use TryUpdateModel(). Here's the code:
<HttpPost()>
Function UpdateRoster() As JsonResult
Dim model As New Models.ViewModels.PlayerAdmin
Dim jsonString As String = Request.Form("json")
model = Deserialise(Of Models.ViewModels.PlayerAdmin)(jsonString)
For Each playerAdminPlayer As Models.ViewModels.PlayerAdminPlayer In model.Roster
Dim playerToTeam As New DAL.PlayersToTeam
Dim player As DAL.Player = PlayerAdminManager.GetPlayerById(playerAdminPlayer.PlayerId)
player.FirstName = playerAdminPlayer.FirstName
PlayerAdminManager.SaveChanges()
Next playerAdminPlayer
Dim playerAfter As DAL.Player = PlayerAdminManager.GetPlayerById(model.Roster.First.PlayerId)
Return Json(New With {.success = False, .message = playerAfter.FirstName})
End Function
Deserialise is a helper function that converts the incoming JSON string to a vb object.
Things seem to work fine in that player successfully loads from the DB and playerAdminPlayer is the correct object from the JSON string. However, when I call PlayerAdminManager.SaveChanges() (which just passes the call the db.SaveChanges() the result is always 0, even if there is a change (not sure if that is expected).
playerAfter was my attempt to see if changes were actually being saved. It seems to work correctly, in that playerAfter.FirstName is the newly updated first name.
PlayerAdminManager.GetPlayerById(integer) pulls from the DB, so I would think that, since changes are observed in playerAfter, that those changes were saved to the DB. However, when I reload the web page (which pulls from the DB), the old values are there.
Any ideas?
Here are some of the functions I mention:
Function GetPlayerById(ByVal Id As Integer) As DAL.Player
Return Container.Players.Where(Function(o) o.PlayerId = Id And o.IsVisible = True).SingleOrDefault
End Function
Sub SaveChanges()
Dim numberOfChanges As Integer = Container.SaveChanges()
Debug.WriteLine("No conflicts. " & numberOfChanges.ToString() & " updates saved.")
End Sub
EDIT
Container code:
Private _Container As DAL.LateralSportsContainer
Protected ReadOnly Property Container As DAL.LateralSportsContainer
Get
If _Container Is Nothing Then
Dim connStr As New System.Data.EntityClient.EntityConnectionStringBuilder
connStr.ProviderConnectionString = Web.Configuration.WebConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString
connStr.Metadata = "res://*/Lateral.csdl|res://*/Lateral.ssdl|res://*/Lateral.msl"
connStr.Provider = "System.Data.SqlClient"
_Container = New DAL.LateralSportsContainer(connStr.ConnectionString)
End If
Return _Container
End Get
End Property
Turns out I was using a non static (shared) Container. I had 2 Manager classes that both inherited from a BaseManager class were the Container was defined. I was executing the query command in one Manager and saving in another.
Doh!

asp.net multithreading with synclock

i have some test code which i run at every load of a page in my asp.net website
this is the code
Sub TryThreads()
Dim t1 = New Thread(AddressOf TryLock)
t1.Priority = ThreadPriority.Lowest
t1.Start()
Dim t2 = New Thread(AddressOf TryLock)
t2.Priority = ThreadPriority.Lowest
t2.Start()
End Sub
Sub TryLock()
Dim LockObject = New Object
SyncLock LockObject
DoTrace("entered locker")
For x = 0 To 10000
Next
DoTrace("exiting locker")
End SyncLock
DoTrace("exited locker")
End Sub
the "dotrace" simply add a record to a log table in the db
now the right result would be that i should have the entries in the db in order "entered","exiting","exited"
but actually when i look in the db i see first 2 "entered" then 2 "exiting" etc.
meaning that the multithreading is working ok, but not the synclock
is that correct?
and how can this be fixed?
the real code will be adding records to the db and might be called from several pages of different sessions, but the same code must not run twice concurrently
i do appreciate anybodys help
thank you very much!!!
EDIT:
in response to Sashas wonderful post i changed my code to a class (it was in a module) and now it looks like this:
Public Class CheckClass
Property LockObject As Object
Get
If HttpRuntime.Cache("CheckSessionsLock") Is Nothing Then HttpRuntime.Cache("CheckSessionsLock") = New Object
Return HttpRuntime.Cache("CheckSessionsLock")
End Get
Set(ByVal value As Object)
If value Is Nothing Then
HttpRuntime.Cache.Remove("CheckSessionsLock")
Else
HttpRuntime.Cache("CheckSessionsLock") = value
End If
End Set
End Property
Sub TryThreads()
Dim t1 = New Thread(AddressOf TryLock)
t1.Priority = ThreadPriority.Lowest
t1.Start()
Dim t2 = New Thread(AddressOf TryLock)
t2.Priority = ThreadPriority.Lowest
t2.Start()
End Sub
Sub TryLock()
SyncLock LockObject
DoTrace("entered locker")
For x = 0 To 10000
Next
DoTrace("exiting locker")
End SyncLock
DoTrace("exited locker")
End Sub
End Class
now it works 80-90% of the time.
on page load i have:
Dim cc = New CheckClass
cc.TryThreads()
if i open multiple pages at once, they still clash some times. but if i'm correct, the issue is now not with the synclock as much as with the httpruntime.cache, because when using a standard property, on one page, the code works 100%.
so how can i make sure that 2 threads, even from totally different sessions never run the trylock simultaneously?
thank you all for helping out
You are creating a new object instance when the TryLock method is called, and use that for locking. If you want mutual exclusion between the two threads, you need to use a common object instance for locking, e.g. a static member of your class or a parameter that you pass to both threads.

Calling a Class in ASP.NET

I know my ASP.NET but i have to admit, i am dumb with classes and not sure how they work exactly. Also have not worked with them yet but i want to. But what I do know is that it's a place where i can keep code for re-use correct? How will my class look with my code?
So this is my code i use on about 3 forms - but i want to save it in 1 spot and just call it from like when i click on btnSubmit.
Dim strConnection As String = ConfigurationManager.ConnectionStrings("ConnectionString").ConnectionString
Dim con As SqlConnection = New SqlConnection(strConnection)
Dim cmd As SqlCommand = New SqlCommand
Dim objDs As DataSet = New DataSet
Dim dAdapter As SqlDataAdapter = New SqlDataAdapter
cmd.Connection = con
cmd.CommandType = CommandType.Text
cmd.CommandText = "SELECT distinct FIELD FROM TABLE order by FIELD"
dAdapter.SelectCommand = cmd
con.Open()
dAdapter.Fill(objDs)
con.Close()
If (objDs.Tables(0).Rows.Count > 0) Then
lstDropdown.DataSource = objDs.Tables(0)
lstDropdown.DataTextField = "FIELD"
lstDropdown.DataValueField = "FIELD"
lstDropdown.DataBind()
lstDropdown.Items.Insert(0, "Please Select")
lstDropdown2.Items.Insert(0, "Please Select")
Else
lblMessage.Text = "* Our Database seem to be down!"
End If
What must i put here to execute my code above?
Protected Sub btnSubmit_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnSubmit.Click
?????????????????????????????????
End Try
End Sub
Etienne
A class is (in VB.Net) is defined as so
Public Class Person
private _firstName as string
private _lastName as string
'''Constructor with no params
public Sub New()
_firstName = ""
_lastName = ""
End Sub
'Contructor with params
Public Sub New(FirstName as String, LastName as String)
_firstName = FirstName
_lastName = LastName
End Sub
Public Property FirstName As String
Get
return _firstName
End Get
Set(value as String)
_firstName = value
End Set
End Property
Public Property LastName As String
Get
return _lastName
End Get
Set(value as String)
_lastName = value
End Set
End Property
Public Function HitHomeRun() As Boolean
....'Do some stuff here
End Function
End Class
You can then instantiate the class and call its members.
Dim p as New Person()
p.FirstName = "Mike"
p.LastName = "Schmidt"
dim IsHomeRunHit As Boolean = p.HitHomeRun()
Learn more about creating and consuming classes in VB.Net.
This is a very big topic and can be defined in many different ways. But typically what you are venturing into is an N-Tier architecture.
Data Access Layer
Business Logic
UI Logic
Now the way a class can be built in your question can be done, but in the long run is prone to maintenance horror and modifiiability is cut short. Not to mention very much prone to bugs. Putting any type of data access code in your UI layer is bad practice.
This is where the power of having separate layers of classes (separation of concerns) in each layer gives you the ability to reuse code and ability to easily modify for future expansions/features etc. This is getting into Software Architecture is a very broad topic to put into one post.
But if you are really interested here are some links to point you into the right directions.
N-Tier Architecture from Wikipedia
Data Access Layer
Business Logic Layer
Martin Fowler is an expert in Architecture
There is software that eases the pain of the DAL.
1. Linq-To-SQL ability to query your data via .Net Objects (compiled queries)
2. Entity Framework Version 2 of Linq-To-SQL
And this effectively could replace all of your SQL code.
If you want to reuse the code, you should put it in a separate project. That way you can add that project to different solutions (or just reference the compiled dll).
In your web project you add a reference to the project (or to the dll if you have compiled it before and don't want to add the project to the solution).
In your new project you add a class file, for example named UIHelper. In the class skeleton that is created for you, you add a method. As the class is in a separate project, it doesn't know about the controls in the page, so you have to send references to those in the method call:
Public Shared Sub PopulateDropdowns(lstDropdown As DropDownList, lstDropdown2 As DropDownList)
... here goes your code
End Sub
In your page you call it with references to the dropdown lists that you have in the page:
UIHelper.PopulateDropdowns(lstDropdown, lstDropdown2)
This will get you started. There is a lot more to learn about using classes...
I sometimes create a "Common" class and put public Shared methods in it that I want to call from different places.
Something along these lines:
Public Class Common
Public Shared Sub MyMethod
'Do things.
End Sub
End Class
I'd then call it using:
Common.MyMethod
Obviously, you can a sub/function definition that takes the parameters you require.
Sorry if my VB.NET code is a bit off. I usually use C#.
I think you should look into using visual studio designer tools to do your data access and data binding. Search for typed datasets

Resources