我今天刚开发了一个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
1namespace ISS.DNN.Modules.Department
2{
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 : PortalModuleBase
20 {
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 #endregion
51
52 Private MembersPrivate Members#region Private Members
53
54 private int DepartmentID = Null.NullInteger;
55
56 #endregion
57
58 Event HandlersEvent Handlers#region Event Handlers
59
60 /**//**//**//// -----------------------------------------------------------------------------
61 /// <summary>
62 /// Page_Load runs when the control is loaded
63 /// </summary>
64 /// <remarks>
65 /// </remarks>
66 /// <history>
67 /// </history>
68 /// -----------------------------------------------------------------------------
69 protected void Page_Load(System.Object sender, System.EventArgs e)
70 {
71 try
72 {
73 //Determine DepartmentId of Department to Update
74 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 datalist
80 if (Page.IsPostBack == false)
81 {
82 cmdDelete.Attributes.Add("onClick", "javascript:return confirm('" + Localization.GetString("DeleteItem") + "');");
83
84 if(DepartmentID != -1)
85 {
86 //get DepartmentName
87 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 else
96 {
97 Response.Redirect(Globals.NavigateURL(), true);
98 }
99 }
100 else
101 {
102 cmdDelete.Visible = false;
103 ctlAudit.Visible = false;
104 }
105 }
106 }
107 catch (Exception exc) //Module failed to load
108 {
109 Exceptions.ProcessModuleLoadException(this, exc);
110 }
111 }
112
113 /**//**//**//// -----------------------------------------------------------------------------
114 /// <summary>
115 /// cmdCancel_Click runs when the cancel button is clicked
116 /// </summary>
117 /// <remarks>
118 /// </remarks>
119 /// <history>
120 /// </history>
121 /// -----------------------------------------------------------------------------
122 protected void cmdCancel_Click(System.Object sender, System.EventArgs e)
123 {
124 try
125 {
126 this.Response.Redirect(Globals.NavigateURL(this.TabId), true);
127 }
128 catch (Exception exc) //Module failed to load
129 {
130 Exceptions.ProcessModuleLoadException(this, exc);
131 }
132 }
133
134 /**//**//**//// -----------------------------------------------------------------------------
135 /// <summary>
136 /// cmdDelete_Click runs when the delete button is clicked
137 /// </summary>
138 /// <remarks>
139 /// </remarks>
140 /// <history>
141 /// </history>
142 /// -----------------------------------------------------------------------------
143 protected void cmdDelete_Click(System.Object sender, System.EventArgs e)
144 {
145 try
146 {
147 //Only attempt to delete the item if it exists already
148 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 load
157 {
158 Exceptions.ProcessModuleLoadException(this, exc);
159 }
160 }
161
162 /**//**//**//// -----------------------------------------------------------------------------
163 /// <summary>
164 /// cmdUpdate_Click runs when the update button is clicked
165 /// </summary>
166 /// <remarks>
167 /// </remarks>
168 /// <history>
169 /// </history>
170 /// -----------------------------------------------------------------------------
171 protected void cmdUpdate_Click(System.Object sender, System.EventArgs e)
172 {
173 try
174 {
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 table
184 if(Null.IsNull(DepartmentID))
185 {
186 objDepartments.AddDepartment(objDepartment);
187 }
188 else
189 {
190 objDepartments.UpdateDepartment(objDepartment);
191 }
192
193 //Redirect back to the portal home page
194 this.Response.Redirect(Globals.NavigateURL(this.TabId), true);
195 }
196 catch (Exception exc) //Module failed to load
197 {
198 Exceptions.ProcessModuleLoadException(this, exc);
199 }
200 }
201
202 #endregion
203
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界面的开发,以及安装包的制作!