Syntax to change the value of a cached object property - asp.net

In an ASP.NET 3.5 VB web app, I successfully manage to cache an object containing several personal details such as name, address, etc. One of the items is CreditNum which I'd like to change in the cache on the fly. Is there a way to access this directly in the cache or do I have to destroy and rebuild the whole object just to change the value of objMemberDetails.CreditNum?
The cache is set using:
Public Shared Sub CacheSet(ByVal key As String, ByVal value As Object)
Dim userID As String = HttpContext.Current.User.Identity.Name
HttpContext.Current.Cache(key & "_" & userID) = value
End Sub

Besides that this answer might help; Cache is really there to help you add, read, and drop the objects that your app requires frequently.

Related

Referencing other aspx controls events in a module

For an ASP.Net application using VB how can I reference an event or textbox not located within the same file.
For example when you are coding on say Default.aspx and you put a textbox on the page this works to reference it.
Dim username As String
username = Textbox1.Text
Ok but now I want to get the values and response and process it (amongst other tasks) in a separate module say security.vb.
how can I effectively call it from security.vb so it says username = "Default.aspx".Textbox1.Text
i have tried many versions to achieve this and Google'd but I don't know the correct terms to search so am not getting a good result.
The closest Stack question is Reference from Module but that doesn't have an answer. I know this must be so simple but it eludes me.
Another "module"? You're not using classes? Using classes would make this easy:
In Default.aspx.vb
username = Textbox1.Text
Dim security As New Security(username)
In Security.vb:
Public Sub New(ByVal username as String)
Me.username = username
End Sub
Private username as String
Then you can access the username variable in your Security class whenever you need it. (Note that since the username variable is not declared as Shared, it will only be valid for the current instance of the Security class that you created in Default.aspx.vb. You could make it Shared, but that would be a bad idea on a web server, since if you did, that would mean that only one user could be logged in at a time, and whenever Bob logs in, Alice's session suddenly starts displaying Bob's data!)

Public Shared Variable Shared Between Users?

I've taken over the maintenance of the website (ASP.NET VB) and on one particular page I noticed the below code
Inherits System.Web.UI.Page
Public Shared UserNumber As String
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
UserNumber = Session("UserNumber")
...
End Sub
My question is whether the variable UserNumber can be accessed or changed by any other user than the current one?
Many thanks
A Shared variable is the same as a static variable in C#.
These can be shared across all instances, therefore different users would share the same variable.
Looking at the variable name, I would assume you would need to remove this Shared
You are applying a Session variable value to the Shared String on Page_Init.
Therefore each time the user loads the page, their session variable will override the current value.
If you are not using this variable outside of this class, then I would recommend changing it to:
Protected UserNumber As String
EDIT My initial answer was incorrect. Trying again...
Technically, as #Curt indicated, a Shared variable is shared across instances of the class.
However, with the code as is, it is less likely that the value will be shared amongst users as it is set to each user's local copy of the value in their Session in Page_Init.
There is a possible "race condition" where after the shared variable UserNumber has been initialised in Page_Init, and another user submits a request which updates the value of that variable from their session, the first user will then see the second user's value. i.e. users can see other user's values for concurrent requests.
Instead, I recommend using a ReadOnly non-shared property to get the value from the Session once:
Private mUserNumber As String
Public ReadOnly Property UserNumber As String
Get
If String.IsNullOrEmpty(mUserNumber) Then
mUserNumber = Session("UserNumber")
End If
Return mUserNumber
End Get
End Property
This uses a pattern called "Lazy-loading", which I use in read-only properties a lot on pages to improve performance and readability of code.

Sql data reader in classes

Hi
On several pages of our website, I want to check if the currently logged in user has accepted our terms and conditions in the past. This boolean value is stored in the application database. Rather than creating a sql data reader afresh on each relevant page, I thought I could put it in a class and then assign the true/false to a variable. This is what I have so far and it does exactly what I want it to:
Public Shared ReadOnly Property termsCompleted As String
Get
Dim selectTerms As String = "SELECT Terms FROM tblPersonal WHERE Ref=#Ref"
Dim dbconn As String = ConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString
Using myConnection As New SqlConnection(dbconn)
myConnection.Open()
Dim cmdTerms As New SqlCommand(selectTerms, myConnection)
cmdTerms.Parameters.AddWithValue("#Ref", myUser.ToString())
Dim readerTerms As SqlDataReader = cmdTerms.ExecuteReader()
readerTerms.Read()
termsCompleted = readerTerms.Item(0)
readerTerms.Close()
myConnection.Close()
End Using
End Get
End Property
I am them using the following on each page that is relevant to deny access and redirect (in the page_load):
If Variables.termsCompleted = False Then
Response.Redirect("Terms.aspx")
End If
While this works ok, i'm interested in how secure it is, and is there a better way to do this?
Thanks
Have you considered retrieving the information once during Session_Start, and carrying it around in Session so that you can interrogate it any time you want?
If you can't retrieve the data during authentication/authorization, you would retrieve the data in the same way as you show above.
To put the value into Session: Session["termsCompleted"] = "true";
To read the value from Session: if (Session["termsCompleted"] == "true")....
As an alternative, you could add the information to HttpContext.Current.User.
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' Code that runs when a new session is started
Dim selectTerms As String = "SELECT Terms FROM tblPersonal WHERE Ref=#Ref"
If Request.IsAuthenticated = True Then
Dim dbconn As String = ConfigurationManager.ConnectionStrings("ApplicationServices").ConnectionString
Using myConnection As New SqlConnection(dbconn)
myConnection.Open()
Dim cmdTerms As New SqlCommand(selectTerms, myConnection)
cmdTerms.Parameters.AddWithValue("#Ref", Variables.myUser)
Dim readerTerms As SqlDataReader = cmdTerms.ExecuteReader()
readerTerms.Read()
Session("termsCompleted") = readerTerms.Item(0)
readerTerms.Close()
myConnection.Close()
End Using
End If
End Sub
And in the code-behind:
If Session("termsCompleted") = False Then
Response.Redirect("Terms.aspx")
End If
Unfortunately this is redirecting to the terms.aspx page every time regardless of what is in the database. From debugging it's picking up the reader item as 'False' even when it's true..
Thanks
Create a base page and have each page inherit from that. In this base page you can do the data access once to perform this check. Then store it in session state.
I don't think you have a security issue...I think it's more of a best practice issue. It's not good practice to put your data access requests in a property. In projects I work on, I typically will have a class that has functions that handle my data access with a buisiness layer that makes the calls to my data access. An n-tier project design may not fit your project...I'm just speaking from my experience.
If you need to reuse the bit flag, just store it in Session.
This logic doesn't really belong on a page. If accepting the terms of use is a requirement for accessing parts of your site then you should handle it that way. This problem is a very similar situation to having an administrator section of a site that only a few users can access.
Ideally this is something you would handle before the request gets to the page. There are (at least) two ways to approach this.
You could write a custom HTTP module that subscribes to the AuthorizeRequest event. It will check whether this page requires that you accept terms of agreement or not and if so checks to see if the user has or not. If not it will redirect the user to the terms of use page.
The other option is to put this code into your Global.ascx file. You would want to subscribe to the AuthorizeRequest event and perform your logic there.
I don't think it matters which option you chose (though the second one may be a little more straight forward to implement). The benefit is that this concern is handled outside of the page itself. This way as you add new pages to your site, you can't forget to add your validation code to it. If you ever decide that in addition to accepting terms of agreement users need to do something else, you now have one place to change instead of going through all of the pages, etc.
You should also take advice of some of the other answers and store this value into the Session to avoid having to to do a database request every time a page loads.
More information:
Http Modules and handlers
How To Create an ASP.NET HTTP Module Using Visual C# .NET (VB should be the same concept with VB syntax).
Application, Page and Control lifecycle (to help you better understand how ASP.NET application lifecycle works and what else is possible).

ASP.NET WebForms -- Processing special query-string parameters across all pages on a site -- URL Rewriting, URL Routing, or other approaches?

Working on an ecommerce site which will be integrated with a 3rd party vendor--that vendor uses different identifiers for stores than we use internally (i.e. their store ABC123 is our 001-321).
I'm researching the best approach to inspect incoming requests for reserved query-string parameters that indicate the request is using their identifiers and map the identifiers back to our identifiers (so if the request is example.com/&theirId=ABC123 I want to transform the request to example.com/&ourId=001-321).
To do this mapping I need to inspect the provided ID, execute a lookup against the database or cache, and forward the request to the specified page--limiting the modifications to just the query-string parameters (other parameters will need to be maintained, as with the details of the HTTPHeader, etc).
So far I'm researching a few different approaches:
Implementing it in a base Page (which already does too much, but has the benefit of our Logging infrastructure and some other injected dependencies)
Implementing it in an IHttpModule
Using URL Rewriting
Using URL Routing (looks like routing isn't what I want, feel free to offer insight if you think it still fits)
Performance cost is a consideration: the actual number of times this translation will occur will be very small compared to the number of requests not requiring it--perhaps 1%.
However for another integrated site we will perform this mapping on nearly every request--would a different approach be better suited to this scenario from the previous?
This is a classic case where a HTTP module makes the most sense--you wish to dive into the URL handling on all requests. Perf-overhead-wise you shouldn't have that much of an issue presuming you can short-circuit things correctly and avoid doing DB/cache lookups where you don't need.
Configuration-wise, you should already have to solve the problem of deploying and managing your configuration, so I doubt if another custom module adds much overhead.
Code-wise, its generally better to favor composition over inheritance--you can add or remove the module as required--but having code statically included into a bloated base page class can create more challenges.
I have implemented something similar to this as a base page class for my aspx pages, but as you mentioned a module would work as well. In my opinion, if this functionality is needed across all pages I would just crate a base class only because maintaining another http-module is more of a pain because it needs to be mapped in your web config / iis. Url rewriting is cpu intensive and may not provide you the flexibility you need - again it just adds another configuration / iss dependency. I don't think either of these are going to incur much overhead as long as you implement some sort of caching.
Hope this helps...
Enjoy!
I usually create a Singleton class to hold the site's request context, and store it in the HttpContext.Current.Items(). I initialize this class in the Application_BeginRequest routine.
Imports System.Web
Public Class SiteContext
Private _viewId As Int32
Private _tab As String
Private _action As String
Private Sub New()
_viewId = -1
_tab = String.Empty
_action = String.Empty
FillContext()
End Sub
Public Shared Function Instance() As SiteContext
' gets the site specific context for the current request
If HttpContext.Current.Items("RequestContext") Is Nothing Then
HttpContext.Current.Items("RequestContext") = New SiteContext
End If
Return HttpContext.Current.Items("RequestContext")
End Function
' fill the request context with site specific items
Private Sub FillContext()
' iterate through all items passes via the querystring and save values to matching key property names
For i As Int16 = 0 To _context.Request.QueryString.Count - 1
Dim qryItem As String = _context.Request.QueryString.Keys.Item(i)
Select Case qryItem
Case "v", "view", "viewid", "vid" ' VIEW ID
If IsNumeric(_context.Request.QueryString(qryItem)) AndAlso CType(_context.Request.QueryString(qryItem), Double) < 10000 Then
_viewId = CType(_context.Request.QueryString(qryItem), Int32)
End If
Case "tab" ' TAB ID; secondary parameter to choose sub view
_tab = _context.Request.QueryString(qryItem)
Case "action" ' ACTION ID; tertiary parameter to choose sub-sub view
_action = _context.Request.QueryString(qryItem)
Case Else
End Select
Next
End Sub
Public Property ViewId() As Int32
Get
Return _viewId
End Get
Set(ByVal Value As Int32)
If Value < 1 Then
Value = 1
End If
_viewId = Value
End Set
End Property
Public Property Tab() As String
Get
Return _tab
End Get
Set(ByVal Value As String)
_tab = Value.Trim
End Set
End Property
Public Property Action() As String
Get
Return _action
End Get
Set(ByVal Value As String)
_action = Value.Trim
End Set
End Property
End Class

How can i preserve list contents on postbacks?

On the page load event of my webpage i fill the list of with the contents of the structure
Structure MainStruct
Dim Ans1 As String
Dim Ans2 As String
End Structure
Dim Build As New List(Of MainStruct)
The problem i that on post-back the contents of the list-of get lost.
So, how can i preserve the contents of the list-of in ASP.NET?
You can either put it in a session or a viewstate in case you donot wish to keep in a storage like database or a ASP.net cache. Of course, you shall have to be careful if you keep it in session as you shall have to clean it up as soon as you go out of scope. Also, serialising/deserialising will be another angle. Can't you have some global cache or so for your app?

Resources