I am having a really tough time with structuring a Class that is used throughout the application.
The problem is the exact same issue as described here:
Sitecore switches user session with another user
A session variable is being shared by any secondary user that logs in AFTER the first user.
My Class basically assigns a permission level to the session object, so that each page and or control can read it without doing a trip to the DB.
The Class Structure is as follows:
Public NotInheritable Class cPermissions
Public Shared Sub AssignPermissionToSession(ByVal UserID As Integer)
Private Shared Sub SetInSession(key As String, value As Dictionary(Of String, String))
Public Shared Function HasPerm(ByVal ControlName As String) as Boolean
End Class
So to explain the process: User Logs in. The login code calls cPermissions.AssignPermissionToSession(UserID). That Sub calls SetInSession which assigns the permission dictionary to a session object.
As a sidenote, I would prefer a NotInheritable class in this instance as it allows me to shorthand through the code, using the Shared Function HasPerm without instantiating the class. HasPerm reads the session object and returns true or false if the control has permission or not.
So back to the original problem, according to the previous link mentioned at the start, because the Sub is shared, I am experiencing session Hijacking.
But if I don't share the SetInSession sub, the shared sub AssignPermissionsToSession (which login needs to see) cant access it.
So basically I would really appreciate if someone could instruct me how to structure this class correctly without experiencing Accidental Session Hijacking.
Thanks in Advance!
The Code as requested is as follows (shrunk for brevity):
Public NotInheritable Class cPermissions
'local dictionary that gets created, and then assigned to session
Private Shared dPermissions As New Dictionary(Of String, String)
Public Shared Sub AssignPermissionToSession(ByVal UserID As Integer)
dPermissions.Clear()
'Here I open DB and get a list of Roles that each member may have
While ....
BuildPermissionArray()
End While
'Now dPermission should be created assign to session
SetInSession("Permissions", dPermissions)
End Sub
Private Shared Sub BuildPermissionArray()
'Here we create the local Dictionary ready for the session
'So for each role we get each permission for each control ie:
dPermissions.add(control,perm)
End Sub
Private Shared Sub SetInSession(ByVal key As String, value As Dictionary(Of String, String))
If value Is Nothing Then
HttpContext.Current.Session(key) = New Dictionary(Of String, Integer)
Else
HttpContext.Current.Session(key) = value
End If
End Sub
Public Shared Function HasPermission(ByVal PermissionType As Permission, ByVal ControlName As String) As Boolean
Dim obj As Object = HttpContext.Current.Session("Permissions")
Dim d As Dictionary(Of String, String) = DirectCast(obj, Dictionary(Of String, String))
'Here I search the dictionary and check relevant permission for the control name
Return result
End Function
End Class
Now the Login code calls:
cPermissions.AssignPermissionToSession(UserID)
And each page load reads the controls on the current page and calls:
cPermissions.HasPermission(View,"PageOrControlName")
Related
I made a two static classes
NotInheritable Class gObject2
Public Shared TestSyncLock As String = "test"
End Class
NotInheritable Class gObject3
Public Shared TestSyncLock As String = "test"
End Class
Then I have two aspx
Synclock1.aspx:
Public Class SyncLock1
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
SyncLock gObject2.TestSyncLock
Thread.Sleep(10000)
End SyncLock
End Sub
End Class
Synclock2.aspx
Public Class SyncLock2
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
SyncLock gObject3.TestSyncLock
SomeDiv.InnerHtml = "It works"
End SyncLock
End Sub
End Class
When I go to synclock1.aspx it spins for 10 seconds and shows a blank page as expected.
When I go to synclock2.aspx it spits out it works
Everything is good so far.
Now when I go to synclock1.apx and then in another browser got to synclock2.aspx, synclock2.aspx doesn't finish loading until synclock1.aspx finishes.
These are 2 different objects I'm locking with synclock, but it treats them the same. Why is this?
The SyncLockstatement takes an object reference as its argument. As the String type is a reference type, your code is satisfying that constraint. However, due to String Interning in .Net, the literal value equality of the two separate String references is also causing referential equality between gObject2.TestSyncLock and gObject3.TestSyncLock.
From: String.IsInterned Method - Remarks (emphasis added)
The common language runtime automatically maintains a table, called
the intern pool, which contains a single instance of each unique
literal string constant declared in a program, as well as any unique
instance of String you add programmatically by calling the Intern
method.
The intern pool conserves string storage. If you assign a literal
string constant to several variables, each variable is set to
reference the same constant in the intern pool instead of referencing
several different instances of String that have identical values.
Since both gObject2.TestSyncLock and gObject3.TestSyncLock are pointing to the same String reference, SyncLock gObject2.TestSyncLock will block SyncLock gObject3.TestSyncLock.
The subject code is a good example of how string interning can cause unexpected behavior. The article Interning Strings and immutability provides additional details on the mechanics of interning and also provides another example where interning can cause unexpected results.
So the moral of this story is to avoid using strings as the argument for SyncLock. It is safer to use something like the following:
NotInheritable Class gObject2
Public Shared TestSyncLock As New Object
End Class
NotInheritable Class gObject3
Public Shared TestSyncLock As New Object
End Class
I took a div id="DivErr" runat="server"
This is my Web Page written a class within
Public Class ReceiptInv Inherits System.Web.UI.Page
Partial Class MyTimer
Private Sub New()
End Sub
Public Shared timer As New Timer(5000)
' Enable the timer to run
Public Shared Sub StartRuning()
AddHandler timer.Elapsed, AddressOf timer_Elapsed
timer.Start()
End Sub
' This method will be called every 5 seconds
Private Shared Sub timer_Elapsed(ByVal sender As Object, ByVal e As ElapsedEventArgs)
Dim TMR As New ReceiptInv
TMR.DivErr.Visible = False
End Sub
End Class
End Class
I want to make this DivErr visible false in every 5 seconds.
But error in line
TMR.DivErr.Visible = False
NullReferenceException Unhandled By Usercode
Object reference not set to an instance of an Object
Can anyone tell what i am doing wrong ?? Thanks in Advance..
You need to get a real instance of the page, then you can access the controls and properties of it. Since your method is Shared you cannot access controls of the current page's instance (easily).
But you can try to get the page-instance via HttpContext.CurrentHandler.
Private Shared Sub timer_Elapsed(ByVal sender As Object, ByVal e As ElapsedEventArgs)
Dim page = TryCast(HttpContext.CurrentHandler, ReceiptInv)
If page IsNot Nothing Then
page.DivErr.Visible = False
End If
End Sub
However, why does the method need to be shared at all? A Shared timer is shared by all requests!
Apart from that i suspect that you're trying to make a control visible/invisible every 5th second. That won't work this way since you're using a server timer. You could use an ASP.NET-Ajax-Timer instead: http://msdn.microsoft.com/en-us/library/bb386404(v=vs.100).aspx
As I'm self taught my VB coding is not bad but my use of OOP is poor. I'm sure this can be done but I have not found out how yet.
I am building a webforms app which needs to grab data about a user from AD. I have a Person Class which I can use as follows
Public Class _Default
Inherits System.Web.UI.Page
Dim LoggedOnPerson As Person 'Added here so available throughout class
Private strLoggedOnUser As String
Private strADDomain As String
Private strADUserID As String
Public Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
strLoggedOnUser = Request.ServerVariables("LOGON_USER").ToUpper
strADDomain = strLoggedOnUser.Split("\")(0)
strADUserID = strLoggedOnUser.Split("\")(1)
If Not IsPostBack Then
'Dim LoggedOnPerson As Person *** changed to
LoggedOnPerson = New Person
'Get details from AD for logged on user
LoggedOnPerson.GetDetails(strADDomain, strADUserID)
'Store in Session
Session("LoggedOnUser") = LoggedOnUser
'This will now give me access to details such as
'LoggedOnPerson.EmailAddress
'LoggedOnPerson.GivenName
'LoggedOnPerson.TelephoneNo etc.
Else
'Postback so pull in details from Session
LoggedOnUser = Session("LoggedOnUser")
End If
End Sub
End Class
My problem is that I cannot access LoggedOnPerson in other events. e.g.
Public Sub SaveDetails()
Dim email As String = LoggedOnPerson.Email
'This now produces correct result. No error that LoggedOnPerson is not declared
End Sub
I of course get LoggedOnPerson is not declared error. How can I get around this.
You have created the object of "Person" inside Page_Load event. Take it outside and declare at the class level. Also add that object to view state/session state on Page_Load event and typecast it to "Person" class inside other events.
When are Shared (Static) variables created and destroyed. For example have a look at the code below:
Imports System.Data.SqlClient
Public Class Form1
Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Person.testCon = New SqlConnection
Person.Age = 30
Dim p1 As Person
End Sub
End Class
Imports System.Data.SqlClient
Public Class Person
Public Shared testCon As SQLConnection
End Class
The testCon variable is accessible from the Form_Load before the first instance of Person is created. I realise that it is probably not good practice to have a connection as a shared variable but I want to get my point across. I also want to know when variables are created and destroyed if they are primitives (like Person.Age in the example)
Shared variables live for the length of your application, according to Microsoft.
However, object type variables are only instantiated when you tell them to be.
You can verify this behavior by creating a new test class:
Public Class Class1
Sub New()
System.Diagnostics.Debug.Fail("Class Created")
End Sub
End Class
Then create a shared variable for this class as a member variable in another class:
Private Shared m_TestClass As Class1
If you don't access the shared variable, the Debug.Fail statement will not be executed. However, as soon you instantiate this class and assign it, it will be fired (just like any other object):
m_TestClass = New Class1
Shared variables live until the AppDomain they reside in is unloaded.
You could also test this by adding a Finalize statement to the test class with a similar Debug.Fail statement.
The lifetime is one reason that you should use SyncLock when assigning new values to object-type shared variables.
I'm having problems with retrieving multiple instances of a session variable from an InProc session state.
In the following code I persist a simple BusinessObject into a session variable on the Page_Load event. On the click of a button I try to retrieve the object back into 2 new declared instances of the same BusinessObject.
All works great until I change one of the properties in the first instance, it changes the second instance as well.
Is this normal behaviour? I would have thought as these were new instances they wouldn’t demonstrate static behaviour?
Any ideas where I'm going wrong?
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
' create a new instance of a business object and set a containg variable
Dim BO As New BusinessObject
BO.SomeVariable = "test"
' persist to inproc session
Session("BO") = BO
End If
End Sub
Protected Sub btnRetrieveSessionVariable_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnRetrieveSessionVariable.Click
' retrieve the session variable to a new instance of BusinessObject
Dim BO1 As New BusinessObject
If Not Session("BO") Is Nothing Then BO1 = Session("BO")
' retrieve the session variable to a new instance of BusinessObject
Dim BO2 As New BusinessObject
If Not Session("BO") Is Nothing Then BO2 = Session("BO")
' change the property value on the first instance
BO1.SomeVariable = "test2"
' why has this changed on both instances?
Dim strBO1Property As String = BO1.SomeVariable
Dim strBO2Property As String = BO2.SomeVariable
End Sub
' simple BusinessObject class
Public Class BusinessObject
Private _SomeVariable As String
Public Property SomeVariable() As String
Get
Return _SomeVariable
End Get
Set(ByVal value As String)
_SomeVariable = value
End Set
End Property
End Class
your BO1 and BO2 are the same object
BO1 is a name that references some area in memory;
BO2 is another name that references the SAME area of memory; Session("BO") references the SAME area of memory.
To truly create different objects BO1 and BO2, you should create a copy of the object - for example implement Clone() method in your business object class.
You're instantiating two new objects, and then setting each of them to be the same object (i.e. the one from session), so your behaviour is exactly as you would expect.
Incidentally, you may wish to consider how your page would perform if a user opens two of these pages in a tab - will your business object in the session then cause you some problems?