Figure 22-4Listing 22-5: A serializable object that can be used in the out-of-process Session VB _ Public Class Person Public firstName As String Public lastName As String Public Overri
Trang 1Figure 22-4
Listing 22-5: A serializable object that can be used in the out-of-process Session
VB
<Serializable()> _
Public Class Person
Public firstName As String
Public lastName As String
Public Overrides Function ToString() As String
Return String.Format("Person Object: {0} {1}", firstName, lastName) End Function
End Class
Trang 2[Serializable]
public class Person
{
public string firstName;
public string lastName;
public override string ToString()
{
return String.Format("Person Object: {0} {1}", firstName, lastName);
}
}
Because you put an instance of thePersonclass from Listing 22-5 into theSessionobject that is currently configured asStateServer, you should add a strongly typed property to the basePageclass from Listing 22-3 In Listing 22-6 you see the strongly typed property added Note the cast on the propertyGet, and the strongly typed return value indicating that this property deals only with objects of typePerson
Listing 22-6: Adding a strongly typed property to SmartSessionPage
VB
Public Class SmartSessionPage
Inherits System.Web.UI.Page
Private Const MYSESSIONPERSONKEY As String = "myperson"
Public Property MyPerson() As Person
Get
Return CType(Session(MYSESSIONPERSONKEY), Person) End Get
Set(ByVal value As Person)
Session(MYSESSIONPERSONKEY) = value End Set
End Property
End Class
C#
public class SmartSessionPage : System.Web.UI.Page
{
private const string MYPERSON = "myperson";
public Person MyPerson
{
get
{
return (Person)Session[MYPERSON];
}
set
{
Session[MYPERSON] = value;
}
}
}
Trang 3Now, add code to create a newPerson, populate its fields from the text box, and put the instance into
the now-out-of-process Session State Service Then, retrieve thePersonand write its values out to the
browser using the overloadedToString()method from Listing 22-5
Certain classes in the Framework Class Library are not marked as serializable If
you use objects of this type within your own objects, these objects are not
serializable at all For example, if you include a DataRow field in a class and add
your object to the State Service, you receive a message telling you it ‘‘ is not
marked as serializable’’ because the DataRow includes objects that are not
serializable.
In Listing 22-7, the value of theTextBoxis split into a string array and the first two strings are put into
aPersoninstance For example, if you entered"Scott Hanselman"as a value,"Scott"is put into
Per-son.firstNameand"Hanselman"is put intoPerson.lastName The values you enter should appear
when they are retrieved later inRetrieve.aspxand written out to the browser with the overloaded
ToStringmethod
Listing 22-7: Setting and retrieving objects from the Session using State Service
and a base page
VB — Default.aspx.vb
Partial Class _Default
Inherits SmartSessionPage
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
Dim names As String() names = TextBox1.Text.Split(" "c) ’ " "c creates a char Dim p As New Person()
p.firstName = names(0) p.lastName = names(1) Session("myperson") = p End Sub
End Class
VB — Retrieve.aspx.vb
Partial Class Retrieve
Inherits SmartSessionPage Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
Handles Me.Load Dim p As Person = MyPerson Response.Write(p) ’ ToString will be called!
End Sub
End Class
C# — Default.aspx.cs
public partial class _Default : SmartSessionPage
{
protected void Button1_Click(object sender, EventArgs e)
Trang 4string[] names = TextBox1.Text.Split(’ ’);
Person p = new Person();
p.firstName = names[0];
p.lastName = names[1];
Session["myperson"] = p;
}
}
C# — Retrieve.aspx.cs
public partial class Retrieve : SmartSessionPage
{
protected void Page_Load(object sender, EventArgs e)
{
Person p = MyPerson;
Response.Write(p); //ToString will be called!
}
}
Now, launch the browser, enter your name (or"Scott Hanselman"if you like), click the button to store
it in theSession, and then visitRetrieve.aspxvia the hyperlink You see the result of theToString() method viaResponse.Write, as shown in Figure 22-5
The completed code and techniques shown in Listing 22-7 illustrate a number of best practices for session management:
❑ Mark your objects asSerializableif you might ever use non-In-Proc session state
❑ Even better, do all your development with a local session state server This forces you to discover non-serializable objects early, gives you a sense of the performance and memory usages of asp-net_state.exe, and allows you to choose from any of the session options at deployment time
❑ Use a basePageclass or helper object with strongly typed properties to simplify your code It
enables you to hide the casts made to session keys otherwise referenced throughout your code
These best practices apply to all state storage methods, including SQL session state
SQL-Backed Session State
ASP.NET sessions can also be stored in a SQL Server database InProc offers speed, StateServer offers a resilience/speed balance, and storing sessions in SQL Server offers resilience that can serve sessions to a large Web farm that persists across IIS restarts, if necessary
SQL-backed session state is configured withaspnet_regsql.exe This tool adds and removes
sup-port for a number of ASP.NET features such as cache dependency (see Chapter 23) and
personaliza-tion/membership (see Chapters 17 and 18) as well as session support When you runaspnet_regsql.exe from the command line without any options, surprisingly, it pops up a GUI as shown in Figure 22-6 This utility is located in the NET Framework’s installed directory, usuallyc:\windows\microsoft.net
\framework\2.0 Note that the Framework 3.5 includes additional libraries, but this wizard is still in the 2.0 directory
Trang 5Figure 22-5
The text of the dialog shown in Figure 22-6 contains instructions to runaspnet_regsqlfrom the
com-mand line with a"-?"switch You have a huge number of options, so you’ll want to pipe it through in a
form likeaspnet_regsql -? | more You see the session-state–specific options shown here:
SESSION STATE OPTIONS
-ssadd Add support for SQLServer mode session state
-ssremove Remove support for SQLServer mode session state
-sstype t|p|c Type of session state support:
t: temporary Session state data is stored in the
"tempdb" database Stored procedures for managing session are installed in the "ASPState" database
Data is not persisted if you restart SQL (Default)
Trang 6p: persisted Both session state data and the stored procedures are stored in the "ASPState" database
c: custom Both session state data and the stored procedures are stored in a custom database The database name must be specified
-d <database> The name of the custom database to use if -sstype is
"c"
Figure 22-6
Three options exist for session state support:t,p, andc The most significant difference is that the
-sstype toption does not persist session state data across SQL Server restarts, whereas the-sstype p
option does Alternatively, you can specify a custom database with the-coption and give the database name with-d database
The following command-line example configures your system for SQL session support with the SQL
Server on localhost with ansapassword of wrox and a persistent store in the ASPState database
(Cer-tainly, you know not to deploy your system usingsaand a weak password, but this simplifies the
example Ideally you’d use Windows Integration Authentication and give the Worker Process Identity
access to the ASPState database.) If you’re using SQL Express, replace ‘‘localhost’’ with ‘‘.\SQLEXPRESS’’
If you aren’t using Windows Authentication, you may need to explicitly enable the sa account from the Management Studio, run this tool, and then disable the sa account for security reasons
Trang 7C:\ >aspnet_regsql -S localhost -U sa -P wrox -ssadd -sstype p
Start adding session state
Finished
Next, open up Enterprise Manager and look at the newly created database Two tables are created —
ASPStateTempApplications and ASPStateTempSessions — as well as a series of stored procedures to
support moving the session back and forth from SQL to memory
If your SQL Server has its security locked down tight, you might get an Error 15501 after executing
asp-net_regsql.exethat says ‘‘An error occurred during the execution of the SQL file ’InstallSqlState.sql’.’’
The SQL error number is 15501 and the SqlException message is:
This module has been marked OFF Turn on ’Agent XPs’ in order to be able to access the module If
the job does not exist, an error from msdb.dbo.sp_delete_job is expected
This is a rather obscure message, butaspnet_regsql.exeis trying to tell you that the extended stored
procedures it needs to enable session state are not enabled for security reasons You’ll need to allow them
explicitly To do so, execute the following commands within the SQL Server 2005 Query Analyzer or the
SQL Server 2005 Express Manager:
USE master
EXECUTE sp_configure ’show advanced options’, 1
RECONFIGURE WITH OVERRIDE
GO
EXECUTE sp_configure ’Agent XPs’, 1
RECONFIGURE WITH OVERRIDE
GO
EXECUTE sp_configure ’show advanced options’, 0
RECONFIGURE WITH OVERRIDE
GO
Now, change theweb.config<sessionState>element to use SQL Server, as well as the new connection
string:
<sessionState mode="SQLServer" sqlConnectionString="data source=127.0.0.1;user
id=sa;password=Wrox"/>
The session code shown in Listing 22-7 continues to work as before However, if you open up the
ASPStateTempSessions table, you see the serialized objects Notice in Figure 22-7 that the Session ID from
the trace appears as a primary key in a row in the ASPStateTempSessions table
Figure 22-7 shows theSessionIdas seen in the Request Details of ASP.NET tracing ThatSessionId
appears in theSessionIdcolumn of theASPStateTempSessionstable in theASPStatedatabase just
created Notice also theASPStateTempApplicationstable that keeps track of each IIS application that
may be using the same database to manage sessions
Trang 8If you want to use your own database to store session state, you specify the database name with the-d
<database>switch ofaspnet_regsql.exeand include theallowCustomSqlDatabase="true"attribute and the name of the database in the connection string:
<sessionState allowCustomSqlDatabase="true" mode="SQLServer"
sqlConnectionString="data source=127.0.0.1; database=MyCustomASPStateDatabase;"/>
Figure 22-7
Trang 9The user ID and password can be included in the connection string; or Windows Integrated Security can
be used if the ASP.NET Worker Process’s identity is configured with access in SQL Server
Extending Session State with Other Providers
ASP.NET Session State is built on a new, extensible, provider-based storage model You can implement
custom providers that store session data in other storage mechanisms simply by deriving from
Session-StateStoreProviderBase This extensibility feature also allows you to generate session IDs via your
own algorithms by implementingISessionIDManager
You start by creating a class that inherits fromSessionStateStoreProviderBase The session module
will call methods on any session provider as long as it derives fromSessionStateStoreProviderBase
Register your custom provider in your application’sweb.config, as in the following example:
<sessionState mode ="Custom" customProvider ="WroxProvider">
<providers >
<add name ="WroxProvider" type ="Wrox.WroxStore, WroxSessionSupplier"/>
</providers>
</sessionState>
ASP.NET initializes theSessionStateModule, and these methods are called on any custom
implementation:
❑ Initialize: This method is inherited ultimately fromSystem.Configuration.Provider
.ProviderBaseand is called immediately after the constructor With this method, you set your
provider name and call up to the base implementation ofInitialize
❑ SetItemExpireCallback: With this method, you can register any methods to be called when a
session item expires
❑ InitializeRequest: This method is called by theSessionStateModulefor each request This is
an early opportunity to get ready for any requests for data that are coming
❑ CreateNewStoreData: With this method, you create a new instance ofSessionStateStoreData,
the data structure that holds session items, the session timeout values, and any static items
When a session item is requested, ASP.NET calls your implementation to retrieve it Implement the
following methods to retrieve items:
❑ GetItemExclusive: This method enables you to getSessionStateStoreDatafrom your chosen
store You may have created an Oracle provider, stored data in XML, or stored data elsewhere
❑ GetItem: This is your opportunity to retrieve it as you did inGetItemExclusiveexcept without
exclusive locking You may or may not care, depending on what backing store you’ve chosen
When it’s time to store an item, the following method is called:
❑ SetAndReleaseItemExculsive: Here you should save theSessionStateStoreDataobject to your
custom store
A number of third-party session state providers are available — both open source and for sale
Trang 10ScaleOut Software released the first third-party ASP.NET State Provider in the form
of their StateServer product It fills a niche between the ASP.NET included
singleton StateServer and the SQL Server Database State Provider ScaleOut
Software’s StateServer is an out-of-process service that runs on each machine in the
Web farm and ensures that session state is stored in a transparent and distributed
manner among machines in the farm You can learn more about StateServer and
their ASP.NET 2.0 Session Provider at www.scaleoutsoftware.com/
Another commercial product is StrangeLoop Network’s AppScaler It includes an
ASP.NET Session Provider that plugs into their network acceleration appliance.
Their product also optimizes ViewState among other things and won a ’’Best of
TechEd 2007’’ award Details are at www.strangeloopnetworks.com/
The derivation-based provider module for things such as session state will no doubt continue to create
a rich ecosystem of enthusiasts who will help push the functionality to new places Microsoft did
not expect
Cookieless Session State
In the previous example, the ASP.NET Session State ID was stored in a cookie Some devices don’t sup-port cookies, or a user may have turned off cookie supsup-port in his browser Cookies are convenient because the values are passed back and forth with every request and response That means everyHttpRequest
contains cookie values, and everyHttpResponsecontains cookie values What is the only other thing that
is passed back and forth with everyRequestandResponse? The URL
If you include thecookieless="UseUri"attribute in theweb.config, ASP.NET does not send the
ASP.NET Session ID back as a cookie Instead, it modifies every URL to include the Session ID just before the requested page:
<sessionState mode="SQLServer" cookieless="UseUri" sqlConnectionString="data
source=127.0.0.1;user id=sa;password=Wrox"></sessionState>
Notice that the Session ID appears in the URL as if it were a directory of its own situated between the
actual Web site virtual directory and the page With this change, server-side user controls such as
theHyperLinkcontrol, used in Listing 22-1, have their properties automatically modified The link in
Listing 22-1 could have been hard-coded as HTML directly in the Designer, but then ASP.NET could not modify the target URL shown in Figure 22-8
The Session ID is a string that contains only the ASCII characters allowed in a URL That makes sense
when you realize that moving from a cookie-based Session-State system to a cookieless system requires putting that Session State value in the URL
Notice in Figure 22-8 that the request URL contains a Session ID within parentheses One disadvantage
to cookieless Sessions is how easily they can be tampered with Certainly, cookies can be tampered with using HTTP sniffers, but URLS can be edited by anyone The only way Session State is maintained is if
every URL includes the Session ID in this way.