Download as pdf or txt
Download as pdf or txt
You are on page 1of 26

Tài liệu xây dựng DAL+ của DotNET Nuke.

Các bạn chỉ cần dựa theo cấu trúc để xây dựng.

Setting Up The Module


We will create the module using the following steps:

· Create the DAL+


o Create the "info class"
o Create the "controller class"
· Create the "View" control
o Create The Grid View and Form View
o Create the code behind
· Create the tables and stored procedures

Create The Directories


Open your DotNetNuke website in Visual Studio.

Create the DAL+


First we will create the Data Access Layer using the DAL+ method. This is the class that
communicates with the database.

Create the "info class"


Right-click on the "App_Code" folder and select "New Folder"
Name the new folder "ThingsForSale"

Right-click on the "ThingsForSale" folder you just created and select "Add New Item"

In the "Add New Item" box that opens, click on "Class" under "Visual Studio Installed
Templates", enter "ThingsForSaleInfo.vb" in the "Name" box and click the "Add" button.

The class will now open up in the designer.


Replace ALL the code with the following code:

Namespace YourCompany.Modules.ThingsForSale

Public Class ThingsForSaleInfo

Private _ModuleId As Integer


Private _ID As Integer
Private _UserID As Integer
Private _Category As String
Private _Description As String
Private _Price As Double
' initialization
Public Sub New()
MyBase.New()
End Sub
' <summary>
' Gets and sets the Module Id
' </summary>
Public Property ModuleId() As Integer
Get
Return _ModuleId
End Get
Set(ByVal value As Integer)
_ModuleId = value
End Set
End Property
' <summary>
' Gets and sets the Item ID
' </summary>
Public Property ID() As Integer
Get
Return _ID
End Get
Set(ByVal value As Integer)
_ID = value
End Set
End Property
' <summary>
' Gets and sets the UserID
' </summary>
Public Property UserID() As Integer
Get
Return _UserID
End Get
Set(ByVal value As Integer)
_UserID = value
End Set
End Property
' <summary>
' Gets and sets the Category
' </summary>
Public Property Category() As String
Get
Return _Category
End Get
Set(ByVal value As String)
_Category = value
End Set
End Property
' <summary>
' Gets and sets the Description
' </summary>
Public Property Description() As String
Get
Return _Description
End Get
Set(ByVal value As String)
_Description = value
End Set
End Property
' <summary>
' Gets and sets the Price
' </summary>
Public Property Price() As Double
Get
Return _Price
End Get
Set(ByVal value As Double)
_Price = value
End Set
End Property

End Class

End Namespace

"controller class"
Right-click on the "ThingsForSale" folder and select "Add New Item".

In the "Add New Item" box that opens, click on "Class" under "Visual Studio Installed
Templates", enter "ThingsForSaleController.vb" in the "Name" box and click the "Add"
button.
The class will now open up in the designer.

Replace ALL the code with the following code:

Imports System
Imports System.Collections.Generic
Imports System.Data
Namespace YourCompany.Modules.ThingsForSale

Public Class ThingsForSaleController

<DataObjectMethod(DataObjectMethodType.Insert)> _
Public Shared Sub ThingsForSale_Insert(ByVal ThingsForSaleInfo As ThingsForSaleInfo)
DataProvider.Instance().ExecuteNonQuery("ThingsForSale_Insert", ThingsForSaleInfo.ModuleId,
GetNull(ThingsForSaleInfo.UserID), GetNull(ThingsForSaleInfo.Category.ToString),
GetNull(ThingsForSaleInfo.Description.ToString), GetNull(ThingsForSaleInfo.Price))
End Sub

<DataObjectMethod(DataObjectMethodType.Delete)> _
Public Shared Sub ThingsForSale_Delete(ByVal ThingsForSaleInfo As ThingsForSaleInfo)
DataProvider.Instance().ExecuteNonQuery("ThingsForSale_Delete", ThingsForSaleInfo.ID)
End Sub

<DataObjectMethod(DataObjectMethodType.Update)> _
Public Shared Sub ThingsForSale_Update(ByVal ThingsForSaleInfo As ThingsForSaleInfo)
DataProvider.Instance().ExecuteNonQuery("ThingsForSale_Update", ThingsForSaleInfo.ID,
ThingsForSaleInfo.ModuleId, GetNull (ThingsForSaleInfo.UserID),
GetNull(ThingsForSaleInfo.Category.ToString), GetNull(ThingsForSaleInfo.Description.ToString),
GetNull(ThingsForSaleInfo.Price))
End Sub

<DataObjectMethod(DataObjectMethodType.Select)> _
Public Shared Function ThingsForSale_SelectAll(ByVal ModuleId As Integer) As List(Of ThingsForSaleInfo)
Return CBO.FillCollection(Of
ThingsForSaleInfo)(CType(DataProvider.Instance().ExecuteReader("ThingsForSale_SelectAll", ModuleId),
IDataReader))
End Function

Private Shared Function GetNull(ByVal Field As Object) As Object


Return Null.GetNull(Field, DBNull.Value)
End Function

End Class

End Namespace

This time we did a lot. However, we did a lot without using a lot of code.

We have constructed a class called "ThingsForSaleController" that has 4 public methods. Each
of these methods uses one of the new methods of the DAL+ to execute stored procedures.
We haven't created the stored procedures yet. We will do that in a later step. For now, we have
simply created a method for each task we will need to perform with the database:

· Delete - (ThingsForSale_Delete)
· Insert - (ThingsForSale_Insert)
· Select - (ThingsForSale_SelectAll)
· Update - (ThingsForSale_Update)

Note: A protected method, "GetNull" is used to pass the proper null value to the database for any
values that could be empty.

The Delete, Insert, and Update methods accept the "ThingsForSaleInfo" class that was created
previously as a parameter.

The SelectAll methods takes an integer as a parameter and RETURNS a "ThingsForSaleInfo"


class.

The DAL+ is comprised of 4 methods used to execute stored procedures. The methods are:

· ExecuteNonQuery - Used to execute a stored procedure that will not return a value.
· ExecuteReader - Used to execute a stored procedure that will return multiple records.
· ExecuteScalar - Used to execute a stored procedure that will return a single value.
· ExecuteSQL - Used to execute a sql statement.
The Delete, Insert, and Update methods use the ExecuteNonQuery method of the DAL+ and
the SelectAll method uses the ExecuteReader method of the DAL+ (the ExecuteScalar and
ExecuteSQL methods of the DAL+ are not used in this tutorial).

Below is an explanation of the format used to implement the DAL+. The ExecuteReader
method that is used in the "ThingsForSale_SelectAll" method is used in this example:

We have completed creating the DAL+ for our module.

"View" control

Complete The Code


The steps that remain are:

· Create the "View" control


o Create The Grid View and Form View
o Create the code behind
· Create the tables and stored procedures
· Register the module in DotNetNuke

Remember, A DotNetNuke module resides in 2 directories:

· The Web User Controls and their associated code behind files reside in the
"DesktopModules" directory.
· All other code resides in the "App_Code" directory.

We have created the DAL+ code in the "App_Code" directory. We will now complete the
module by creating the Web User Control in the "DesktopModules" directory.
Create The Directory
Right-click on the "DesktopModules" folder and select "New Folder"

Name the new folder "ThingsForSale"

Create the "View" control


Right-click on the "ThingsForSale" folder you just created and select "Add New Item"
In the "Add New Item" box that opens:

· Click on "Web User Control" under "Visual Studio Installed Templates".


· Enter "ViewThingsForSale.ascx" in the "Name" box.
· Make sure the "Place code in a separate file" box is checked.
· Click the "Add" button.

The "ViewThingsForSale.ascx" file will be created in the "ThingsForSale" folder under the
"DesktopModules" folder.

Clicking the "plus" icon next to the file will display the associated code behind file
"ViewThingsForSale.ascx.vb".
Create The Grid View and Form View
Double-click on the "ViewThingsForSale.ascx" file and it will open up in the main editing
window. Right now the page will be blank. Click the "Source" button at the bottom of the page
to switch to source view.

Replace ALL the code with the following code: <%@ Control language="vb"
Inherits="YourCompany.Modules.ThingsForSale.ViewThingsForSale" CodeFile="ViewThingsForSale.ascx.vb"
AutoEventWireup="false" Explicit="True" %>
<%@ Register Assembly="DotNetNuke.WebUtility" Namespace="DotNetNuke.UI.Utilities" TagPrefix="cc1" %>
<%@ Register TagPrefix="dnn" TagName="Audit" Src="~/controls/ModuleAuditControl.ascx" %> <br />

<asp:ObjectDataSource ID="ObjectDataSource_ThingsForSale" runat="server"


DataObjectTypeName="YourCompany.Modules.ThingsForSale.ThingsForSaleInfo"
DeleteMethod="ThingsForSale_Delete" InsertMethod="ThingsForSale_Insert"
OldValuesParameterFormatString="original_{0}"
OnInit="Page_Load" SelectMethod="ThingsForSale_SelectAll"
TypeName="YourCompany.Modules.ThingsForSale.ThingsForSaleController"
UpdateMethod="ThingsForSale_Update">
<SelectParameters>
<asp:Parameter DefaultValue="00" Name="ModuleId" Type="Int32" />
</SelectParameters>
</asp:ObjectDataSource>

<asp:GridView ID="GridView1" runat="server" AllowPaging="True" AutoGenerateColumns="False"


DataSourceID="ObjectDataSource_ThingsForSale" DataKeyNames="ID,UserID,ModuleId" CellPadding="4"
CellSpacing="1" EnableViewState="False">
<Columns>
<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
<asp:BoundField DataField="UserID" HeaderText="UserID" SortExpression="UserID" Visible="False" />
<asp:BoundField DataField="ModuleId" HeaderText="ModuleId" SortExpression="ModuleId" Visible="False" />
<asp:BoundField DataField="ID" HeaderText="ID" SortExpression="ID" Visible="False" />
<asp:BoundField DataField="Category" HeaderText="Category" SortExpression="Category" />
<asp:BoundField DataField="Price" HeaderText="Price" SortExpression="Price" DataFormatString="{0:c}"
HtmlEncode="False" />
<asp:BoundField DataField="Description" HeaderText="Description" SortExpression="Description" />
</Columns>
<EmptyDataTemplate>
There are no Things 4 Sale
</EmptyDataTemplate>
</asp:GridView>
<br />
<asp:LinkButton ID="Add_My_Listing_LinkButton" runat="server" EnableViewState="False">Add My
Listing</asp:LinkButton><br />
<br />

<asp:FormView ID="FormView1" runat="server" DataKeyNames="ID"


DataSourceID="ObjectDataSource_ThingsForSale"
DefaultMode="Insert" BorderColor="DarkGray" BorderStyle="Solid" BorderWidth="1px" CellPadding="4"
Visible="False">
<EditItemTemplate>
</EditItemTemplate>
<InsertItemTemplate>
Category:&nbsp;<asp:DropDownList ID="DropDownList1" runat="server" DataSource='<%# Eval("Category")
%>'
SelectedValue='<%# Bind("Category") %>' EnableViewState="False">
<asp:ListItem>Home</asp:ListItem>
<asp:ListItem>Office</asp:ListItem>
<asp:ListItem>Electronics</asp:ListItem>
<asp:ListItem>Misc.</asp:ListItem>
</asp:DropDownList>&nbsp;
Price: $
<asp:TextBox ID="PriceTextBox" runat="server" Text='<%# Bind("Price") %>' Width="56px"
CausesValidation="True" EnableViewState="False"></asp:TextBox><br />
<asp:RangeValidator ID="RangeValidator1" runat="server" ControlToValidate="PriceTextBox"
ErrorMessage="Price must be greater than 0" MaximumValue="99999"
MinimumValue="1"></asp:RangeValidator>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ControlToValidate="PriceTextBox"
ErrorMessage="A price is required"></asp:RequiredFieldValidator><br />
Description:<br />
<asp:TextBox ID="DescriptionTextBox" runat="server" Text='<%# Bind("Description") %>' MaxLength="499"
TextMode="MultiLine" Width="286px" EnableViewState="False"></asp:TextBox><br />
<asp:LinkButton ID="InsertButton" runat="server" CausesValidation="True" CommandName="Insert"
Text="Insert" OnClick="InsertButton_Click"></asp:LinkButton>
<asp:LinkButton ID="InsertCancelButton" runat="server" CausesValidation="False" CommandName="Cancel"
Text="Cancel" OnClick="InsertCancelButton_Click"></asp:LinkButton>
<asp:TextBox ID="ModuleIdTextBox" runat="server" Text='<%# Bind("ModuleId") %>' Width="14px"
Visible="False"></asp:TextBox>
<asp:TextBox ID="IDTextBox" runat="server" Text='<%# Bind("ID") %>' Width="13px"
Visible="False"></asp:TextBox>
<asp:TextBox ID="UserIDTextBox" runat="server" Text='<%# Bind("UserID") %>'
Width="10px" Visible="False"></asp:TextBox>
</InsertItemTemplate>
<ItemTemplate>
</ItemTemplate>
</asp:FormView>

Click the "Design" button at the bottom of the design window and the screen will look like the
image on the right.
We placed 4 controls on the page:

· ObjectDataSource Control
o This is at the top of the image on the right. It is labeled "ObjectDataSource".
This control is bound to the "ThingsForSaleController" class created in the
earlier step.
· GridView Control
o This control is immediately under the "ObjectDataSource" control. This control
is bound to the "ObjectDataSource" control and is configured to Select, Update,
and Delete.
· LinkButton Control
o This is a simple LinkButton that will display messages and when clickable, will
allow the FormView control below it to display.
· FormView Control
o This control will allow a user to enter an item into the database. it is also bound to
the "ObjectDataSource" control and is configured to Insert.

A little more about the ObjectDataSource Control


Hover the mouse over the "ObjectDataSource" control until the small black arrow appears.

Click on it and the configuration menu will appear. click on "Configure Data Source".

The "ThingsForSaleController" class is configured as the Object Data Source.

Click the "Next >" button.


The next screen shows 4 tabs (Select, Update, Insert, and Delete). clicking on each tab reveals
that a different method of the "ThingsForSaleController" class is configured to handle each
function.

Click the "Next >" button.


The final screen shows the configuration for the parameter that is passed to the Select method.

Here we indicate "ModuleId" with a default value of "00". This is just a "place holder".

The actual value will be supplied at run-time by code in a later step.


In the properties window of the "ObjectDataSource" control we see that the
"DataObjectTypeName" is set to our "ThingsForSaleInfo" class that was created in a previous
step.

This is how we indicate that this class will be used to pass data between the
"ObjectDataSource" control and the "ThingsForSaleController" class.
Create the code behind
Double-click on the "ViewThingsForSale.ascx.vb" file so that it opens up in the design
window.

Replace ALL the code with the following code: Imports DotNetNuke
Imports System.Web.UI
Imports System.Collections.Generic
Imports System.Reflection
Imports DotNetNuke.Security.PortalSecurity

Namespace YourCompany.Modules.ThingsForSale

Partial Class ViewThingsForSale

Inherits Entities.Modules.PortalModuleBase

Dim ThingsForSaleInfo_data As New ThingsForSaleInfo

Protected Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load

If IsInRole("Registered Users") Or IsInRole("Administrators") Then


Add_My_Listing_LinkButton.Enabled = True
Else
Add_My_Listing_LinkButton.Text = "You must be logged in to add a Listing"
Add_My_Listing_LinkButton.Enabled = False
End If

End Sub

Protected Sub SetModuleId(ByVal sender As Object, ByVal e As


System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles
ObjectDataSource_ThingsForSale.Selecting

e.InputParameters("ModuleId") = ModuleId.ToString

End Sub

Protected Sub InsertingItem(ByVal sender As Object, ByVal e As


System.Web.UI.WebControls.FormViewInsertEventArgs) Handles FormView1.ItemInserting

e.Values.Item("UserID") = Entities.Users.UserController.GetCurrentUserInfo.UserID
e.Values.Item("ModuleId") = ModuleId.ToString()
e.Values.Item("ID") = 0
End Sub

Protected Sub InsertCancelButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)

Me.FormView1.Visible = False

End Sub

Protected Sub Add_My_Listing_LinkButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)


Handles Add_My_Listing_LinkButton.Click

Me.FormView1.Visible = True

End Sub

Protected Sub InsertButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)

Me.FormView1.Visible = False
Add_My_Listing_LinkButton.Text = "Update Successful - Add Another Listing"

End Sub

Protected Sub HideEditButtons(ByVal sender As Object, ByVal e As


System.Web.UI.WebControls.GridViewRowEventArgs) Handles GridView1.RowDataBound

If e.Row.RowType = DataControlRowType.DataRow Then


ThingsForSaleInfo_data = CType(e.Row.DataItem, ThingsForSaleInfo)
If IsInRole("Administrators") Or (Entities.Users.UserController.GetCurrentUserInfo.UserID =
CInt(ThingsForSaleInfo_data.UserID)) Then
e.Row.Cells.Item(0).Enabled = True
Else
e.Row.Cells.Item(0).Text = "&nbsp;"
End If
End If

End Sub

End Class

End Namespace

We entered code that will handle:


· Only allowing a person who is a registered user or an administrator to add an entry
(IsInRole("Registered Users") Or IsInRole("Administrators") )
· Only allowing a person to edit their own entries
(Entities.Users.UserController.GetCurrentUserInfo.UserID = CInt(ThingsForSaleInfo_data.UserID)
· Injecting the current "ModuleId" into the "ObjectDataSource" control.

Hopefully this will help those using Object Data Sources with DotNetNuke. There is a problem
of grabbing the current “ModuleId”.

This is a very important value that is exposed by the DotNetNuke core code. This value tells you
which instance of the module you are working with. This is important because a person can place
multiple instances of your module on a single page. You can’t have them click a button on one
instance of the module and return data from another instance of the module.

You can see the solution in “ViewThingsForSale.ascx” and “ViewThingsForSale.ascx.vb”. In


the “ViewThingsForSale.ascx” file, in the "ObjectDataSource" control, we indicate the
“ModuleId” parameter as a “Select” parameter that will be passed to the “Select” method:

In “ViewThingsForSale.ascx.vb” we have this:

Protected Sub SetModuleId(ByVal sender As Object, ByVal e As


System.Web.UI.WebControls.ObjectDataSourceSelectingEventArgs) Handles
ObjectDataSource_ThingsForSale.Selecting
e.InputParameters("ModuleId") = ModuleId.ToString
End Sub

This event fires when the “Select” event is called in the "ObjectDataSource" control, but before
the control passes the value to the “SelectAll” method in the "ThingsForSaleController" class.
This allows you to pass the “ModuleId” to the "ThingsForSaleController" class (and on to the
"ThingsForSale_SelectAll" stored procedure so it returns the proper data).

Compile and Build The Module


From the toolbar select "Build" then "Build Solution"
The site should build with no errors

In the SOLUTION EXPLORER right-click on the "Default.aspx" page and select SET AS
START PAGE
From the toolbar select DEBUG then START WITHOUT DEBUGGING

The website should now come up.


Create the tables and stored
procedures
/** Create Table **/

CREATE TABLE {databaseOwner}[{objectQualifier}ThingsForSale] (


[ID] [int] IDENTITY(1,1) NOT NULL,
[ModuleId] [int] NOT NULL,
[UserID] [int] NULL,
[Category] [nvarchar](25),
[Description] [nvarchar](500),
[Price] [float] NULL
) ON [PRIMARY]

ALTER TABLE {databaseOwner}[{objectQualifier}ThingsForSale] ADD


CONSTRAINT [PK_{objectQualifier}ThingsForSale] PRIMARY KEY CLUSTERED
([ID]) ON [PRIMARY]

GO
/** Create Stored Procedures **/

CREATE PROCEDURE {databaseOwner}[{objectQualifier}ThingsForSale_Delete]


@ID int
AS
DELETE FROM {objectQualifier}ThingsForSale
WHERE (ID = @ID)
RETURN
GO

CREATE PROCEDURE {databaseOwner}[{objectQualifier}ThingsForSale_Insert]


@ModuleId int,
@UserID int,
@Category nvarchar(25),
@Description nvarchar(500),
@Price float
AS
INSERT INTO {objectQualifier}ThingsForSale
(ModuleId, UserID, Category, Description, Price)
VALUES (@ModuleId,@UserID,@Category,@Description,@Price)
RETURN
GO

CREATE PROCEDURE {databaseOwner}[{objectQualifier}ThingsForSale_SelectAll]


@ModuleId int
AS
SELECT ID, ModuleId, UserID, Category, Description, Price
FROM {objectQualifier}ThingsForSale
WHERE (ModuleId = @ModuleId)
ORDER BY Category
RETURN
GO

CREATE PROCEDURE {databaseOwner}[{objectQualifier}ThingsForSale_Update]


@ID int,
@ModuleId int,
@UserID int,
@Category nvarchar(25),
@Description nvarchar(500),
@Price float
AS
UPDATE {objectQualifier}ThingsForSale
SET ModuleId = @ModuleId, UserID = @UserID, Category = @Category, Description = @Description, Price =
@Price
WHERE (ID = @ID)
RETURN

We ran a SQL script that created the table and the stored procedures.

You will notice that the script is written like:


CREATE TABLE {databaseOwner}[{objectQualifier}ThingsForSale]

rather than the normal:

CREATE TABLE [dbo][ThingsForSale]

The script commands "{databaseOwner}" and "{objectQualifier}" indicate that they are to be
replaced by configuration settings in the web.config file. Normally "{databaseOwner}" is set to
".dbo" and "{objectQualifier}" is set to nothing (it would not have a setting). However, if
alternate settings were indicated in the web.config file, those settings would be inserted into the
script.

You must have the "Run as Script" box checked for this replacement to happen.

You might also like