Sections
spotlight
     
     
WWWCoder.com Resource Directory

Creating a Custom User Object
4/18/2005 12:40:05 PM

In this article we will cover how to create an assembly which is define a type of User, Users class, and UserController class for hosting AD search functions.

This project wraps up AD functionality, but can be easily extended to expand a user object to contain properties from other systems. For example, say you're running an ERP application and you have certain properties you would like to expose to your intranet application, in addition, your application is authenticating and consuming information from AD. You could just create multiple objects to call information from the various systems and then display the information in the client. Here we will create a single user object with properties that are exposed via the object, by combining all the user properties in our custom object, the client then only interacts with our object. If any changes happen to the backend for user properties or we want to expose information from other sources, we can then change our object class, without having to change the various consumers. You can then wrap the object in a Web service to extend it further.

Defining the User Class

The first thing we're going to do is create a user object. For this tutorial we're just exposing AD properties, so we'll define some of the properties that we'll be pulling from AD

First our private members:

Public Class User 

#Region "Private Members"
    Private m_FirstName As String
    Private m_LastName As String
    Private m_MI As String
    Private m_Phone As String
    Private m_Fax As String
    Private m_Mobile As String
    Private m_EmployeeID As String
    Private m_ADsPath As String
    Private m_UserName As String
    Private m_DisplayName As String
    Private m_OtherPhone As String
    Private m_PhysicalDeliveryOfficeName As String
    Private m_StreetAddress As String
    Private m_City As String
    Private m_State As String
    Private m_PostalCode As String
    Private m_Country As String
    Private m_Email As String
    Private m_BudgetCenter As String
 

#End Region

Now we need to expose these properties to calling classes:

#Region "Public Members"

    Public Property FirstName() As String
        Get
            Return m_FirstName
        End Get
        Set(ByVal Value As String)
            m_FirstName = Value
        End Set
    End Property
 

    Public Property LastName() As String
        Get
            Return m_LastName
        End Get
        Set(ByVal Value As String)
            m_LastName = Value
        End Set
    End Property

::
::
:: 

#End Region

End Class

Defining the Users Class

Next we'll create a class a Users class which will provide us with the abilty to enumerate through our users and create our collection of user objects:

Public Class Users
    Implements IEnumerable
    Private m_Users As New ArrayList 

    Public Function GetEnumerator() As _
        System.Collections.IEnumerator Implements _
        System.Collections.IEnumerable.GetEnumerator
        Return New UserEnumerator(m_Users)
    End Function
 

    Public Sub New()

    End Sub 

    Public ReadOnly Property Count() As Int32
        Get
            Return m_Users.Count
        End Get
    End Property
 

    Public Sub AddUser(ByVal User As User)
        m_Users.Add(User)
    End Sub
 

    Private Class UserEnumerator
        Implements IEnumerator
        Private m_Users As ArrayList
        Private m_Position As Int32 = -1 

        Public Sub New(ByVal Users As ArrayList)
            m_Users = Users
        End Sub
 

        Public ReadOnly Property Current() As _
          Object
Implements System.Collections.IEnumerator.Current
            Get
                Return m_Users(m_Position)
            End Get
        End Property
 

        ' Implementation of IEnumerator

        Public Function MoveNext() As Boolean _
            Implements
System.Collections.IEnumerator.MoveNext
            m_Position += 1
            If m_Position >= m_Users.Count Then
                Return False
            Else
                Return True
            End If
        End Function
 

        ' Implementation of IEnumerator
        Public Sub Reset() Implements System.Collections.IEnumerator.Reset
            m_Position = -1
        End Sub
    End Class

End Class

You can see from the previous class this extends the ArrayList and provides us with the ability to navigate through our Users collection.

The UserSearcher Class

In the next code block is what we use to populate the objects. Combined with the UserController class which provides the interaction with the backend system, in this case AD will create our User objects:

Public Class UserSearcher
    Private _items As New Users 

    Public Sub New() 

    End Sub 

    Public Property SearchItems()
        Get
            Return _items
        End Get

        Set(ByVal Value)
            _items = Value
        End Set
    End Property
 

    Public Sub AddSearchItemResult(ByVal Item As User)
        _items.AddUser(Item)
    End Sub

End
Class

UserController Class

Next we have our UserController class, which interacts with the backend systems, performs a search and then populates the users via the UserSearcher class. In order to instantiate our UserController, we will need to pass logon credentials for AD. This enables us to perform a search on AD and return the user collection:

Imports System.Security.Principal
Imports
System.DirectoryServices
Imports
System 

Public Class UserController

#Region "Private Members"
    'Private m_Users As New Users
    Private m_Directory As DirectoryEntry
    Private m_Domain As String
#End Region
 

#Region "Public Members"
    'Object creation, pass the domain, username, and password for searching the AD
    Public Sub New(ByVal Domain As String, ByVal UserName As String, _
       ByVal
Password As String)
        'Domain = in the form of "LDAP://domain.com/DC=domain,DC=com"
        m_Domain =
Domain
        m_Directory = New DirectoryEntry(m_Domain, UserName, Password)
    End Sub
#End Region
 

#Region "Controller Methods"
    'Accepts a filter string, and then searches AD for only users.
    'Returns an array of Users typed as a Users class.
    Public Function GetUsersByFilter(ByVal FilterString As _
       String
, Optional ByVal SizeLimit As Integer = 1000) As Users
        Dim Searcher As New DirectorySearcher(m_Directory)
        Dim SearchResultColl As SearchResultCollection
        Dim objSearchResult As SearchResult
        Searcher.SizeLimit = SizeLimit
        'see if they're typing in an extension
        Try
            Dim extension As Integer = CType(FilterString.Replace("-", ""), Integer)
            Searcher.Filter = "(&(objectClass=user)(telephoneNumber=*" & FilterString & "*))"
        Catch ex As Exception
            Searcher.Filter = "(&(objectClass=user)(displayName=" & FilterString & "*))"
        End Try
        SearchResultColl = Searcher.FindAll()
        Dim oSearch As New UserSearcher
        If Not SearchResultColl Is Nothing Then
            For Each objSearchResult In SearchResultColl
                Dim thisUser As New User
                thisUser = BuildSingleUser(objSearchResult)
                oSearch.AddSearchItemResult(thisUser)
            Next
            Return oSearch.SearchItems
        Else
            Return Nothing
        End If
    End Function
 

    'This method handles the populatation of the User object.
    Private Function BuildSingleUser(ByVal mySearchResult As SearchResult) As User
        Dim myUser As New User
        Dim myResultPropColl As ResultPropertyCollection
        Dim myResultPropValueColl As ResultPropertyValueCollection
        myResultPropColl = mySearchResult.Properties
        myUser.Email = BuildField("mail", myResultPropColl)
        myUser.DisplayName = BuildField("displayName", myResultPropColl)
        myUser.FirstName = BuildField("givenName", myResultPropColl)
        myUser.LastName = BuildField("sn", myResultPropColl)
        myUser.StreetAddress = BuildField("streetAddress", myResultPropColl)
        myUser.PostalCode = BuildField("postalCode", myResultPropColl)
        myUser.City = BuildField("l", myResultPropColl)
        myUser.State = BuildField("st", myResultPropColl)
        myUser.Phone = BuildField("telephoneNumber", myResultPropColl)
        myUser.Country = BuildField("co", myResultPropColl)
        myUser.EmployeeID = BuildField("employeeid", myResultPropColl)
        myUser.BudgetCenter = BuildField("extensionattribute6", myResultPropColl)
        myUser.PhysicalDeliveryOfficeName = _
          BuildField("PhysicalDeliveryOfficeName", myResultPropColl)
        myUser.Fax = BuildField("facsimileTelephoneNumber", myResultPropColl)
        myUser.Mobile = BuildField("mobile", myResultPropColl)
        myUser.OtherPhone = BuildField("othertelephone", myResultPropColl)
        myUser.ADsPath = BuildField("AdsPath", myResultPropColl)
        Return myUser
    End Function
 

   'for trapping a null data type returned from AD.
   Private
Function BuildField(ByVal FieldName As String, _
      ByVal
myResultPropColl As ResultPropertyCollection) As String
        If Not myResultPropColl Is Nothing Then
            Try
                Dim myResultPropValueColl As ResultPropertyValueCollection = _
                  myResultPropColl.Item(FieldName)
                Return myResultPropValueColl.Item(0)
            Catch ex As Exception
                Return "Null"
            End Try
        Else
            Return "Null"
        End If
    End Function
 

    'function to pull a single user account based on their account name.
    ' you can the type returned is of type user.
    Public
Function GetSingleUserByAccount(ByVal AccountName As String) As User
        Try
            Dim Searcher As New DirectorySearcher(m_Directory)
            Dim SearchResultColl As SearchResultCollection
            Searcher.Filter = ("(&(objectClass=user)(samaccountname=" & AccountName & "))")
            SearchResultColl = Searcher.FindAll()
            If Not SearchResultColl Is Nothing Then
                Return DefinedUser(SearchResultColl)
            Else
                Return Nothing
            End If
        Catch ex As Exception
            Throw ex
        End Try
    End Function
 

    Private Function DefinedUser(ByVal SearchResultColl As SearchResultCollection) As User
        Dim myUser As New User
        Dim mySearchResult As SearchResult
        Dim myResultPropColl As ResultPropertyCollection
        Dim myResultPropValueColl As ResultPropertyValueCollection
        mySearchResult = SearchResultColl.Item(0)
        myUser = BuildSingleUser(mySearchResult)
        Return myUser
    End Function
#End Region
 

End Class

Wrapping in Web Service

These classes are then compiled into their own assembly to be consumed by a client. The next block of code shows an example of a Web service calling our User assembly.

<WebMethod()> _
    Public Function GetSingleUserByAccount(ByVal SAMAccountName As _
       String
, ByVal DomainRoot As String) As User
        Dim myUser As New User
        Dim mySearch As New UserController(DomainRoot, UserName, Password)
        myUser = mySearch.GetSingleUserByAccount(SAMAccountName)
        Return myUser
    End Function
 

<WebMethod()> _
    Public Function GetUsersByFilter(ByVal FilterString As _
        String
, ByVal DomainRoot As String) As User()
        Dim myUsers As Users
        Dim User As User
        Dim al As New ArrayList
        Dim mySearch As New UserController(DomainRoot, UserName, Password)
        myUsers = mySearch.GetUsersByFilter(FilterString, 4000)
        For Each User In myUsers
            al.Add(User)
        Next
        Return al.ToArray(GetType(User))
    End Function

You'll notice we maintain our types on the Web service calls but return an array of user objects back to the calling client of the Web service. You can also see that we do not expose the AD credentials in our service, nor do we allow the values to be passed over the Web or intranet in order to avoid any packet sniffers gaining access to the information. In this particular implementation we opted to use the DPAPI and store the values in the registry in an encrypted format.

Then just call your user object from your client and work directly with user objects.

In this example we just exposed AD, but you can consolidate information from various sources in your single user object for your applications.

 


Page Options:
format for printing  Format for Printer
email article  Email Page
add to your favorites   Add to Favorites
How would you rate the quality of this content?
Poor - - Excellent
Comments?
Overall Rating:
Comments Left:
Left on 7/1/2008 1:33:45 PM by Anonymous
Comments: How can I get this into a Web application in VS 2005 what do I need to do. i am new to this .net development
Left on 7/1/2008 12:57:31 PM by Anonymous
Comments: How to build this out properly in Web App or Web services to get it working?
Left on 6/14/2005 4:05:22 AM by Anonymous
Comments: Nice! if it is possible then allow me to aske some questions
Left on 6/8/2005 6:53:04 AM by Anonymous
Comments: Rocks.
No ratings available.
Left on 6/8/2005 5:14:23 AM by Anonymous
Comments: much code for copying properties... maybe consider some o/r mapper
Left on 6/7/2005 11:58:49 PM by Anonymous
Comments: Darn I likle it :)
     
     

 

     
     

 


 


Digg This
 


DotNetNuke Platinum Benefactor

     
     

Other family network sites: santry.com - katieandkarleigh.com

Powered by 

 

     
Copyright 20010 - Santry Technology Solutions, Box 172, Girard, PA 16417, (814) 774-0970
Privacy Statement | Terms Of Use