A Custom Business Object (CBO) is essentially a blueprint, or representation, of an object that is important to the application. In DotNetNuke, an example of a CBO is an instance of the DotNetNuke.Services .FileSystem.FileInfo class in /components/FileSystem/FileInfo.vb. An instance of this class contains information about a single file as shown in Listing 7-2.
Listing 7-2: The FileInfo CBO Class
<XmlRoot("file", IsNullable:=False)> Public Class FileInfo Private _FileId As Integer Private _PortalId As Integer Private _FileName As String Private _Extension As String Private _Size As Integer Private _Width As Integer Private _Height As Integer Private _ContentType As String Private _Folder As String <XmlIgnore()> Public Property FileId() As Integer Get Return _FileId End Get Set(ByVal Value As Integer) _FileId = Value End Set End Property <XmlIgnore()> Public Property PortalId() As Integer Get Return _PortalId End Get Set(ByVal Value As Integer) _PortalId = Value End Set End Property <XmlElement("filename")> Public Property FileName() As String Get Return _FileName End Get Set(ByVal Value As String) _FileName = Value End Set End Property <XmlElement("extension")> Public Property Extension() As String Get Return _Extension End Get Set(ByVal Value As String) _Extension = Value End Set End Property <XmlElement("size")> Public Property Size() As Integer Get Return _Size End Get Set(ByVal Value As Integer) _Size = Value End Set End Property <XmlElement("width")> Public Property Width() As Integer Get Return _Width End Get Set(ByVal Value As Integer) _Width = Value End Set End Property <XmlElement("height")> Public Property Height() As Integer Get Return _Height End Get Set(ByVal Value As Integer) _Height = Value End Set End Property <XmlElement("contenttype")> Public Property ContentType() As String Get Return _ContentType End Get Set(ByVal Value As String) _ContentType = Value End Set End Property <XmlElement("folder")> Public Property Folder() As String Get Return _Folder End Get Set(ByVal Value As String) _Folder = Value End Set End Property End Class
The FileInfo class has no methods, only properties. This is an important distinction to recognize — CBOs only have properties. The methods to manage the CBO are in a CBO Controller class specific to the CBO. A CBO Controller class contains the business logic necessary to work with its associated CBO class. For example, there is a FileController class in /components/FileSystem/FileController.vb that contains business logic for the FileInfo CBO. For the sake of the core File Manager module, the FileInfo data is stored in the database. Therefore, the FileController class contains the logic necessary to hydrate the FileInfo object (or a collection of FileInfo objects) with data retrieved from the database.
One powerful core service is the CBO Hydrator, which is located in the CBO class in /components/ Shared/CBO.vb. It is a collection of methods that provide a centralized means of hydrating a CBO or a collection of CBOs.
Figure 7-2 shows how a CBO Controller class makes a call to the CBO Hydrator by sending in an open DataReader and the type of object to fill. Depending on the method called within the CBO Hydrator, it returns either a single hydrated object or a collection of hydrated objects. When the CBO Hydrator fills an object's properties, it discovers the properties of the CBO using reflection. Then it caches the properties that it has discovered so that the next time an object of the same type is hydrated, the properties won't need to be discovered. Instead, they can be pulled from the cache.
Figure 7-2
To hydrate a collection of CBOs, use the DotNetNuke.Common.Utilities.CBO.FillCollection method. The method accepts an IDataReader and a type as input parameters. It returns an ArrayList of objects of the type specified in the objType parameter. For example, the code-behind for the Portals module ($AppRoot/admin/Portal/Portals.ascx.vb) needs a collection of PortalInfo objects so it can display a list of Portals in the portal module's rendered output. The code-behind calls DotNetNuke.Entities.Portals .PortalController.GetPortals() to get an ArrayList of PortalInfo objects. That ArrayList is filled by the DotNetNuke.Common.Utilities.CBO.FillCollection method, which converts an iDataReader object (from a database query) into a collection of hydrated PortalInfo objects. Here's the DotNetNuke .Common.Utilities.CBO.FillCollection method signature:
Public Shared Function FillCollection(ByVal dr As IDataReader, ByVal objType As _ Type) As ArrayList
To hydrate a single CBO rather than a collection, use the CBO.FillObject method. It accepts the same input parameters, but returns a single object. For example, in the code-behind for the Site Settings module ($AppRoot/Admin/Portal/SiteSettings.ascx.vb), the control needs a PortalInfo object to display the portal settings in the module's rendered output. The code-behind gets the PortalInfo object from a call to DotNetNuke.Entities.Portals.PortalController.GetPortal. The GetPortal method uses the DotNetNuke.Common.Utilities.CBO.FillObject method to convert an iDataReader object (from a database query) into a hydrated PortalInfo object. Following is the method signature for DotNetNuke.Common.Utilities.CBO.FillObject:
Public Shared Function FillObject(ByVal dr As IDataReader, ByVal _ objType As Type) As Object
The FileController shown in Listing 7-3 is an example of a CBO Controller that utilizes the CBO Hydrator.
Listing 7-3: The FileController CBO Controller Class
Public Class FolderController Public Function GetFoldersByPortal(ByVal PortalID As Integer) As ArrayList Return _ CBO.FillCollection(DataProvider.Instance().GetFoldersByPortal(PortalID), _ GetType(Services.FileSystem.FolderInfo)) End Function Public Function GetFolder(ByVal PortalID As Integer, ByVal FolderPath As _ String) As FolderInfo Return CType(CBO.FillObject(DataProvider.Instance().GetFolder(PortalID, _ FolderPath), GetType(Services.FileSystem.FolderInfo)), FolderInfo) End Function Public Function GetFolder(ByVal PortalID As Integer, ByVal FolderID As Integer) As ArrayList Return CBO.FillCollection(DataProvider.Instance().GetFolder(PortalID, _ FolderID), GetType(Services.FileSystem.FolderInfo)) End Function Public Function AddFolder(ByVal objFolderInfo As FolderInfo) As Integer ReturnDataProvider.Instance().AddFolder(objFolderInfo.PortalID, _ objFolderInfo.FolderPath) End Function Public Sub UpdateFolder(ByVal objFolderInfo As FolderInfo) DataProvider.Instance().UpdateFolder(objFolderInfo.PortalID, _ objFolderInfo.FolderID, objFolderInfo.FolderPath) End Sub Public Sub DeleteFolder(ByVal PortalID As Integer, ByVal FolderPath As String) DataProvider.Instance().DeleteFolder(PortalID, FolderPath) End Sub End Class
Using the CBO Hydrator significantly reduces the amount of code needed to fill an object or collection of objects. Without using the CBO Hydrator, you would have to code at least one line per CBO property to fill that object with the contents of a DataReader. Listing 7-4 is an example of filling a single FileInfo object without using the CBO Hydrator.
Listing 7-4: Traditional Method of Filling an Object
Dim dr As IDataReader Try dr = DataProvider.Instance().GetFolder(PortalID, FolderPath) Dim f As New FileInfo f.ContentType = Convert.ToString(dr("ContentType")) f.Extension = Convert.ToString(dr("Extension")) f.FileId = Convert.ToInt32(dr("FileId")) f.FileName = Convert.ToString(dr("FileName")) f.Folder = Convert.ToString(dr("Folder")) f.Height = Convert.ToInt32(dr("Height")) f.PortalId = Convert.ToInt32(dr("PortalId")) f.Size = Convert.ToInt32(dr("Size")) f.Width = Convert.ToInt32(dr("Width")) Return f Finally If Not dr Is Nothing Then dr.Close() End If End Try
Instead of writing all of that code, the CBO Hydrator can be used to greatly simplify things. The code in Listing 7-5 does the same thing as the code in Listing 7-4, except it uses the CBO Hydrator.
Listing 7-5: Filling an Object Using the CBO Hydrator
Return CType(CBO.FillObject(DataProvider.Instance().GetFolder(PortalID, _ FolderPath), GetType(Services.FileSystem.FolderInfo)), FolderInfo)
Custom Business Objects are used throughout DotNetNuke to create a truly object-oriented design. The objects provide for type safety and enhance performance by allowing code to work with disconnected collections rather than with DataReaders, DataTables, or DataSets. Use the CBO Hydrator whenever possible to reduce the amount of coding and to enhance the maintainability of the application.