做者: Stephen Walther
原文地址:http://msdn.microsoft.com/asp.net/default.aspx?pull=/library/en-us/dnvs05/html/UserProfiles.asp
譯者:Tony Qu
html
概要:許多ASP.NET應用程序須要跨訪問的用戶屬性跟蹤功能,在ASP.NET1.1中,咱們只能人工實現這一功能。但現在,使用 ASP.NET 2.0的Profile對象,這個過程變得異常簡單。Stephen Walther將驗證該對象,並向你展現如何使用Profile來跟蹤用戶屬性、建立一個購物籃,及其餘一些例子。
web
總目錄
介紹
User Profile總攬
定義User Profile
使用Profile組
使用複雜的Profile屬性
繼承一個Profile
遷移匿名Profile設置
配置Profile Provider
管理Profiles並生成Profile報告
總結
相關書籍
sql
Microsoft ASP.NET 2.0支持被稱爲Profile的新對象,它能夠自動在多個Web應用程序的訪問之間存儲用戶信息。一個User Profile中能夠存儲各類類型的信息,這些信息既能夠是簡單的string和integer類型,也能夠是複雜的自定義類型。例如,你能夠存儲用戶的 姓、購物籃、用戶屬性或網站使用狀況統計。
本文中,你將學習如何在一個應用中定義user profile。咱們也會向你演示如何配置使用不一樣provider的profile。最後,你將學習如何管理和生成user profile的報告。
數據庫
User Profiles總攬
Profile 對象與Session對象十分類似,可是更好用一些。與Session類似的地方在於,Profile是相對於一個特定的用戶的,也就是說,每一個Web應 用程序的用戶都有他們本身的profile對象。與Session不一樣的是,Profile對象是持久對象。若是你向Session中添加一個項,在你離 開網站時,該項就會消失。而Profile則徹底不一樣,當你修改Profile的狀態時,修改在多個訪問之間均有效。
express
profile使用provider模式來存儲信息,默認狀況下,user profile的內容會保存在SQL Server Express數據庫中,該數據庫位於網站的App_Data目錄。然而,在本文的後半部分,你將瞭解如何使用其餘數據提供者(data provider)來存儲信息,如完整版的SQL Server中的一個數據庫或者一個Oracle數據庫。c#
與Session不一樣,Profile是強類型的,Session對象僅僅是一個項集合而已,而profile對象則有強類型屬性。
使用強類型是有它的道理的。例如,使用強類型,你就能夠在Microsoft Visual Web Developer中使用智能感知技術,當你鍵入Profile和一個點的時候,智能感知會彈出你已經定義過的profile屬性列表。
瀏覽器
定義user profile
你既能夠在 machine.config中,也能夠在web.config中定義一個user profile,因爲你不能在應用程序的二級目錄中建立一個包含文件profile節的web.config文件,這意味着你將沒法在一個應用程序中定義 兩個以上的profile。
在列表1的web.config中,列舉了一個簡單的profile定義的實例,該profile有三個屬性,FirstName, LastName和PageVisits。
服務器
列表1
<configuration>
<system.web>
<authentication mode="Forms" />
<anonymousIdentification enabled="true" />
<profile>
<properties>
<add
name="FirstName"
defaultValue="??"
allowAnonymous="true" />
<add
name="LastName"
defaultValue="??"
allowAnonymous="true" />
<add
name="PageVisits"
type="Int32"
allowAnonymous="true"/>
</properties>
</profile>
</system.web>
</configuration>cookie
因爲該profile須要同時被匿名用戶和已認證用戶使用,所以咱們在web.config文件中增長包含一個< anonymousIdentification>元素,有了這個元素,系統就會自動爲匿名用戶生成惟一的ID。仔細看的話咱們會發現,每個 profile屬性都有一個allowAnonymous特性,該特性代表這個profile屬性是否容許被匿名用戶使用。
框架
默認的profile屬性類型是System.String類型。列表1中,因爲沒有爲FirstName和LastName這兩個profile屬性增 加type特性,那麼系統默認它們是string類型,而PageVisits屬性則指定了type特性爲Int32,所以該profile屬性可用於表 示一個整型值。
最後,注意FirstName和LastName屬性都有defaultValue特性。你能夠爲簡單的數據類型設置defaultValue特性,但你不能爲複雜類型設置defaultValue特性。
當你定義好一個profile以後,系統會自動在下一次頁面被調用時,生成一個與該profile相對應的類。這個類會被保存在"Temporary ASP.NET Files Directory"目錄(該目錄也用於存放用於動態生成頁面的類)。你可使用HttpContext的Profile屬性(Property)調用該 類。
當你定義好一個profile後,你可使用以下方法爲profile屬性賦值。
[Visual Basic .NET]
Profile.FirstName = "Bill"
[C#]
Profile.FirstName = "Bill";
任何在web.config中定義的profile屬性都會在Profile對象中呈現。
列表2演示了你該如何使用profile來持 久化保存用戶信息。這個頁顯示了FirstName,LastName, PageVisits三個屬性的值,同時它包含了一個可以用於修改這三個屬性的表單(form)。在Page_Load中更新PageVisits的值, 這意味着每一次刷新頁面,PageVisits的值都會改變。
圖1 使用簡單的profile
列表 2. Simple.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load()
Profile.PageVisits += 1
End Sub
Sub UpdateProfile(ByVal s As Object, ByVal e As EventArgs)
Profile.FirstName = txtFirstName.Text
Profile.LastName = txtLastName.Text
End Sub
</script>
<html>
<head>
<title>Simple</title>
</head>
<body>
<form id="form1" runat="server">
<b>Name:</b> <%= Profile.FirstName %> <%= Profile.LastName %>
<br />
<b>Page Visits:</b> <%= Profile.PageVisits %>
<hr />
<b>First Name:</b>
<asp:TextBox ID="txtFirstName" Runat="Server" />
<br />
<b>Last Name:</b>
<asp:TextBox ID="txtLastName" Runat="Server" />
<br />
<asp:Button
Text="Update Profile"
OnClick="UpdateProfile"
Runat="server" />
</form>
</body>
</html>
列表 2. Simple.aspx (C#)
<%@ Page Language="C#" %>
<script runat="server">
void Page_Load() {
Profile.PageVisits ++;
}
void UpdateProfile(Object s, EventArgs e) {
Profile.FirstName = txtFirstName.Text;
Profile.LastName = txtLastName.Text;
}
</script>
<html>
<head>
<title>Simple</title>
</head>
<body>
<form id="form1" runat="server">
<b>Name:</b> <%= Profile.FirstName %> <%= Profile.LastName %>
<br />
<b>Page Visits:</b> <%= Profile.PageVisits %>
<hr />
<b>First Name:</b>
<asp:TextBox ID="txtFirstName" Runat="Server" />
<br />
<b>Last Name:</b>
<asp:TextBox ID="txtLastName" Runat="Server" />
<br />
<asp:Button ID="Button1"
Text="Update Profile"
OnClick="UpdateProfile"
Runat="server" />
</form>
</body>
</html>
若是你屢次訪問列表2中的頁面,你會注意到PageVisits在不斷增大。若是你關閉的瀏覽器,並在一週以後調用該頁面,PageVisits屬性仍然會保留原值。從這一點能夠看出Profile爲每一個用戶自動保存一個副本。
使用Profile組
儘管你僅能夠爲一個應用程序定義一個profile,但若是你須要讓幾個profile屬性一塊兒工做,把它們放在組中,會讓你以爲它們更易管理。
例如,在列表3中,有一個帶有兩個組的profile,這兩個組分別是Address和Preferences
列表3. Web.Config
<configuration>
<system.web>
<anonymousIdentification enabled="true" />
<profile>
<properties>
<group name="Address">
<add
name="Street"
allowAnonymous="true" />
<add
name="City"
allowAnonymous="true" />
</group>
<group name="Preferences">
<add
name="ReceiveNewsletter"
type="Boolean"
defaultValue="false"
allowAnonymous="true" />
</group>
</properties>
</profile>
</system.web>
</configuration>
當你用組來定義profile時,你應該使用組名來設置或讀取profile屬性。例如,在列表3中,你可使用如下一些句子來完成三個profile屬性的賦值。
[Visual Basic .NET]
Profile.Address.City = "Modesto"
Profile.Address.Street = "111 King Arthur Ln"
Profile.Preferences.ReceiveNewsletter = False
[C#]
Profile.Address.City = "Modesto";
Profile.Address.Street = "111 King Arthur Ln";
Profile.Preferences.ReceiveNewsletter = false;
一個profile的定義只能包含一層組,換句話說,你不能把其餘的組放在一個profile組的下面一層。
使用複雜的profile屬性
到目前爲止,咱們已經介紹了聲明包含簡單類型(如string或整型)屬性的profile,其實你也能夠在profile中聲明覆雜屬性。
舉個例子,假設你如今須要在profile中存儲一個購物籃,若是這樣作的話,你就能夠在每次訪問網站時得到本身的購物籃。
列表4 聲明瞭一個包含profile,這個profile包含一個名爲ShoppingCart的屬性,而該屬性的type特性是一個叫ShoppingCart的類(咱們接下來會建立該類),該類名是有效的。
咱們還會注意到,該聲明中包含一個serializeAs特性,該特性能夠幫助ShoppingCart使用二進制序列化器(binary serializer)進行持久化,而不是使用xml序列化器。
列表4 Web.config
<configuration>
<system.web>
<anonymousIdentification enabled="true" />
<profile>
<properties>
<add
name="ShoppingCart"
type="ShoppingCart"
serializeAs="Binary"
allowAnonymous="true" />
</properties>
</profile>
</system.web>
</configuration>
列表5 中有一個簡單購物籃的實現代碼,該購物籃擁有添加和刪除項(item)的方法(method),同時它還擁有兩個屬性(property),一個是用於得到該購物籃中的全部項的,一個是用於表示全部商品的總價的。
列表5 ShoppingCart (Visual Basic.NET)
Imports Microsoft.VisualBasic
<Serializable()> _
Public Class ShoppingCart
Public _CartItems As New Hashtable()
' Return all the items from the Shopping Cart
Public ReadOnly Property CartItems() As ICollection
Get
Return _CartItems.Values
End Get
End Property
' The sum total of the prices
Public ReadOnly Property Total() As Decimal
Get
Dim sum As Decimal
For Each item As CartItem In _CartItems.Values
sum += item.Price * item.Quantity
Next
Return sum
End Get
End Property
' Add a new item to the shopping cart
Public Sub AddItem(ByVal ID As Integer, _
ByVal Name As String, ByVal Price As Decimal)
Dim item As CartItem = CType(_CartItems(ID), CartItem)
If item Is Nothing Then
_CartItems.Add(ID, New CartItem(ID, Name, Price))
Else
item.Quantity += 1
_CartItems(ID) = item
End If
End Sub
' Remove an item from the shopping cart
Public Sub RemoveItem(ByVal ID As Integer)
Dim item As CartItem = CType(_CartItems(ID), CartItem)
If item Is Nothing Then
Return
End If
item.Quantity -= 1
If item.Quantity = 0 Then
_CartItems.Remove(ID)
Else
_CartItems(ID) = item
End If
End Sub
End Class
<Serializable()> _
Public Class CartItem
Private _ID As Integer
Private _Name As String
Private _Price As Decimal
Private _Quantity As Integer = 1
Public ReadOnly Property ID() As Integer
Get
Return _ID
End Get
End Property
Public ReadOnly Property Name() As String
Get
Return _Name
End Get
End Property
Public ReadOnly Property Price() As Decimal
Get
Return _Price
End Get
End Property
Public Property Quantity() As Integer
Get
Return _Quantity
End Get
Set(ByVal value As Integer)
_Quantity = value
End Set
End Property
Public Sub New(ByVal ID As Integer, _
ByVal Name As String, ByVal Price As Decimal)
_ID = ID
_Name = Name
_Price = Price
End Sub
End Class
列表5 ShoppingCart (c#)
using System;
using System.Collections;
[Serializable]
public class ShoppingCart
{
public Hashtable _CartItems = new Hashtable();
// Return all the items from the Shopping Cart
public ICollection CartItems
{
get { return _CartItems.Values; }
}
// The sum total of the prices
public decimal Total
{
get
{
decimal sum = 0;
foreach (CartItem item in _CartItems.Values)
sum += item.Price * item.Quantity;
return sum;
}
}
// Add a new item to the shopping cart
public void AddItem(int ID, string Name, decimal Price)
{
CartItem item = (CartItem)_CartItems[ID];
if (item == null)
_CartItems.Add(ID, new CartItem(ID, Name, Price));
else
{
item.Quantity++;
_CartItems[ID] = item;
}
}
// Remove an item from the shopping cart
public void RemoveItem(int ID)
{
CartItem item = (CartItem)_CartItems[ID];
if (item == null)
return;
item.Quantity--;
if (item.Quantity == 0)
_CartItems.Remove(ID);
else
_CartItems[ID] = item;
}
}
[Serializable]
public class CartItem
{
private int _ID;
private string _Name;
private decimal _Price;
private int _Quantity = 1;
public int ID
{
get { return _ID; }
}
public string Name
{
get { return _Name; }
}
public decimal Price
{
get { return _Price; }
}
public int Quantity
{
get { return _Quantity; }
set { _Quantity = value; }
}
public CartItem(int ID, string Name, decimal Price)
{
_ID = ID;
_Name = Name;
_Price = Price;
}
}
若是你把列表5中的代碼添加到應用程序的App_Code目錄中,購物籃會自動被編譯。
在列表5中有一點值得注意,那就是ShoppingCart和CartItem類都加上了可序列化的特性,這一點對於他們可否被序列化十分重要,只有這樣才能保存在Profile對象中。
最後,列表6的頁面顯示了能夠被添加到購物籃中的產品。購物籃是經過BindShoppingCart方法從Profile對象中載入,該方法把購物籃中的對象綁定到一個GridView對象上,這些對象能夠經過ShoppingCart類的CartItems屬性得到。
圖2 在profile中存儲購物籃
AddCartItem方法用於在購物籃中添加一個產品,該方法中包含了檢測Profile是否存在ShoppingCart的代碼。對於Profile中存儲的對象,你必須本身實例化這些對象,他們不會自動實例化。
RemoveCartItem方法用於從購物籃中移除一個產品,該方法只是簡單地經過調用Profile中的ShoppingCart對象的RemoveItem方法。
列表 6 - Products.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load()
If Not IsPostBack Then
BindShoppingCart()
End If
End Sub
Sub BindShoppingCart()
If Not Profile.ShoppingCart Is Nothing Then
CartGrid.DataSource = Profile.ShoppingCart.CartItems
CartGrid.DataBind()
lblTotal.Text = Profile.ShoppingCart.Total.ToString("c")
End If
End Sub
Sub AddCartItem(ByVal s As Object, ByVal e As EventArgs)
Dim row As GridViewRow = ProductGrid.SelectedRow
Dim ID As Integer = CInt(ProductGrid.SelectedDataKey.Value)
Dim Name As String = row.Cells(1).Text
Dim Price As Decimal = CDec(row.Cells(2).Text)
If Profile.ShoppingCart Is Nothing Then
Profile.ShoppingCart = New ShoppingCart
End If
Profile.ShoppingCart.AddItem(ID, Name, Price)
BindShoppingCart()
End Sub
Sub RemoveCartItem(ByVal s As Object, ByVal e As EventArgs)
Dim ID As Integer = CInt(CartGrid.SelectedDataKey.Value)
Profile.ShoppingCart.RemoveItem(ID)
BindShoppingCart()
End Sub
</script>
<html>
<head>
<title>Products</title>
</head>
<body>
<form id="form1" runat="server">
<table width="100%">
<tr>
<td valign="top">
<h2>Products</h2>
<asp:GridView
ID="ProductGrid"
DataSourceID="ProductSource"
DataKeyNames="ProductID"
AutoGenerateColumns="false"
OnSelectedIndexChanged="AddCartItem"
ShowHeader="false"
CellPadding="5"
Runat="Server">
<Columns>
<asp:ButtonField
CommandName="select"
Text="Buy" />
<asp:BoundField
DataField="ProductName" />
<asp:BoundField
DataField="UnitPrice"
DataFormatString="{0:c}" />
</Columns>
</asp:GridView>
<asp:SqlDataSource
ID="ProductSource"
ConnectionString=
"Server=localhost;Database=Northwind;Trusted_Connection=true;"
SelectCommand=
"SELECT ProductID,ProductName,UnitPrice FROM Products"
Runat="Server" />
</td>
<td valign="top">
<h2>Shopping Cart</h2>
<asp:GridView
ID="CartGrid"
AutoGenerateColumns="false"
DataKeyNames="ID"
OnSelectedIndexChanged="RemoveCartItem"
CellPadding="5"
Width="300"
Runat="Server">
<Columns>
<asp:ButtonField
CommandName="select"
Text="Remove" />
<asp:BoundField
DataField="Name"
HeaderText="Name" />
<asp:BoundField
DataField="Price"
HeaderText="Price"
DataFormatString="{0:c}" />
<asp:BoundField
DataField="Quantity"
HeaderText="Quantity" />
</Columns>
</asp:GridView>
<b>Total:</b>
<asp:Label ID="lblTotal" Runat="Server" />
</td>
</tr>
</table>
</form>
</body>
</html>
列表 6. Products.aspx (C#)
<%@ Page Language="C#" %>
<%@ Import Namespace="System.Globalization" %>
<script runat="server">
void Page_Load() {
if (!IsPostBack)
BindShoppingCart();
}
void BindShoppingCart()
{
if (Profile.ShoppingCart != null)
{
CartGrid.DataSource = Profile.ShoppingCart.CartItems;
CartGrid.DataBind();
lblTotal.Text = Profile.ShoppingCart.Total.ToString("c");
}
}
void AddCartItem(Object s, EventArgs e)
{
GridViewRow row = ProductGrid.SelectedRow;
int ID = (int)ProductGrid.SelectedDataKey.Value;
String Name = row.Cells[1].Text;
decimal Price = Decimal.Parse(row.Cells[2].Text,
NumberStyles.Currency);
if (Profile.ShoppingCart == null)
Profile.ShoppingCart = new ShoppingCart();
Profile.ShoppingCart.AddItem(ID, Name, Price);
BindShoppingCart();
}
void RemoveCartItem(Object s, EventArgs e)
{
int ID = (int)CartGrid.SelectedDataKey.Value;
Profile.ShoppingCart.RemoveItem(ID);
BindShoppingCart();
}
</script>
<html>
<head>
<title>Products</title>
</head>
<body>
<form id="form1" runat="server">
<table width="100%">
<tr>
<td valign="top">
<h2>Products</h2>
<asp:GridView
ID="ProductGrid"
DataSourceID="ProductSource"
DataKeyNames="ProductID"
AutoGenerateColumns="false"
OnSelectedIndexChanged="AddCartItem"
ShowHeader="false"
CellPadding="5"
Runat="Server">
<Columns>
<asp:ButtonField
CommandName="select"
Text="Buy" />
<asp:BoundField
DataField="ProductName" />
<asp:BoundField
DataField="UnitPrice"
DataFormatString="{0:c}" />
</Columns>
</asp:GridView>
<asp:SqlDataSource
ID="ProductSource"
ConnectionString=
"Server=localhost;Database=Northwind;Trusted_Connection=true;"
SelectCommand=
"SELECT ProductID,ProductName,UnitPrice FROM Products"
Runat="Server" />
</td>
<td valign="top">
<h2>Shopping Cart</h2>
<asp:GridView
ID="CartGrid"
AutoGenerateColumns="false"
DataKeyNames="ID"
OnSelectedIndexChanged="RemoveCartItem"
CellPadding="5"
Width="300"
Runat="Server">
<Columns>
<asp:ButtonField
CommandName="select"
Text="Remove" />
<asp:BoundField
DataField="Name"
HeaderText="Name" />
<asp:BoundField
DataField="Price"
HeaderText="Price"
DataFormatString="{0:c}" />
<asp:BoundField
DataField="Quantity"
HeaderText="Quantity" />
</Columns>
</asp:GridView>
<b>Total:</b>
<asp:Label ID="lblTotal" Runat="Server" />
</td>
</tr>
</table>
</form>
</body>
</html>
繼承一個profile
你也能夠經過從一個已經存在的profile類中繼承一個profile來完成對profile的定義,這種特性可以幫助你在多個應用程序中使用相同的profile。
例如,列表7中列出了一個擁有多個用戶屬性的類,該類是從ProfileBase類繼承而來的(你能夠在System.Web.Profile中找到)
在列表8中的Web.config包含一個從UserInfo類繼承而來的profile,經過該聲明,新的profile能夠得到UserInfo類的全部屬性。
列表 7. UserInfo (Visual Basic .NET)
Imports Microsoft.VisualBasic
Imports System.Web.Profile
Public Class UserInfo
Inherits ProfileBase
Private _FirstName As String
Private _LastName As String
Public Property FirstName() As String
Get
Return _FirstName
End Get
Set(ByVal value As String)
_FirstName = value
End Set
End Property
Public Property LastName() As String
Get
Return _LastName
End Get
Set(ByVal value As String)
_LastName = value
End Set
End Property
End Class
列表 7. UserInfo (C#)
using System; using System.Web.Profile; public class UserInfo : ProfileBase { private string _FirstName; private string _LastName; public string FirstName { get { return _FirstName; } set { _FirstName = value; } } public string LastName { get { return _LastName; } set { _LastName = value; } } }
using System;
using System.Web.Profile;
public class UserInfo : ProfileBase
{
private string _FirstName;
private string _LastName;
public string FirstName
{
get { return _FirstName; }
set { _FirstName = value; }
}
public string LastName
{
get { return _LastName; }
set { _LastName = value; }
}
}
列表 8. Web.Config
<configuration>
<system.web>
<anonymousIdentification enabled="true" />
<profile inherits="UserInfo" />
</system.web>
</configuration>
遷移匿名Profile設置
Profile對象既可用於匿名用戶也能夠用於已認證用戶。然而,當用戶從匿名用戶狀態轉換爲已認證用戶狀態時,Profile對象可以以一種使人難以理解的方式完成任務。
當匿名用戶使用Profile對象時,用戶profile是與一個隨機生成的號碼相關聯的,該號碼是根據每一個用戶惟一輩子成的,它保存在瀏覽器的cookie中,不管什麼時候該用戶返回應用程序,該用戶的Profile設置會被自動加載。
若是匿名用戶經過認證的話,全部與該用戶相關的profile就會丟失,同時系統會生成一個新的profile。這時該Profile信息將與用戶名相關聯,而非惟一識別號。
要想理解全部這些工做,最好的方法就是看看下面的例子。列表9中的web.config定義了一個profile,該profile只有一個FavoriteColor屬性。
列表 9 Web.config
<configuration>
<system.web>
<authentication mode="Forms" />
<anonymousIdentification enabled="true" />
<profile>
<properties>
<add
name="FavoriteColor"
allowAnonymous="true"
defaultValue="Red" />
</properties>
</profile>
</system.web>
</configuration>
列表10中有一個包含兩個按鈕的頁面,分別是login和logout按鈕,其中還有一個用於更新FavoriteColor屬性的表單。
列表10. Anonymous.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server">
Sub Login(ByVal s As Object, ByVal e As EventArgs)
FormsAuthentication.SetAuthCookie("Bill", False)
Response.Redirect(Request.Path)
End Sub
Sub Logout(ByVal s As Object, ByVal e As EventArgs)
FormsAuthentication.SignOut()
Response.Redirect(Request.Path)
End Sub
Sub UpdateProfile(ByVal s As Object, ByVal e As EventArgs)
Profile.FavoriteColor = txtFavoriteColor.Text
End Sub
Sub Page_PreRender()
lblUsername.Text = Profile.UserName
lblFavoriteColor.Text = Profile.FavoriteColor
End Sub
</script>
<html>
<head>
<title>Anonymous</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Button ID="Button1"
Text="Login"
OnClick="Login"
Runat="Server" />
<asp:Button ID="Button2"
Text="Logout"
OnClick="Logout"
Runat="Server" />
<hr />
<asp:TextBox
id="txtFavoriteColor"
Runat="Server" />
<asp:Button ID="Button3"
Text="Update Profile"
OnClick="UpdateProfile"
Runat="Server" />
<hr />
<b>Username:</b>
<asp:Label
id="lblUsername"
Runat="Server" />
<br />
<b>Favorite Color:</b>
<asp:Label
id="lblFavoriteColor"
Runat="Server" />
</form>
</body>
</html>
列表10. Anonymous.aspx (C#)
<%@ Page Language="C#" %>
<script runat="server">
void Login(Object s, EventArgs e)
{
FormsAuthentication.SetAuthCookie("Bill", false);
Response.Redirect(Request.Path);
}
void Logout(Object s, EventArgs e)
{
FormsAuthentication.SignOut();
Response.Redirect(Request.Path);
}
void UpdateProfile(Object s, EventArgs e)
{
Profile.FavoriteColor = txtFavoriteColor.Text;
}
void Page_PreRender()
{
lblUsername.Text = Profile.UserName;
lblFavoriteColor.Text = Profile.FavoriteColor;
}
</script>
<html>
<head>
<title>Anonymous</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Button
Text="Login"
OnClick="Login"
Runat="Server" />
<asp:Button ID="Button1"
Text="Logout"
OnClick="Logout"
Runat="Server" />
<hr />
<asp:TextBox
id="txtFavoriteColor"
Runat="Server" />
<asp:Button
Text="Update Profile"
OnClick="UpdateProfile"
Runat="Server" />
<hr />
<b>Username:</b>
<asp:Label
id="lblUsername"
Runat="Server" />
<br />
<b>Favorite Color:</b>
<asp:Label
id="lblFavoriteColor"
Runat="Server" />
</form>
</body>
</html>
當你打開第一個頁面時,UserName的值是一個隨機生成的惟一識別號(見圖3)。當你按下Login按鈕後,你就完成了身份認證,它是經過用戶票據(User Bill)完成的。
圖3 使用匿名和認證profile
列表10的頁面中包含一個用於更新FavoriteColor的表單,要注意的是,在你登陸登出的時候,會分別生成兩個不一樣的profile。例如當你先登陸,後登出的話,那麼系統會生成一個隨機的惟一識別號。
在 不少狀況下,你須要把匿名profile遷移到認證profile狀態,若是你須要遷移profile屬性值的話,你能夠利用 ProfileModule類的MigrateAnonymous事件完成該任務,該事件只能在Global.asax文件中進行處理。列表11中的 Global.asax演示了你如何才能實現FavoriteColor屬性的遷移。
列表 11. Global.asax (Visual Basic .NET)
<%@ Application Language="VB" %>
<script runat="server">
Sub Profile_MigrateAnonymous(ByVal s As Object, _
ByVal e As ProfileMigrateEventArgs)
Dim anonProfile As ProfileCommon = _
Profile.GetProfile(e.AnonymousId)
Profile.FavoriteColor = anonProfile.FavoriteColor
End Sub
</script>
列表 11. Global.asax (C#)
<%@ Application Language="C#" %>
<script runat="server">
void Profile_MigrateAnonymous(Object s,
ProfileMigrateEventArgs e)
{
ProfileCommon anonProfile =
Profile.GetProfile(e.AnonymousId);
Profile.FavoriteColor = anonProfile.FavoriteColor;
}
</script>
經過Profile類的GetProfile()方法你能夠得到匿名profile,該方法接收一個惟一識別號,而且返回與惟一識別號對應的profile。ProfileMigrateEventArgs對象包含一個匿名識別號。
配置Profile Provider
默 認狀況下,profile被保存在sqlserver 2005 express數據庫,它位於App_Data目錄中,這或許在你開發一些普通的asp.net應用程序時是沒有問題的,但頗有可能,你須要把你的應用程 序的profile保存在另外一個數據庫中,好比一個完整版的SqlServer 2005的實例中,而該數據庫又位於你局域網的某個位置。
Profile使用Provider模式,經過修改web.config或machine.config的設置來告訴系統把信息存儲在哪裏。
ASP.NET 自己配了一個profile provider,叫SqlProfileProvider。若是你感到困惑,你能夠經過繼承ProfileProvider基類來建立一個本身的 provider。例如,你能夠建立一個基於Oracle數據庫或MySql數據庫的Provider。在這裏,咱們將只討論最簡單的方法,即經過 SqlServer數據庫來保存profile信息。
要使用Microsoft SQL Server存儲profile信息,必須完成兩個步驟。首先,你必須安裝SQL Server數據庫,而後你必須從新設置配置文件。
ASP.NET 2.0框架提供了一個用於配置SQL Server來存儲Profile信息的工具,該工具叫作aspnet_regsql,它位於Windows/Microsoft.NET/ Framework/[.NET版本號]。執行該工具後,你會看到圖4中的ASP.NET SQL Server安裝嚮導。
圖4 使用ASP.NET SQL Server安裝程序
SQL Server安裝嚮導會指導你完成必要的步驟,完成這些步驟後,嚮導會自動建立用於存儲profile信息的存儲過程和表結構。
在你完成SQL Server數據庫的配置後,你須要修改web.config或machine.config中的數據庫鏈接設置來指向服務器上的SQL Server數據庫,本例中該數據庫的實例名爲MyServer,列表12列出了該配置文件。
列表 12. Web.Config
<configuration>
<connectionStrings>
<add
name="myConnectionString"
connectionString=
"Server=MyServer;Trusted_Connection=true;database=MyDatabase" />
</connectionStrings>
<system.web>
<anonymousIdentification enabled="true" />
<profile defaultProvider="MyProfileProvider">
<providers>
<add
name="MyProfileProvider"
type="System.Web.Profile.SqlProfileProvider"
connectionStringName="myConnectionString" />
</providers>
<properties>
<add
name="FirstName"
allowAnonymous="true" />
<add
name="LastName"
allowAnonymous="true" />
</properties>
</profile>
</system.web>
</configuration>
在列表12中的profile配置中,包含了一個defaultProvider特性,這個特性指向一個叫MyProfileProvider的 profile provider,而這個provider定義是在profile標記的<providers>節中完成的。 MyProfileProvider則使用一個叫MyConnectionString的鏈接字符串完成數據庫鏈接,並保存profile信息到數據庫 中。MyConnectionString能夠在位於web.config開頭的<connectionStrings>節中找到。
管理profile並生成profile報告
Profile會對象自動保存用戶profile信息,這既是好事業是壞事。說它是好事,是由於你不須要寫存儲信息的全部邏輯代碼,說它是壞事,是由於這樣可能形成一大堆無用的信息被保存在數據庫中。
幸運的是,ASP.NET 2.0框架包含一個叫作ProfileManager的類,你可使用它來管理profile信息。它包含了至關多的方法使你可以有效地管理profile而且生成profile報表,下面列出了一些該類的重要方法:
DeleteInactiveProfiles. 刪除一個特定日期以前的全部profile
DeleteProfile. 刪除特定用戶的profile
DeleteProfiles. 刪除一個profile集合
FindInactiveProfilesByUserName. 返回一個ProfileInfo對象的集合,該集合表示的profile是匹配一個某個名字,而且是從某個特定日期開始一直未被使用
FindProfilesByUserName. 返回一個ProfileInfo對象集合,該集合與某個用戶名相關聯
GetAllInactiveProfiles. 返回一個ProfileInfo對象集合,該集合表示的profile是從某個特定日期開始一直未被使用的profile
GetAllProfiles. 返回一個ProfileInfo對象集合,該集合表示全部的profile
GetNumberOfInactiveProfiles. 返回從某個特定日期開始一直未被使用的profile的數量
GetNumberOfProfiles. 返回profile總數
這些方法中,雖然全部的方法都返回一個ProfileInfo對象集合,但沒有一個返回一個真正的profile。ProfileInfo對象包含如下profile屬性
IsAnonymous. 表示該profile是否爲匿名profile
LastActivityDate. 最後一次profile被訪問的時間和日期
LastUpdatedDate. 最後一次profile被升級的時間和日期
Size. 表示profile的大小,這是在profile provider存儲profile信息時記錄的
UserName. 與profile關聯的用戶名
ProfileManager有幾個方法提供了額外的參數用於支持分頁。例如,GetAllProfiles方法的一個重載版本就提供了專門用於設置頁面索引、頁面大小、總共的記錄數的參數,這些參數在須要分頁的頁面中十分有用。
ProfileManager 既能夠在asp.net頁面下使用,也能夠在其它程序中使用。例如,你可能須要作一個控制檯程序用於天天清除長時間未使用的 profile。列表14的控制檯程序會刪除七天未使用的profile,你可使用Windows計劃任務(Windows Scheduled Tasks)來安排該程序的執行時間。
列表 14. DeleteInactiveProfiles (Visual Basic .NET)
Imports System.Web.Profile
Public Class DeleteInactiveProfiles
Public Shared Sub Main()
Dim deleted As Integer
deleted =
ProfileManager.DeleteInactiveProfiles(
ProfileAuthenticationOption.All,
DateTime.Now.AddDays(-7))
Console.WriteLine("Deleted " & deleted & " profiles" )
End Sub
End Class
列表 14. DeleteInactiveProfiles (C#)
using System;
using System.Web.Profile;
public class DeleteInactiveProfiles
{
public static void Main()
{
int deleted = 0;
deleted =
ProfileManager.DeleteInactiveProfiles(
ProfileAuthenticationOption.All,
DateTime.Now.AddDays(-7));
Console.WriteLine("Deleted " +
deleted.ToString() + " profiles" );
}
}
你能夠經過一下的命令行指令對列表14進行編譯
[Visual Basic .NET]
C:/WINDOWS/Microsoft.NET/Framework/v2.0.40607/vbc
/r:System.Web.dll DeleteInactiveProfiles.vb
[C#]
C:/WINDOWS/Microsoft.NET/Framework/v2.0.40607/csc
DeleteInactiveProfiles.cs
你還可使用ProfileManager類生成profile信息報表。例如,若是你打算生成一個用戶調查的報表,你能夠把用戶調查保存在profile中,這樣就能夠輕易的使用ProfileManager生成你須要的報表。
列表15中的web.config中有三個屬性:SurveyCompleted、FavoriteLanguage 和 FavoriteEnvironment
Listing 15. Web.Config
<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.web>
<anonymousIdentification enabled="true" />
<profile>
<properties>
<add
name="SurveyCompleted"
type="Boolean"
allowAnonymous="true" />
<add
name="FavoriteLanguage"
allowAnonymous="true" />
<add
name="FavoriteEnvironment"
allowAnonymous="true" />
</properties>
</profile>
</system.web>
</configuration>
列表16中的頁面演示了一個簡單的用戶調查。該頁面包含兩個Panel控件,第一個控件中有兩個調查問題,當用戶完成調查後,第一個控件會自動隱藏,而第二個會顯示出來,第二個Panel有一段表示感謝的文字。
列表 16. Survey.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server">
Sub SaveSurvey(ByVal s As Object, ByVal e As EventArgs)
Profile.FavoriteLanguage = rdlLanguage.SelectedItem.Text
Profile.FavoriteEnvironment = rdlEnvironment.SelectedItem.Text
Profile.SurveyCompleted = True
End Sub
Sub Page_PreRender()
If Profile.SurveyCompleted Then
pnlSurvey.Visible = False
pnlSurveyCompleted.Visible = True
Else
pnlSurvey.Visible = True
pnlSurveyCompleted.Visible = False
End If
End Sub
</script>
<html>
<head>
<title>Survey</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Panel ID="pnlSurvey" Runat="Server">
What is your favorite programming language?
<br />
<asp:RadioButtonList
id="rdlLanguage"
runat="Server">
<asp:ListItem Text="VB.NET" Selected="True" />
<asp:ListItem Text="C#" />
<asp:ListItem Text="J#" />
</asp:RadioButtonList>
<p> </p>
What is your favorite development environment?
<br />
<asp:RadioButtonList
id="rdlEnvironment"
runat="Server">
<asp:ListItem Text="VS.NET" Selected="True" />
<asp:ListItem Text="Web Matrix" />
<asp:ListItem Text="Notepad" />
</asp:RadioButtonList>
<p> </p>
<asp:Button
Text="Submit Survey"
Onclick="SaveSurvey"
Runat="Server" />
</asp:Panel>
<asp:Panel ID="pnlSurveyCompleted" Runat="Server">
Thank you for completing the survey!
</asp:Panel>
</form>
</body>
</html>
列表 16. Survey.aspx (C#)
<%@ Page Language="C#" %>
<script runat="server">
void SaveSurvey(Object s, EventArgs e)
{
Profile.FavoriteLanguage = rdlLanguage.SelectedItem.Text;
Profile.FavoriteEnvironment = rdlEnvironment.SelectedItem.Text;
Profile.SurveyCompleted = true;
}
void Page_PreRender()
{
if (Profile.SurveyCompleted)
{
pnlSurvey.Visible = false;
pnlSurveyCompleted.Visible = true;
}
else
{
pnlSurvey.Visible = true;
pnlSurveyCompleted.Visible = false;
}
}
</script>
<html>
<head>
<title>Survey</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Panel ID="pnlSurvey" Runat="Server">
What is your favorite programming language?
<br />
<asp:RadioButtonList
id="rdlLanguage"
runat="Server">
<asp:ListItem Text="VB.NET" Selected="True" />
<asp:ListItem Text="C#" />
<asp:ListItem Text="J#" />
</asp:RadioButtonList>
<p> </p>
What is your favorite development environment?
<br />
<asp:RadioButtonList
id="rdlEnvironment"
runat="Server">
<asp:ListItem Text="VS.NET" Selected="True" />
<asp:ListItem Text="Web Matrix" />
<asp:ListItem Text="Notepad" />
</asp:RadioButtonList>
<p> </p>
<asp:Button ID="Button1"
Text="Submit Survey"
Onclick="SaveSurvey"
Runat="Server" />
</asp:Panel>
<asp:Panel ID="pnlSurveyCompleted" Runat="Server">
Thank you for completing the survey!
</asp:Panel>
</form>
</body>
</html>
列表17中顯示調查的結果,該頁面中有一個顯示ProfileInfo對象集合的GridView控件,該ProfileInfo對象集合是由 ProfileManager的GetAllProfiles方法得到的。當你點擊GridView中的任意一行的Select連接時,你將會看到對這個 問題的調查結果,該調查結果是由Profile類的GetProfile方法得到的。
圖5 顯示調查結果
列表 17. SurveyResults.aspx (Visual Basic .NET)
<%@ Page Language="VB" %>
<script runat="server">
Sub Page_Load()
ResultsGrid.DataSource = _
ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All)
ResultsGrid.DataBind()
End Sub
Sub DisplayProfileDetails(ByVal s As Object, ByVal e As EventArgs)
Dim SelectedProfile As ProfileCommon
SelectedProfile = Profile.GetProfile(ResultsGrid.SelectedValue)
lblLanguage.Text = SelectedProfile.FavoriteLanguage
lblEnvironment.Text = SelectedProfile.FavoriteEnvironment
End Sub
</script>
<html>
<head>
<title>Survey Results</title>
</head>
<body>
<form id="form1" runat="server">
<h2>Survey Results</h2>
<asp:GridView
id="ResultsGrid"
DataKeyNames="UserName"
AutoGenerateSelectButton="true"
OnSelectedIndexChanged="DisplayProfileDetails"
SelectedRowStyle-BackColor="LightYellow"
Runat="Server" />
<p> </p>
<h2>Survey Details</h2>
<b>Favorite Language:</b>
<asp:Label
id="lblLanguage"
Runat="Server" />
<br />
<b>Favorite Environment:</b>
<asp:Label
id="lblEnvironment"
Runat="Server" />
</form>
</body>
</html>
列表 17. SurveyResults.aspx (C#)
<%@ Page Language="C#" %>
<script runat="server">
void Page_Load()
{
ResultsGrid.DataSource =
ProfileManager.GetAllProfiles(ProfileAuthenticationOption.All);
ResultsGrid.DataBind();
}
void DisplayProfileDetails(Object s, EventArgs e)
{
ProfileCommon SelectedProfile =
Profile.GetProfile(ResultsGrid.SelectedValue.ToString());
lblLanguage.Text = SelectedProfile.FavoriteLanguage;
lblEnvironment.Text = SelectedProfile.FavoriteEnvironment;
}
</script>
<html>
<head>
<title>Survey Results</title>
</head>
<body>
<form id="form1" runat="server">
<h2>Survey Results</h2>
<asp:GridView
id="ResultsGrid"
DataKeyNames="UserName"
AutoGenerateSelectButton="true"
OnSelectedIndexChanged="DisplayProfileDetails"
SelectedRowStyle-BackColor="LightYellow"
Runat="Server" />
<p> </p>
<h2>Survey Details</h2>
<b>Favorite Language:</b>
<asp:Label
id="lblLanguage"
Runat="Server" />
<br />
<b>Favorite Environment:</b>
<asp:Label
id="lblEnvironment"
Runat="Server" />
</form>
</body>
</html>
總結 當創建Web應用程序時,我依舊花費了大量的時間和精力用於作一些大傷腦筋的事情。其中的一個任務就是寫一些用於從數據庫存儲和得到用戶信息的代碼。雖然 Profile對象引入的都是asp.net 1.0中能夠實現的功能,可是這個新特性幫助咱們從乏味的編碼工做中解脫出來,這樣也能讓咱們在寫Web應用程序的過程當中,把更多的精力放在咱們更感興趣 的事情上。