DNN 模块插件开发全程详解 (一)
2006-11-22 14:35 by 风云, 1068 visits, 收藏, 编辑我今天刚开发了一个DNN插件,也是我第一次开发DNN插件,我把开发的过程描述下来,对于精通DNN的希望多多指点,对于希望涉足DNN的起到抛砖引玉的作用.
本示例以一张基本的表Department的CRUD来说明用C#制作DNN4.3插件的全过程
1:首先创建Department表
(ModuleID,DepartmentID,DepartmentName,CreatedByUser,CreatedDate),
DepartmentID是主键
通过ModuleID建立Department表和Modules表的关系(ModuleID字段是实现模块插件的关键)
创建对应的CRUD存储过程
2:创建部门模块的内核部分
2.1: 创建VS2005的类库项目
2.2 添加DotNetNuke.dll 引用
2.3 添加DepartmentInfo实体类
using System;
using System.Configuration;
using System.Data;
namespace ISS.DNN.Modules.Department
{
/**//**//**//// -----------------------------------------------------------------------------
///<summary>
/// The Info class for the Department
/// </summary>
/// <remarks>
/// </remarks>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public class DepartmentInfo
![]()
{
Private MembersPrivate Members#region Private Members
private int _ModuleId;
private int _DepartmentID;
private string _DepartmentName;
private int _CreatedByUser;
private DateTime _CreatedDate;
private string _CreatedByUserName;
#endregion
ConstructorsConstructors#region Constructors
// initialization
public DepartmentInfo()
![]()
{
}
#endregion
Public MethodsPublic Methods#region Public Methods
/**//**//**//// <summary>
/// Gets and sets the Module Id
/// </summary>
public int ModuleId
![]()
{
get
![]()
{
return _ModuleId;
}
set
![]()
{
_ModuleId = value;
}
}
/**//**//**//// <summary>
/// Gets and sets the Item Id
/// </summary>
public int DepartmentId
![]()
{
get
![]()
{
return _DepartmentID;
}
set
![]()
{
_DepartmentID = value;
}
}
/**//**//**//// <summary>
/// gets and sets the DepartmentName
/// </summary>
public string DepartmentName
![]()
{
get
![]()
{
return _DepartmentName;
}
set
![]()
{
_DepartmentName = value;
}
}
/**//**//**//// <summary>
/// Gets and sets the User Id who Created/Updated the DepartmentName
/// </summary>
public int CreatedByUser
![]()
{
get
![]()
{
return _CreatedByUser;
}
set
![]()
{
_CreatedByUser = value;
}
}
/**//**//**//// <summary>
/// Gets and sets the User Id who Created/Updated the DepartmentName
/// </summary>
public string CreatedByUserName
![]()
{
get
![]()
{
return _CreatedByUserName;
}
set
![]()
{
_CreatedByUserName = value;
}
}
/**//**//**//// <summary>
/// Gets and sets the Date when Created/Updated
/// </summary>
public DateTime CreatedDate
![]()
{
get
![]()
{
return _CreatedDate;
}
set
![]()
{
_CreatedDate = value;
}
}
#endregion
![]()
}
}
2.4 创建DataProvider抽象类并添加一下代码
using System;
using DotNetNuke;
using System.Data;
using DotNetNuke.Framework;
namespace ISS.DNN.Modules.Department

{
/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// An abstract class that provides the DAL contract
/// </summary>
/// <remarks>
/// </remarks>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public abstract class DataProvider
{

Shared/Static MethodsShared/Static Methods#region Shared/Static Methods
// singleton reference to the instantiated object
static DataProvider objProvider = null;
// constructor
static DataProvider()
{
CreateProvider();
}
// dynamically create provider
//一定要注意DataProvider的配置节department
private static void CreateProvider()
{
objProvider = (DataProvider)Reflection.CreateObject("department");
}
// return the provider
public static DataProvider Instance() 
{
return objProvider;
}
#endregion

Abstract methodsAbstract methods#region Abstract methods
public abstract void AddDepartment(int ModuleId, string DepartmentName, int UserId);
public abstract IDataReader GetDepartment(int ModuleId, int DepartmentID);
public abstract IDataReader GetDepartments(int ModuleId);
public abstract void UpdateDepartment(int ModuleId, int DepartmentID, string DepartmentName, int UserId);
public abstract void DeleteDepartment(int ModuleId, int DepartmentID);
#endregion
}
}
2.5 创建业务控制类DepartmentController
using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Xml;
using System.Web;
using DotNetNuke;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Services.Search;
namespace ISS.DNN.Modules.Department

{
/**//**//**//// -----------------------------------------------------------------------------
///<summary>
/// The Controller class for the Department
/// </summary>
/// <remarks>
/// </remarks>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public class DepartmentController : ISearchable, IPortable
{

ConstructorsConstructors#region Constructors
public DepartmentController()
{
}
#endregion

Public MethodsPublic Methods#region Public Methods

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// adds an object to the database
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="objDepartment">The DepartmentInfo object</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public void AddDepartment(DepartmentInfo objDepartment)
{
if (objDepartment.DepartmentName.Trim() != "")
{
DataProvider.Instance().AddDepartment(objDepartment.ModuleId, objDepartment.DepartmentName, objDepartment.CreatedByUser);
}
}

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// deletes an object from the database
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="ModuleId">The Id of the module</param>
/// <param name="DepartmentId">The Id of the item</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public void DeleteDepartment(int ModuleId, int DepartmentID) 
{
DataProvider.Instance().DeleteDepartment(ModuleId,DepartmentID);
}

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// gets an object from the database
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="moduleId">The Id of the module</param>
/// <param name="DepartmentId">The Id of the item</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public DepartmentInfo GetDepartment(int ModuleId, int DepartmentID)
{
return CBO.FillObject (DataProvider.Instance().GetDepartment(ModuleId, DepartmentID),typeof(DepartmentInfo)) as DepartmentInfo;
}

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// gets an object from the database
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="moduleId">The Id of the module</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public IList GetDepartments(int ModuleId)
{
return CBO.FillCollection(DataProvider.Instance().GetDepartments(ModuleId),typeof(DepartmentInfo));
}

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// saves an object to the database
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="objDepartment">The DepartmentInfo object</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public void UpdateDepartment(DepartmentInfo objDepartment)
{
if (objDepartment.DepartmentName.Trim() != "")
{
DataProvider.Instance().UpdateDepartment(objDepartment.ModuleId, objDepartment.DepartmentId, objDepartment.DepartmentName, objDepartment.CreatedByUser);
}
}
#endregion

Optional InterfacesOptional Interfaces#region Optional Interfaces

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// GetSearchItems implements the ISearchable Interface
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="ModInfo">The ModuleInfo for the module to be Indexed</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public SearchItemInfoCollection GetSearchItems(ModuleInfo ModInfo)
{
SearchItemInfoCollection SearchItemCollection = new SearchItemInfoCollection();
IList colDepartments = GetDepartments(ModInfo.ModuleID);
foreach (DepartmentInfo objDepartment in colDepartments)
{
if(objDepartment != null)
{
SearchItemInfo SearchItem = new SearchItemInfo(ModInfo.ModuleTitle, objDepartment.DepartmentName, objDepartment.CreatedByUser, objDepartment.CreatedDate, ModInfo.ModuleID, objDepartment.DepartmentId.ToString(), objDepartment.DepartmentName, "DepartmentId=" + objDepartment.DepartmentId.ToString());
SearchItemCollection.Add(SearchItem);
}
}
return SearchItemCollection;
}


/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// ExportModule implements the IPortable ExportModule Interface
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="ModuleID">The Id of the module to be exported</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public string ExportModule(int ModuleID)
{
string strXML = "";
IList colDepartments = GetDepartments(ModuleID);
if (colDepartments.Count != 0)
{
strXML += "<Departments>";
foreach (DepartmentInfo objDepartment in colDepartments)
{
strXML += "<Department>";
strXML += "<DepartmentName>" + XmlUtils.XMLEncode(objDepartment.DepartmentName) + "</DepartmentName>";
strXML += "</Department>";
}
strXML += "</Departments>";
}
return strXML;
}

/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// ImportModule implements the IPortable ImportModule Interface
/// </summary>
/// <remarks>
/// </remarks>
/// <param name="ModuleID">The Id of the module to be imported</param>
/// <param name="DepartmentName">The DepartmentName to be imported</param>
/// <param name="Version">The version of the module to be imported</param>
/// <param name="UserId">The Id of the user performing the import</param>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public void ImportModule(int ModuleID, string DepartmentName, string Version, int UserId)
{
XmlNode xmlDepartments = Globals.GetContent(DepartmentName, "Departments");
foreach (XmlNode xmlDepartment in xmlDepartments.SelectNodes("Department"))
{
DepartmentInfo objDepartment = new DepartmentInfo();
objDepartment.ModuleId = ModuleID;
objDepartment.DepartmentName = xmlDepartment.SelectSingleNode("DepartmentName").InnerText;
objDepartment.CreatedByUser = UserId;
AddDepartment(objDepartment);
}
}
#endregion
}
}
2.6 创建UI 部门浏览控件ViewDepartment,这个类一定要继承PortalModuleBase,该类是DNN模块的基类也是模块插件机制的关键,提供了很多默认的实现,该类又实现了一个接口IActionable,这个接口指明该控件又哪些操作行为,本类指明了可以对Department进行添加操作
Actions.Add(this.GetNextActionID(), Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), ModuleActionType.AddContent, "", "", this.EditUrl(), false, SecurityAccessLevel.Edit, true, false);
namespace ISS.DNN.Modules.Department
{
using System;
using System.Data;
using System.Collections;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Reflection;
using DotNetNuke;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Entities.Modules;
using DotNetNuke.Entities.Modules.Actions;
using DotNetNuke.Security;
using DotNetNuke.Services.Exceptions;
using DotNetNuke.Services.Localization;
![]()
/**//**//**//// <summary>
/// ViewDepartment 的摘要说明。
/// </summary>
public class ViewDepartment : PortalModuleBase, IActionable
![]()
{
protected System.Web.UI.WebControls.DataList lstDepartment;
![]()
Web 窗体设计器生成的代码Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
override protected void OnInit(EventArgs e)
![]()
{
//
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
//
InitializeComponent();
base.OnInit(e);
}
![]()
/**//**//**//// <summary>
/// 设计器支持所需的方法 - 不要使用代码编辑器
/// 修改此方法的内容。
/// </summary>
private void InitializeComponent()
![]()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
Public MethodsPublic Methods#region Public Methods
public bool DisplayAudit()
![]()
{
bool retValue = false;
if ((string)Settings["auditinfo"] == "Y")
![]()
{
retValue = true;
}
return retValue;
}
#endregion
Event HandlersEvent Handlers#region Event Handlers
/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// Page_Load runs when the control is loaded
/// </summary>
/// <remarks>
/// </remarks>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
protected void Page_Load(System.Object sender, System.EventArgs e)
![]()
{
try
![]()
{
DepartmentController objDepartments = new DepartmentController();
IList colDepartments;
//get the content from the Department table
colDepartments = objDepartments.GetDepartments(ModuleId);
if (colDepartments.Count == 0)
![]()
{
//add the content to the Department table
DepartmentInfo objDepartment = new DepartmentInfo();
objDepartment.ModuleId = ModuleId;
objDepartment.DepartmentName = Localization.GetString("DefaultContent", LocalResourceFile);
objDepartment.CreatedByUser = this.UserId;
objDepartments.AddDepartment(objDepartment);
//get the content from the Department table
colDepartments = objDepartments.GetDepartments(ModuleId);
}
//bind the content to the repeater
lstDepartment.DataSource = colDepartments;
lstDepartment.DataBind();
}
catch (Exception exc) //Module failed to load
![]()
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}
#endregion
Optional InterfacesOptional Interfaces#region Optional Interfaces
/**//**//**//// -----------------------------------------------------------------------------
/// <summary>
/// Registers the module actions required for interfacing with the portal framework
/// </summary>
/// <value></value>
/// <returns></returns>
/// <remarks></remarks>
/// <history>
/// </history>
/// -----------------------------------------------------------------------------
public ModuleActionCollection ModuleActions
![]()
{
get
![]()
{
ModuleActionCollection Actions = new ModuleActionCollection();
Actions.Add(this.GetNextActionID(), Localization.GetString(ModuleActionType.AddContent, this.LocalResourceFile), ModuleActionType.AddContent, "", "", this.EditUrl(), false, SecurityAccessLevel.Edit, true, false);
return Actions;
}
}
#endregion
}
}
2.7 创建UI 部门编辑控件EditDepartment(实现CUD),该类也要继承PortalModuleBase
1
namespace ISS.DNN.Modules.Department2


{3
using System;4
using System.Data;5
using System.Drawing;6
using System.Web;7
using System.Web.UI.WebControls;8
using System.Web.UI.HtmlControls;9
using DotNetNuke;10
using DotNetNuke.Common;11
using DotNetNuke.Common.Utilities;12
using DotNetNuke.Entities.Modules;13
using DotNetNuke.Services.Exceptions;14
using DotNetNuke.Services.Localization;15

16

/**//**//**//// <summary>17
/// EditDepartment 的摘要说明。18
/// </summary>19
public class EditDepartment : PortalModuleBase20

{21
protected System.Web.UI.WebControls.RequiredFieldValidator valDepartmentName;22
protected System.Web.UI.WebControls.LinkButton cmdUpdate;23
protected System.Web.UI.WebControls.LinkButton cmdCancel;24
protected System.Web.UI.WebControls.LinkButton cmdDelete;25
protected DotNetNuke.UI.UserControls.ModuleAuditControl ctlAudit;26
protected DotNetNuke.UI.UserControls.TextEditor txtDepartmentName;27

28

Web 窗体设计器生成的代码Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码29
override protected void OnInit(EventArgs e)30

{31
//32
// CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。33
//34
InitializeComponent();35
base.OnInit(e);36
}37
38

/**//**//**//// <summary>39
/// 设计器支持所需的方法 - 不要使用代码编辑器40
/// 修改此方法的内容。41
/// </summary>42
private void InitializeComponent()43

{44
this.cmdUpdate.Click += new System.EventHandler(this.cmdUpdate_Click);45
this.cmdCancel.Click += new System.EventHandler(this.cmdCancel_Click);46
this.cmdDelete.Click += new System.EventHandler(this.cmdDelete_Click);47
this.Load += new System.EventHandler(this.Page_Load);48

49
}50
#endregion51

52

Private MembersPrivate Members#region Private Members53

54
private int DepartmentID = Null.NullInteger;55

56
#endregion57

58

Event HandlersEvent Handlers#region Event Handlers59

60

/**//**//**//// -----------------------------------------------------------------------------61
/// <summary>62
/// Page_Load runs when the control is loaded63
/// </summary>64
/// <remarks>65
/// </remarks>66
/// <history>67
/// </history>68
/// -----------------------------------------------------------------------------69
protected void Page_Load(System.Object sender, System.EventArgs e)70

{71
try72

{73
//Determine DepartmentId of Department to Update74
if(this.Request.QueryString["DepartmentId"] !=null)75

{76
DepartmentID = Int32.Parse(this.Request.QueryString["DepartmentId"]);77
}78

79
//If this is the first visit to the page, bind the role data to the datalist80
if (Page.IsPostBack == false)81

{82
cmdDelete.Attributes.Add("onClick", "javascript:return confirm('" + Localization.GetString("DeleteItem") + "');");83

84
if(DepartmentID != -1)85

{86
//get DepartmentName87
DepartmentController objDepartments = new DepartmentController();88
DepartmentInfo objDepartment = objDepartments.GetDepartment(ModuleId,DepartmentID);89
if (objDepartment != null)90

{91
txtDepartmentName.Text = objDepartment.DepartmentName;92
ctlAudit.CreatedByUser = objDepartment.CreatedByUserName;93
ctlAudit.CreatedDate = objDepartment.CreatedDate.ToString();94
}95
else96

{97
Response.Redirect(Globals.NavigateURL(), true);98
}99
}100
else101

{102
cmdDelete.Visible = false;103
ctlAudit.Visible = false;104
}105
}106
}107
catch (Exception exc) //Module failed to load108

{109
Exceptions.ProcessModuleLoadException(this, exc);110
}111
}112

113

/**//**//**//// -----------------------------------------------------------------------------114
/// <summary>115
/// cmdCancel_Click runs when the cancel button is clicked116
/// </summary>117
/// <remarks>118
/// </remarks>119
/// <history>120
/// </history>121
/// -----------------------------------------------------------------------------122
protected void cmdCancel_Click(System.Object sender, System.EventArgs e)123

{124
try125

{126
this.Response.Redirect(Globals.NavigateURL(this.TabId), true);127
}128
catch (Exception exc) //Module failed to load129

{130
Exceptions.ProcessModuleLoadException(this, exc);131
}132
}133

134

/**//**//**//// -----------------------------------------------------------------------------135
/// <summary>136
/// cmdDelete_Click runs when the delete button is clicked137
/// </summary>138
/// <remarks>139
/// </remarks>140
/// <history>141
/// </history>142
/// -----------------------------------------------------------------------------143
protected void cmdDelete_Click(System.Object sender, System.EventArgs e)144

{145
try146

{147
//Only attempt to delete the item if it exists already148
if (!Null.IsNull(DepartmentID))149

{150
DepartmentController objDepartments = new DepartmentController();151
objDepartments.DeleteDepartment(ModuleId,DepartmentID);152
}153

154
this.Response.Redirect(Globals.NavigateURL(this.TabId), true);155
}156
catch (Exception exc) //Module failed to load157

{158
Exceptions.ProcessModuleLoadException(this, exc);159
}160
}161

162

/**//**//**//// -----------------------------------------------------------------------------163
/// <summary>164
/// cmdUpdate_Click runs when the update button is clicked165
/// </summary>166
/// <remarks>167
/// </remarks>168
/// <history>169
/// </history>170
/// -----------------------------------------------------------------------------171
protected void cmdUpdate_Click(System.Object sender, System.EventArgs e)172

{173
try174

{175
DepartmentController objDepartments = new DepartmentController();176
DepartmentInfo objDepartment = new DepartmentInfo();177

178
objDepartment.ModuleId = ModuleId;179
objDepartment.DepartmentId = DepartmentID;180
objDepartment.DepartmentName = txtDepartmentName.Text;181
objDepartment.CreatedByUser = this.UserId;182

183
//Update the DepartmentName within the Department table184
if(Null.IsNull(DepartmentID))185

{186
objDepartments.AddDepartment(objDepartment);187
}188
else189

{190
objDepartments.UpdateDepartment(objDepartment);191
}192

193
//Redirect back to the portal home page194
this.Response.Redirect(Globals.NavigateURL(this.TabId), true);195
}196
catch (Exception exc) //Module failed to load197

{198
Exceptions.ProcessModuleLoadException(this, exc);199
}200
}201

202
#endregion203

204
}205
}206

2.8 创建模块设置控件Settings,该类一定要继承ModuleSettingsBase
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using DotNetNuke;
using DotNetNuke.Common;
using DotNetNuke.Common.Utilities;
using DotNetNuke.Services.Localization;
using DotNetNuke.Services.Exceptions;
namespace ISS.DNN.Modules.Department

{
public abstract class Settings : DotNetNuke.Entities.Modules.ModuleSettingsBase
{
Web Form Designer generated codeWeb Form Designer generated code#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}

/**//**//**//// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
}
#endregion
public override void LoadSettings()
{
try 
{
if (!Page.IsPostBack) 
{
string setting1 = ((string)TabModuleSettings["settingname1"]);
string setting2 = ((string)Settings["settingname2"]);
}
}
catch (Exception exc) 
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}
public override void UpdateSettings()
{
try 
{
DotNetNuke.Entities.Modules.ModuleController objModules = new DotNetNuke.Entities.Modules.ModuleController();
objModules.UpdateTabModuleSetting(TabModuleId, "settingname1", "value");
objModules.UpdateModuleSetting(ModuleId, "settingname2", "value");
Response.Redirect(Globals.NavigateURL(), true);
}
catch (Exception exc) 
{
Exceptions.ProcessModuleLoadException(this, exc);
}
}
}
}
OK,现在已经完成了系统的关键开发了,编译项目生成ISS.DNN.Modules.Department.dll,下一篇介绍SqlDataProvider的开发,UI界面的开发,以及安装包的制作!