程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> 建立一個使用.Net 2.0 MemberShip功能的標准例程(三)——綁定訪問篇

建立一個使用.Net 2.0 MemberShip功能的標准例程(三)——綁定訪問篇

編輯:關於.NET

經過上一章的例子 我們已經建立了一個標准的,有很多有趣(甚至有些是專業級)功能的登陸系統了。

可是我們如何管理這個系統呢?難道我們要用m$提供的asp.net管理工具管理一輩子麼?

——當然不!那太可怕了!T_T

——我們要自己寫一個後台,一個可以根據用戶權限自己修改的後台!@_@

當然有一種數據庫狂人,他們只冷冷的瞥了幾眼m$提供的數據庫結構,輕描淡寫的破譯了其中所有的奧妙之處,隨手拖了5-6個grid 寫了10多行SQL 就用數據庫方式搞定了。對於這種高手,我們仰慕,我們恨不得馬上吸光他的百年功力,然後殺之後快,NND.

但是成為這樣的高手需要非常的經驗和手腕。我們這些小菜鳥,沒有寫輪眼,也不是聖斗士,所謂“看穿”技能在我們的身上是不能工作的。我們只有membership標准對象 profile標准對象 和roles標准對象。

難道就不能很方便的通過綁定方式訪問這些對象麼?

通過頁面訪問較為復雜的對象——在.net 1.x 的時代——對我們曾是一種煎熬。明明好多對象有著數據行的特性,為什麼不能直接訪問呢?於是好多人---包括我,嘗試過各種辦法。我是失敗那批5555,也有很多的人成功了,研究出一些很有效的辦法。可是這個狀況沒有持續多久——自從.net 2.0推出了ODS ,我的失敗陰影就再也不復回來~~~

1 用ODS綁定MemberShip的總體思想

如圖所示

從戰略上 我們把每個用戶看成一個行,把Membership中的GetAllUsers ()看成一個Select語句。

但是一個標准的System.Web.Security.MembershipUser並不具有數據綁定對象的特性

比如主鍵/只讀等信息所以我們可以重寫它為它添加上這些特性

2 簡單的綁定方法

這裡采用的是MSDN上的部分c#代碼修改成的VB代碼 順便我也把版權信息粘貼上來

'/*
'Copyright ?2005, Peter Kellner
'All rights reserved.
'http://peterkellner.net
'Redistribution and use in source and binary forms, with or without
'modification, are permitted provided that the following conditions
'are met:
'- Redistributions of source code must retain the above copyright
'notice, this list of conditions and the following disclaimer.
'- Neither Peter Kellner, nor the names of its
'contributors may be used to endorse or promote products
'derived from this software without specific prior written
'permission.
'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
'LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
'FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
'COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
'INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING,
'BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
'CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
'LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
'ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
'POSSIBILITY OF SUCH DAMAGE.
'*/
Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Collections.Generic
Imports System.ComponentModel
_
'/ <summary>
'/ Summary description for MembershipUserWrapper
'/ This class is inherited from MembershipUser
'/ Using the sytax public class ClassName (..) : base(initializers) allows for calling the
'/ contstructor of the base class. In this case MembershipUser.
'/ </summary>
'/
Namespace Membership_ToolNamespace Membership_Tool
  Public Class MembershipUserWrapperClass MembershipUserWrapper
    Inherits MembershipUser
    '/ <summary>
    '/ This constructor is used to create a MembershipUserWrapper from a MembershipUser object. MembershipUser is a default type used
    '/ in the Membership API provided with ASP.NET 2.0
    '/ </summary>
    '/ <param name="mu">MembershipUser object</param>
    Public Sub New()Sub New(ByVal mu As MembershipUser)
      MyBase.New(mu.ProviderName, mu.UserName, mu.ProviderUserKey, mu.Email, mu.PasswordQuestion, mu.Comment, mu.IsApproved, mu.IsLockedOut, mu.CreationDate, mu.LastLoginDate, mu.LastActivityDate, mu.LastPasswordChangedDate, mu.LastLockoutDate)
    End Sub 'New<DataObjectField(True)> _
    '/ <summary>
    '/ This calls the base class UserName property. It is here so we can tag
    '/ this property as the primary key so that datakeynames attribute gets set in the data control.
    '/ </summary>
    '/
    <DataObjectField(True)> _
    Public Overrides ReadOnly Property UserName()Property UserName() As String
      Get
        Return MyBase.UserName
      End Get
    End Property
    '/ <summary>
    '/ This constructor is used to create a MembershipUserWrapper from individual parameters values. 
    '/ For details of what each parameter means, see the Microsoft Membership class.
    '/ </summary>
    '/ <param name="comment">Passes to MembershipUser.comment</param>
    '/ <param name="creationDate">Passes to MembershipUser.creationDate</param>
    '/ <param name="email">Passes to MembershipUser.email</param>
    '/ <param name="isApproved">Passes to MembershipUser.isApproved</param>
    '/ <param name="lastActivityDate">Passes to MembershipUser.lastActivityDate</param>
    '/ <param name="lastLoginDate">Passes to MembershipUser.lastLoginDate</param>
    '/ <param name="passwordQuestion">Passes to MembershipUser.passwordQuestion</param>
    '/ <param name="providerUserKey">Passes to MembershipUser.providerUserKey</param>
    '/ <param name="userName">Passes to MembershipUser.userName</param>
    '/ <param name="lastLockoutDate">Passes to MembershipUser.lastLockoutDate</param>
    '/ <param name="providerName">Passes to MembershipUser.providerName</param>
    '/
    Public Sub New()Sub New(ByVal comment As String, ByVal creationDate As DateTime, ByVal email As String, ByVal isApproved As Boolean, ByVal lastActivityDate As DateTime, ByVal lastLoginDate As DateTime, ByVal passwordQuestion As String, ByVal providerUserKey As Object, ByVal userName As String, ByVal lastLockoutDate As DateTime, ByVal providerName As String)
      MyBase.New(providerName, userName, providerUserKey, email, passwordQuestion, comment, isApproved, False, creationDate, lastLoginDate, lastActivityDate, DateTime.Now, lastLockoutDate)
    End Sub 'New
  End Class 'MembershipUserWrapper
  ' This calls a constructor of MembershipUser automatically because of the base reference above
End Namespace

這樣MembershipUser 的Username 被標記成 只讀/主鍵 在綁定的時候 GridView會識別這一說明生成相應的編輯模式模板。

數據行已經被我們建立好了,那麼數據從哪裡來呢?我們建立一個新類MembershipUserODS 把提供我們的數據的方法集中在這個類中,它就能起到Dataadepter的作用。

  <DataObject(True)> _
  Public Class MembershipUserODSClass MembershipUserODS
  End Class

其中加入如下方法來實現數據的讀取,也就是Select操作:

  <DataObjectMethod(DataObjectMethodType.Select, False)> Public Shared _
Function GetMembers()Function GetMembers(ByVal returnAllApprovedUsers As Boolean, ByVal returnAllNotApprovedUsers As Boolean, ByVal usernameToFind As String) As List(Of MembershipUserWrapper)
      Dim memberList As New List(Of MembershipUserWrapper)
      '看看是否只需要返回某個特定的用戶
      If Not (usernameToFind Is Nothing) Then
        '      {
        Dim mu As MembershipUser = Membership.GetUser(usernameToFind)
        If Not mu Is Nothing Then
          Dim md As MembershipUserWrapper = New MembershipUserWrapper(mu)
          memberList.Add(md)
        End If
      Else
        Dim muc As MembershipUserCollection = Membership.GetAllUsers()
        Dim mu As MembershipUser
        For Each mu In muc
          If returnAllApprovedUsers = True And mu.IsApproved = True Or (returnAllNotApprovedUsers = True And mu.IsApproved = False) Then
            Dim md As New MembershipUserWrapper(mu)
            memberList.Add(md)
          End If
        Next mu
    return memberList
end Function

(在隨後的源代碼包裡面有排序的功能 大家參考下就好)

這時候我們已經可以對 MembershipUserODS  進行數據綁定了----這個方法實現了數據綁定的最基礎的動作:選擇。

利用同樣的方式 我們建立對應 插入、更新和刪除操作的 方法:

插入:

<DataObjectMethod(DataObjectMethodType.Insert, True)> Public Shared _
  Sub Insert()Sub Insert(ByVal userName As String, ByVal isApproved As Boolean, ByVal comment As String, ByVal lastLockoutDate As DateTime, ByVal creationDate As DateTime, ByVal email As String, ByVal lastActivityDate As DateTime, ByVal providerName As String, ByVal isLockedOut As Boolean, ByVal lastLoginDate As DateTime, ByVal isOnline As Boolean, ByVal passwordQuestion As String, ByVal lastPasswordChangedDate As DateTime, ByVal password As String, ByVal passwordAnswer As String)
      ' The incoming parameters, password and passwordAnswer are not properties of the
      ' MembershipUser class. Membership has special member functions to deal with these
      ' two special properties for security reasons. For this reason, they do not appear
      ' in a datacontrol that is created with this user object. 
      '
      ' the only reason you may want to have defaults is so you can build insert into your
      ' datacontrol. A better approach would be to either follow the example shown in the
      ' Membership.asp page where the parameters are set directly to the userobject, or not
      ' include "new" at all in your control and use the other controls in the Membership API
      ' for creating new members. (CreateUserWizard, etc)
      '
      ' It is recommended that you only enable the following lines if you are sure of what you are doing
      'if (password == null)
      '{
      '  password = "pass0word";
      '}
      'if (passwordAnswer == null)
      '{
      '  passwordAnswer = "Password Answer";
      '}
      Dim status As MembershipCreateStatus
      Membership.CreateUser(userName, password, email, passwordQuestion, passwordAnswer, isApproved, status)
      If status <> MembershipCreateStatus.Success Then
        Throw New ApplicationException(status.ToString())
      End If
      Dim mu As MembershipUser = Membership.GetUser(userName)
      mu.Comment = comment
      Membership.UpdateUser(mu)
    End Sub

更新:

  <DataObjectMethod(DataObjectMethodType.Update, True)> Public Shared _
  Sub Update()Sub Update(ByVal UserName As String, ByVal email As String, ByVal isApproved As Boolean, ByVal comment As String, ByVal lastActivityDate As DateTime, ByVal lastLoginDate As DateTime)
      Dim dirtyFlag As Boolean = False
      Dim mu As MembershipUser = Membership.GetUser(UserName)
      If mu.Comment Is Nothing Or (mu.Comment & "").CompareTo(comment) <> 0 Then
        dirtyFlag = True
        mu.Comment = comment
      End If
      If mu.Email Is Nothing Or (mu.Email & "").CompareTo(email) <> 0 Then
        dirtyFlag = True
        mu.Email = email
      End If
      If mu.IsApproved <> isApproved Then
        dirtyFlag = True
        mu.IsApproved = isApproved
      End If
      If dirtyFlag = True Then
        Membership.UpdateUser(mu)
      End If
    End Sub

刪除:

   <DataObjectMethod(DataObjectMethodType.Delete, True)> Public Shared _
  Sub Delete()Sub Delete(ByVal UserName As String)
      Membership.DeleteUser(UserName, True)
    End Sub

以上的工作,我們在ODS和membership之間 建立了一條橋梁,通過我們的代碼,membership 復雜的對象被我們用簡單的數據屬性所代理,而能夠被ODS正確識別

下面我們簡單的試驗下我們工作的成果,親手綁定一下。

建立一個新頁面Default.aspx 在上面放置一個GridView和一個ODS控件。

效果如下圖示:

選擇“配置數據源”,你剛才建立的、帶有<DataObject>聲明的類便會被枚舉出來:

下一步 選擇每種動作的對應方法:

當你把4種基本動作全部配置完畢 ,在屬性欄把ObjectDataSource1.OldValuesParameterFormatString 的內容設置為{0} 就可以綁定了:

基本上不會出現什麼錯誤拉。。。。

同樣的方式  你可以用如下的代碼建立Roles和Profile 的綁定

Roles

'/*
'Copyright ?2005, Peter Kellner
'All rights reserved.
'http://peterkellner.net
'Redistribution and use in source and binary forms, with or without
'modification, are permitted provided that the following conditions
'are met:
'- Redistributions of source code must retain the above copyright
'notice, this list of conditions and the following disclaimer.
'- Neither Peter Kellner, nor the names of its
'contributors may be used to endorse or promote products
'derived from this software without specific prior written
'permission.
'THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
'"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
'LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
'FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
'COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
'INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES INCLUDING,
'BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
'LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
'CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
'LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
'ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
'POSSIBILITY OF SUCH DAMAGE.
'*/
Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Collections.ObjectModel
Namespace Membership_ToolNamespace Membership_Tool
  '/ <summary>
  '/ A class used to encapsulate the Roles in ASP.NET Membermanagement 2.0
  '/ </summary>
  <DataObject(True)> _
  Public Class RoleDataODSClass RoleDataODS
    ' This attribute allows the
    '/ <summary>
    '/ Used to get all roles available
    '/ </summary>
    '/ <returns></returns>
    '/
    <DataObjectMethod(DataObjectMethodType.Select, True)> Public Overloads Shared _
    Function GetRoles()Function GetRoles() As List(Of RoleData)
      Return GetRoles(Nothing, False)
    End Function 'GetRoles
    '/ <summary>
    '/ Returns a collection of RoleData type values. This specialized constructor lets you request by
    '/ an individual user
    '/ </summary>
    '/ <param name="userName">if null and showOnlyAssignedRolls==false, display all roles</param>
    '/ <param name="showOnlyAssignedRolls">if true, just show assigned roles</param>
    '/ <returns></returns>
    <DataObjectMethod(DataObjectMethodType.Select, False)> Public Overloads Shared _
    Function GetRoles()Function GetRoles(ByVal userName As String, ByVal showOnlyAssignedRolls As Boolean) As List(Of RoleData)
      Dim roleList As New List(Of RoleData)
      Dim roleListStr As String() = Roles.GetAllRoles()
      Dim roleName As String
      For Each roleName In roleListStr
        Dim userInRole As Boolean = False
        ' First, figure out if user is in role (if there is a user)
        If Not (userName Is Nothing) Then
          userInRole = Roles.IsUserInRole(userName, roleName)
        End If
        If showOnlyAssignedRolls = False Or userInRole = True Then
          ' Getting usersInRole is only used for the count below
          Dim usersInRole As String() = Roles.GetUsersInRole(roleName)
          Dim rd As New RoleData()
          rd.RoleName = roleName
          rd.UserName = userName
          rd.UserInRole = userInRole
          rd.NumberOfUsersInRole = usersInRole.Length
          roleList.Add(rd)
        End If
      Next roleName
      ' FxCopy will give us a warning about returning a List rather than a Collection.
      ' We could copy the data, but not worth the trouble.
      Return roleList
    End Function 'GetRoles
    '/ <summary>
    '/ Used for Inserting a new role. Doesn't associate a user with a role.
    '/ This is not quite consistent with this object, but really what we want.
    '/ </summary>
    '/ <param name="RoleName">The Name of the role to insert</param>
    <DataObjectMethod(DataObjectMethodType.Insert, True)> Public Shared _
    Sub Insert()Sub Insert(ByVal roleName As String)
      If Roles.RoleExists(roleName) = False Then
        Roles.CreateRole(roleName)
      End If
    End Sub 'Insert
    '/ <summary>
    '/ Delete any given role while first removing any roles associated with existing users
    '/ </summary>
    '/ <param name="roleName">name of role to delete</param>
    <DataObjectMethod(DataObjectMethodType.Delete, True)> Public Shared _
    Sub Delete()Sub Delete(ByVal roleName As String)
      ' remove this role from all users. not sure if deleterole does this automagically
      Dim muc As MembershipUserCollection = Membership.GetAllUsers()
      Dim allUserNames(1) As String
      Dim mu As MembershipUser
      For Each mu In muc
        If Roles.IsUserInRole(mu.UserName, roleName) = True Then
          allUserNames(0) = mu.UserName
          Roles.RemoveUsersFromRole(allUserNames, roleName)
        End If
      Next mu
      Roles.DeleteRole(roleName)
    End Sub 'Delete
  End Class 'RoleDataObject
  '/ <summary>
  '/ Dataobject class used as a base for the collection
  '/ </summary>
  Public Class RoleDataClass RoleData
    ' Non normalized column which counts current number of users in a role
    Private number_OfUsersInRole As Integer
    Public Property NumberOfUsersInRole()Property NumberOfUsersInRole() As Integer
      Get
        Return number_OfUsersInRole
      End Get
      Set(ByVal value As Integer)
        number_OfUsersInRole = value
      End Set
    End Property
    Private role_Name As String
    <DataObjectField(True)> _
    Public Property RoleName()Property RoleName() As String
      Get
        Return role_Name
      End Get
      Set(ByVal value As String)
        role_Name = value
      End Set
    End Property
    Public user_Name As String
    Public Property UserName()Property UserName() As String
      Get
        Return user_Name
      End Get
      Set(ByVal value As String)
        user_Name = value
      End Set
    End Property
    Private user_InRole As Boolean
    Public Property UserInRole()Property UserInRole() As Boolean
      Get
        Return user_InRole
      End Get
      Set(ByVal value As Boolean)
        user_InRole = value
      End Set
    End Property
  End Class 'RoleData
End Namespace
Profile
Imports System
Imports System.Data
Imports System.Configuration
Imports System.Web
Imports System.Web.Security
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.WebControls.WebParts
Imports System.Web.UI.HtmlControls
Imports System.Collections.Generic
Imports System.ComponentModel
Namespace Membership_ToolNamespace Membership_Tool
  <DataObject(True)> _
  Public Class ProfileODSClass ProfileODS
    <DataObjectMethod(DataObjectMethodType.Select, False)> _
    Public Function GetUserProfile()Function GetUserProfile(ByVal UserName As String) As List(Of ProfileEntry)
      Return GetUserProfile(UserName, Nothing)
    End Function
    <DataObjectMethod(DataObjectMethodType.Select, False)> _
  Public Function GetUserProfile()Function GetUserProfile(ByVal UserName As String, ByVal PropertyNames As String) As List(Of ProfileEntry)
      Dim doFilter As Boolean = False
      Dim PNames As String() = Nothing
      If PropertyNames Is Nothing Then
      ElseIf PropertyNames = "" Then
      Else
        PNames = PropertyNames.Split("|")
        doFilter = True
      End If
      Dim pelist As New List(Of ProfileEntry)
      Dim pf As Profile.ProfileBase = System.Web.Profile.ProfileBase.Create(UserName)
      '因為PrifileCommon的一個未知bug 在沒有訪問任何已知屬性前,屬性的集合將不可訪問,所以需要一個缺省的屬性來支持
      '以下為試圖訪問默認的屬性bugjumper來獲得屬性集合
      Try
        Dim x As String = pf.GetPropertyValue("bugjumper")
      Catch ex As Exception
        ' Throw New Exception("管理員並沒有為profilecommon的bug設置默認的屬性參數bugjumper")
      End Try
      '處理bug過程結束
      For Each itm As System.Configuration.SettingsPropertyValue In pf.PropertyValues
        If itm.Name <> "bugjumper" Then '忽略處理bug用的公共屬性
          Dim doAdd As Boolean = False
          If Not doFilter Then
            doAdd = True
          ElseIf Array.IndexOf(PNames, itm.Name) <> -1 Then
            doAdd = True
          End If
          If doAdd Then
            Dim pe As New ProfileEntry(UserName, itm.Name, itm.PropertyValue)
            pelist.Add(pe)
          End If
        End If
      Next
      Return pelist
    End Function
    <DataObjectMethod(DataObjectMethodType.Update, False)> _
    Public Sub UpdateUserProfile()Sub UpdateUserProfile(ByVal UserName As String, ByVal Key As String, ByVal Value As String)
      Dim pf As Profile.ProfileBase = System.Web.Profile.ProfileBase.Create(UserName)
      pf.SetPropertyValue(Key, Value)
      pf.Save()
    End Sub
  End Class
  Public Class ProfileEntryClass ProfileEntry
    Private k, v As String
    Private U As String
    <DataObjectField(True)> _
  Property Key()Property Key() As String
      Get
        Return k
      End Get
      Set(ByVal value As String)
        k = value
      End Set
    End Property
    Property Value()Property Value() As String
      Get
        Return v
      End Get
      Set(ByVal value As String)
        v = value
      End Set
    End Property
    <DataObjectField(True)> _
    Property UserName()Property UserName() As String
      Get
        Return U
      End Get
      Set(ByVal value As String)
        U = value
      End Set
    End Property
    Sub New()Sub New(ByVal NewUserName As String, ByVal NewKey As String, ByVal NewValue As String)
      Me.UserName = NewUserName
      Me.Key = NewKey
      Me.Value = NewValue
    End Sub
  End Class
End Namespace

ProFile可是我自己寫的阿^_^

這裡發現了一個bug,由vs2005 生成的profilecommon類 在第一次成功訪問某屬性前,Properties集合不會正確的枚舉出所有成員,所以我在程序中作了一些小小的調整,具體請看示例工程:DDDD

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved