|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
Table of Contents
IntroductionIn this brief tutorial, we'll look at five different ASP.NET objects we can use to store data. Two of these, the ScopeSince the only difference between all these objects is their scope, it's important to have a clear understanding of exactly what this means. Within the context of this discussion, scope refers to how data inside these objects (or the objects themselves) live for. For example, a user's user ID should exist until he or she logs out, but the new password he or she enters should only exist for the life of the individual request. Scope also refers to the visibility of the data. There're only two types of visibility, data is either available throughout the entire application or for a specific user. An example of this would be the SMTP server name to use when sending an email which should be globally accessible, whereas an email address is specific to an individual user. CommonalityThe above objects all expose their data-storage capabilities via something similar to a //C#
//setting
Application.Add("smtpServer", "127.0.0.1");
Context.Items.Add("culture", new CultureInfo("en-CA"));
Session.Add("userId", 3);
//getting
string smtpServer = (string)Application["smtpServer"];
CultureInfo c = (CultureInfo)Context.Items["culture"];
int userId = (int)Session["userId"];'VB
'setting
Application.Add("smtpServer", "127.0.0.1")
Context.Items.Add("culture", new CultureInfo("en-CA"))
Session.Add("userId", 3)
'getting
Dim smtpServer as string = cstr(Applciation("smtpServer"))
Dim c as CultureInfo = ctype(Context.Items("culture"), CultureInfo)
Dim userId as integer = cint(Session("userId"))
HTTPApplicationThe Worker Process Recycling and Web FarmsWhile it's correct to say that data stored in the Something else to keep in mind is that data stored in the AlternativesThe Web.ConfigIf you require values that are readonly/constants (such as our SMTP server example), consider using the web.config. Unlike values in the ConstantsYou can leverage the Object Oriented nature of ASP.NET and create a utility class with public constants. To be honest, unless you are just mocking something up, I'm not sure why you would ever use this method over using the web.config. It really gives you nothing except for headaches in the long run. HttpCache + (XML | DB)While custom sections in the web.config is definitely the way to go for read-only values, what can we do about read/write values and avoid worker process recycling? The answer is to store values in an XML file or database. While you could do the same thing in classic ASP, you can now leverage a new storage object, the ConclusionIt is my opinion that the usefulness of the HttpCacheThe private DataTable GetStates() {
string cacheKey = "GetStates"; //the key to get/set our cache'd data
DataTable dt = Cache[cacheKey] as DataTable;
if(dt == null){
dt = DataBaseProvider.GetStates();
Cache.Insert(cacheKey, dt, null, DateTime.Now.AddHours(6), TimeSpan.Zero);
}
return dt;
}Private Function GetStates() As DataTable
Dim cacheKey As String = "GetStates" 'the key to get/set our cache'd data
Dim dt As DataTable = CType(Cache(cacheKey), DataTable)
If dt Is Nothing Then
dt = DataBaseProvider.GetStates()
Cache.Insert(cacheKey, dt, Nothing, DateTime.Now.AddHours(6), TimeSpan.Zero)
End If
Return dt
End Function
First thing we do is declare a The important thing to note about the code above is that the processing-heavy data-access code Private Function GetStates(ByVal countryId As Integer) As DataTable
Dim cacheKey As String = "GetStates:" & countryId.ToString()
'the key to get/set our cache'd data
Dim dt As DataTable = CType(Cache(cacheKey), DataTable)
If dt Is Nothing Then
dt = DataBaseProvider.GetStates(countyId)
Cache.Insert(cacheKey, dt, Nothing, _
DateTime.Now.AddHours(6), TimeSpan.Zero)
End If
Return dt
End Function
All I really had to do was add the parameter to my SessionStateSessions exist for the lifetime of a specific user's visit, or until the session timeouts, or you remove it. One thing you probably heard a lot in your ASP days was "don't use sessions", or "sessions are evil". The problem with sessions is how easy they were to use combined with their potentially serious impact on performance, since they were stored in memory. In ASP.NET, you have the choice of storing sessions in memory, in a special service that is part of ASP.NET, or in a SQL database. Having this choice, and using it wisely, makes using sessions in ASP.NET a good thing. You control where sessions are stored via the web.config's <system.web>
<!-- can use a mode of "Off", "InProc", "StateServer" or "SQLServer".
These are CaSe-SeNsItIvE -->
<sessionState mode="InProc" />
...
</system.web>
InProc
StateServer
There are two very important things to keep in mind when using [Serializable()]
public class User {
private int userId;
private string userName;
private UserStatus status;
public int UserId {get { return userId; } set { userId = value; }}
public string UserName {get { return userName; }set { userName = value; }}
public UserStatus Status {get { return status; }set { status = value; }}
public enum UserStatus {
Invalid = 0,
Valid = 1
}
}
To use <sessionState mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424" />
SQL ServerUsing SQL Server is much like using Enabling SQL Server is much like <sessionState mode="SQLServer"
stateConnectionString="Initial Catalog=Session;server=localhsot;uid=sa;pwd=;" />
Additionally, you must run a script to create the database. This script is located in system drive\WINNT\Microsoft.NET\Framework\version\InstallSqlState.sql, for example: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\InstallSqlState.sql on my computer (Windows instead of WinNT because I'm using XP). Simply run it, and you're ready to go. AlternativesConsidering how flexible and powerful sessions are now implemented, there aren't any great alternatives, but here's a list anyways: CookiesCookies behave pretty much the same as sessions, but are stored on the user's computer. This makes them horrible for large data or sensitive information. Additionally, not everyone has cookies enabled (truer and truer with increased privacy concerns). On the flip side, unlike sessions, you can easily use cookies to store information across multiple visits. Cookies used to be a great place to store information you didn't really care if it was kept or not, like a username (hey, if it's there great, the user has one less thing to type. If not, oh well), but most browsers do a better job of this than you can with cookies. QuerystringThe querystring used to be considered a possible alternative to sessions. But again, you can't store large/complex data in them or sensitive information. Additionally, it's a real maintenance nightmare. URL RewritingI won't go into details about URL Rewriting (check out my Localization Tutorial where I explain it briefly). I like using URL Rewriting for simple things such as localization because it needs far less maintenance than using the Querystring, and looks really professional. But just like the cookie or querystring alternative, this won't cut it most of the time. ConclusionAs you can probably tell, sessions in ASP.NET are a lot more useful than they were in classic ASP. The main reason being that you have a good alternative to storing them in memory. But with that comes a bunch of other alternatives: sharing them across web farms (state server/ SQL Server), load balancing (SQL Server), fault tolerance (SQL Server), and a couple of other nice things. Another great feature of sessions in ASP.NET is that they'll work even if the user's browser doesn't support session cookies. This is done by automatically placing the session ID in the querystring, instead of a session cookie. Sure, I just said the QueryString was a bad alternative, but this is automatically done, maintenance free for us! ViewStateYou've probably heard a lot about viewstate and ASP.NET. It's one of the many big-things in ASP.NET. Thankfully (or not depending on how you look at it), I don't plan on going into any details about it, aside for how you can use it as a storage mechanism. For all its glory, the ViewState is a hidden form field. You probably used hidden form fields frequently in classic ASP to track a value between one page and the posted-to page...our usage of the ViewState is no different. Its scope, as you can probably imagine, is for a single user, from one page to another. What some people don't realize about the viewstate is that it isn't some mystical thing that they aren't allowed to touch. You can easily store and retrieve values from and into it: 'VB
Dim pollId As Integer
If Not Page.IsPostBack Then
pollId = getPollId()
viewstate.Add("pollId", pollId)
Else
pollId = CInt(viewstate("pollId"))
End If//C#
int pollId;
if(!Page.IsPostBack){
pollId = getPollId();
ViewState.Add("pollId", pollId);
}else{
pollId = (int)ViewState["pollId"];
}
In the above example, we call an expensive function called ConclusionWhen it comes down to doing similar things to the above example, using the viewstate is a great solution. You could always simply use a hidden form field, or the HttpContextPersonally, I think I've kept the best for last. I think the protected void Application_BeginRequest(Object sender, EventArgs e) {
Context.Items.Add("portal", new Portal(Request.Url));
}
You can then access the instance of the portal throughout the request via: 'VB
Dim portal As Portal= CType(Context.Items("portal"), Portal)
You shouldn't use Another example of using the 'VB
'Fires when the request is first made
Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs)
Context.Items.Add("StartTime", DateTime.Now)
End Sub
'fires at the end of the request
Sub Application_EndRequest(ByVal sender As Object, ByVal e As EventArgs)
Dim startTime As DateTime = CDate(Context.Items("StartTime"))
If DateTime.Now.Subtract(startTime).TotalSeconds > 4 Then
'Log this slow request
End If
End Sub
When the application starts, we store the current time in the context [line: 4]. When the application ends, we retrieve that value [line: 9], compare it to the current time [line: 10], and if it's greater than a certain threshold (4 seconds in this case), we could log some information which might help us identify bottlenecks. ConclusionThere are two reasons I like Going the extra mile by strongly-typingIf there's one thing I dislike about all the above mechanisms, it is that they return objects. At worst, this can lead to run-time errors; at best, it'll give you maintenance problems. The solution is strong-type the object. Look at the code below: Dim currentUser as User = ctype(Session("currentUser"), User)
If currentUser is Nothing Then
'do something, what?
End if
So, what's wrong with the above? First of all, we need to cast the The solution is to wrap this code into a Public Shared ReadOnly Property CurrentUser() As User
Get
Dim _currentUser As User = _
CType(HttpContext.Current.Session("CurrentUser"), User)
If _currentUser Is Nothing Then
_currentUser = New User
HttpContext.Current.Session.Add("CurrentUser", _currentUser)
End If
Return _currentUser
End Get
End Property
I'll explain the whole Dim currentUser as User = User.CurrentUser
There's only one hard coded " Strongly-typing only really makes sense for objects that have a wide scope. The above example is a really good one. But if you find yourself frequently accessing values from one of the above storage objects and repeatedly casting it and doing error checking, consider the above solution. Accessing these objects from the business layerAll of the above objects are readily available to you when programming in code-behind files. You can simply type " Not all your code will be written in code-behind. You'll likely have a bunch of classes (users, groups, portals, sections, roles...), validation objects, and utility classes which don't inherit from It's possible to access the ConclusionHopefully, this tutorial has given you both an overview of these storage objects, as well as some insight to help you chose the right one for the job. It's important to note that we only looked at the storage capabilities of these objects, some of them actually do a lot more (ViewState and Remember to consider alternatives, specifically when looking at the
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||