在SQL Server和NET中构建内容管理系统
上下文
这篇文章最初是在2012年撰写的。技术在这个时代已经取得了相当大的进展,但是如果有人发现它有用的话,我们会把它留在这里。
欢迎阅读有关创建CMS的文章。本文至少需要一些SQL和HTML的基本知识,以及安装的SQL Server和Visual Studio 2008的副本。
你的网站已经到了你想开始动态添加内容的阶段,有很多选项可以免费和付费( 维基百科上的列表 ),但是如何取出中间人并构建自己的?
让我们直接进入编码,第一步是添加内置的ASP用户存储,如果您从未这样做过,请阅读本文介绍成员资格 。
第二步是将我们的SQL表和存储过程添加到数据库中。 DocumentID字段被设置为主键以获得更好的性能。如果你是SQL新手,那么请研究下面的想法;
- 主键
- 外键
- SQL数据类型
SQL
CREATE TABLE DocumentMenu(
DocumentMenuID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_DocumentMenuID PRIMARY KEY,
DocumentMenuName nvarchar(100) NULL,
DocumentMenuMulti bit NULL
)
INSERT INTO DocumentMenu(DocumentMenuName,DocumentMenuMulti) SELECT 'Home',0
INSERT INTO DocumentMenu(DocumentMenuName,DocumentMenuMulti) SELECT 'About',0
INSERT INTO DocumentMenu(DocumentMenuName,DocumentMenuMulti) SELECT 'SQL',0
INSERT INTO DocumentMenu(DocumentMenuName,DocumentMenuMulti) SELECT 'NET',0
GO
CREATE TABLE Document(
DocumentID int IDENTITY(1,1) NOT NULL CONSTRAINT PK_DocumentID PRIMARY KEY,
DocumentMenuLinkID int NULL CONSTRAINT FK_DocumentMenuLinkID FOREIGN KEY REFERENCES DocumentMenu(DocumentMenuID),
DocumentName varchar(100) NULL,
DocumentHeader varchar(100) NULL,
DocumentText varchar(max) NULL,
DocumentLastUpdated datetime NULL,
DocumentKeyWords varchar(250) NULL,
DocumentDescription varchar(250) NULL,
DocumentSubjects varchar(250) NULL
)
GO
INSERT INTO Document(DocumentMenuLinkID,DocumentName) SELECT 1,'Home'
INSERT INTO Document(DocumentMenuLinkID,DocumentName) SELECT 2,'About'
GO
--Update Documents
CREATE PROC UpdDocument(@DocumentID INT,@DocumentMenuLinkID INT,@DocumentName VARCHAR(100),@DocumentHeader VARCHAR(100),@DocumentText VARCHAR(MAX),@DocumentKeyWords VARCHAR(250),@DocumentDescription VARCHAR(250))
AS BEGIN
IF @DocumentID = 0 BEGIN
PRINT 'Insert'
INSERT INTO Document(DocumentMenuLinkID,DocumentName,DocumentHeader,DocumentText,DocumentLastUpdated,DocumentKeyWords,DocumentDescription)
SELECT @DocumentMenuLinkID,@DocumentName,@DocumentHeader,@DocumentText,GETDATE(),@DocumentKeyWords,@DocumentDescription
SELECT SCOPE_IDENTITY()
RETURN
END
IF @DocumentID <>0 BEGIN
PRINT 'Update'
UPDATE Document SET
DocumentMenuLinkID=@DocumentMenuLinkID,DocumentName=@DocumentName,DocumentHeader=@DocumentHeader,DocumentText=@DocumentText,
DocumentLastUpdated=GETDATE(),DocumentKeyWords=@DocumentKeyWords,DocumentDescription=@DocumentDescription
WHERE DocumentID=@DocumentID
END
END
GO
--Get Documents
CREATE PROC GetDocuments(@SubjString NVARCHAR(100)) AS BEGIN
DECLARE @DocumentMenuLinkID INT=(SELECT TOP 1 DocumentMenuID FROM DocumentMenu WHERE DocumentMenuName LIKE @SubjString)
SELECT 'Article: ' + DocumentName DocumentName,
REPLACE('Blog/'+DocumentSubjects+'/'+CAST(DocumentID AS VARCHAR(10)),' ','')+'/'+REPLACE(DocumentHeader,' ',' ') URL,
'Description: ' + DocumentDescription DocumentDescription,
'Keywords: ' + DocumentKeyWords DocumentKeyWords,
CONVERT(VARCHAR(10),DocumentLastUpdated,103) DocumentLastUpdated
FROM Document
INNER JOIN DocumentMenu ON DocumentMenuID=DocumentMenuLinkID
WHERE DocumentMenuLinkID=@DocumentMenuLinkID
ORDER BY DocumentLastUpdated DESC
END
GO
--Get Document
CREATE PROC GetDocument(@DocumentID INT) AS BEGIN
SELECT TOP 1 Document.*,DocumentMenuMulti
FROM Document
INNER JOIN DocumentMenu ON DocumentMenuID=DocumentMenuLinkID
WHERE DocumentID=@DocumentID
END
GO
应用程序设置
这就是SQL代码,下一个阶段是设置一个网页来处理显示我们的文档,要编辑的文档列表和编辑文档页面。
打开一个新项目或者你要添加的项目。我们需要将Global.asax(全局应用程序类)添加到此项目,添加路由处理并将路由注册到该表。以下应用程序可供所有人访问以下页面;
- 主页
- 关于页面
- 登录页面(在单独的文章中介绍)
- 博客目录(所有文档)
- 博客子目录(例如SQL,.NET)
- 博客文章
Web Routing Config
<add name="MySqlConnection"connectionString="Data Source={servername};Initial Catalog={databasename};Integrated Security=True"providerName="System.Data.SqlClient" />
<connectionStrings>
<system.web>
<httpsRuntime requestValidationMode="2.0"/>
<system.web>
<system.webServer>
<modules runAllManagedModulesForAllRequests="True"/>
<system.webServer>
进口
您将需要导入System.Web.Routing。
我已经评论了每一行,告诉你每个人在做什么。我们还需要在我们的Web配置文件中创建一个SQL连接。
我正在使用TinyMCE,这是一个Java脚本编辑器,因此我们还需要更改请求验证模式,页面路由需要更新模块。
VB
'Fires when the application is started
RegisterRoutes(RouteTable.Routes)
End Sub
Sub RegisterRoutes(ByVal routes As RouteCollection) 'This code you will need to add
routes.MapPageRoute("", "Home/", "~/Home.aspx", False, New RouteValueDictionary(New With {.ArticleID = "1"})) 'Manual Route ID 1 is home page
routes.MapPageRoute("", "About/", "~/About.aspx", False, New RouteValueDictionary(New With {.ArticleID = "2"})) 'Manual Route
routes.MapPageRoute("", "Blog/{ArticleSection}/{ArticleID}/{*pathInfo}", "~/ContentPage.aspx") 'Article route to ignore anything further than the Article ID
routes.MapPageRoute("", "Blog/{ArticleSection}/{ArticleID}/", "~/ContentPage.aspx") 'Article route using the Article ID
routes.MapPageRoute("", "Blog/{ArticleSection}/", "~/ContentSubj.aspx") 'Article route using the Section ID
routes.MapPageRoute("", "Blog/{*pathInfo}", "~/ContentSubj.aspx") 'Route to take us into the index
routes.MapPageRoute("", "DocumentManager/{DID}/", "~/ManageDocument.aspx") 'Route to take us to edit document
routes.MapPageRoute("", "DocumentManager/", "~/ManageDocuments.aspx") 'Route to take us to the list of documents
End Sub
C#
{
//Fires when the application is started
RegisterRoutes(RouteTable.Routes);
}
public void RegisterRoutes(RouteCollection routes) //This code you will need to add
{
routes.MapPageRoute("", "Home/", "~/Home.aspx", false, new RouteValueDictionary(new { ArticleID = "1" }));
//Manual Route ID 1 is home page
routes.MapPageRoute("", "About/", "~/About.aspx", false, new RouteValueDictionary(new { ArticleID = "2" }));
//Manual Route
routes.MapPageRoute("", "Blog/{ArticleSection}/{ArticleID}/{*pathInfo}", "~/ContentPage.aspx");
//Article route to ignore anything further than the Article ID
routes.MapPageRoute("", "Blog/{ArticleSection}/{ArticleID}/", "~/ContentPage.aspx");
//Article route using the Article ID
routes.MapPageRoute("", "Blog/{ArticleSection}/", "~/ContentSubj.aspx");
//Article route using the Section ID
routes.MapPageRoute("", "Blog/{*pathInfo}", "~/ContentSubj.aspx");
//Route to take us into the index
routes.MapPageRoute("", "DocumentManager/{DID}/", "~/ManageDocument.aspx");
//Route to take us to edit document
routes.MapPageRoute("", "DocumentManager/", "~/ManageDocuments.aspx");
//Route to take us to the list of documents
}
管理文档库
在这里,我们将列出所有文档以及查看或编辑它们的链接...
为此添加一个名为ManageDocuments.aspx的新Web表单
HTML
<asp:GridView ID="MyDocs" runat="server" AutoGenerateColumns="False" Width="100%" BorderStyle="None" GridLines="None">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="EditURL"DataTextField="DocName"
HeaderText="EditDocument" />
<asp:BoundField DataField="DocumentHeader"HeaderText="DocumentHeader" />
</Columns>
</asp:GridView>
</div>
<div>
<a href="DocumentManager/0/">Add New</a>
</div>
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
If User.IsInRole("SiteAdmin") Then
'If Not IsPostBack Then
Dim com As New SqlCommand("SELECT 'DocumentManager/'+CAST(DocumentID AS VARCHAR(10)) EditURL,DocumentName DocName,DocumentHeader,REPLACE('Blog/'+DocumentSubjects+'/'+CAST(DocumentID AS VARCHAR(10)),' ','')+'/'+DocumentName PreviewURL FROM Document", con)
con.Open()
Dim dr = com.ExecuteReader
MyDocs.DataSource = dr
MyDocs.DataBind()
con.Close()
'End If
End If
End Sub
C#
protected void Page_Load(object sender, System.EventArgs e)
{
if (User.IsInRole("SiteAdmin"))
{
//If Not IsPostBack Then
SqlCommand com = new SqlCommand("SELECT 'DocumentManager/'+CAST(DocumentID AS VARCHAR(10)) EditURL,DocumentName DocName,DocumentHeader,REPLACE('Blog/'+DocumentSubjects+'/'+CAST(DocumentID AS VARCHAR(10)),' ','')+'/'+DocumentName PreviewURL FROM Document", con);
con.Open();
dynamic dr = com.ExecuteReader;
MyDocs.DataSource = dr;
MyDocs.DataBind();
con.Close();
//wwwd If
}
}
文本编辑器
在这里我使用了Tiny MCE文本编辑器。我发现这个作品非常适合我想要的作品,但是还有一些步骤涉及到使用它。
首先添加一个名为ManageDocument.aspx的新Web表单。您可能需要手动添加脚本管理器。
HTML
<ContentTemplate>
<div style="text-align: center;">
<div>Menu</div>
<div>
<asp:DropDownList ID="PageMenu" runat="server">
</asp:DropDownList>
</div>
<div>Page Name</div>
<div><asp:TextBox ID="PageName" runat="server" Width="400px"></asp:TextBox></div>
<div>Header</div>
<div><asp:TextBox ID="HeaderText" runat="server" Width="99%"></asp:TextBox></div>
<div>Content</div>
<div><textarea name="content" cols="1" rows="45" style="width: 100%; margin: 0 0 0 0;" id="ContentText" runat="server"></textarea></div>
<div>Key Words</div>
<div><asp:TextBox ID="KeyWords" runat="server" Width="99%"></asp:TextBox></div>
<div>Description</div>
<div><asp:TextBox ID="Description" runat="server" Width="99%"></asp:TextBox></div>
<div><asp:Button ID="AddUpdate" runat="server" Text="Button"/></div>
</div>
</ContentTemplate>
<triggers>
<asp:PostBackTrigger ControlID="AddUpdate"/>
</triggers>
</asp:UpdatePanel>
JavaScript
</script>
<script type="text/javascript">
tinyMCE.init({
mode: "textareas",
theme: "advanced",
plugins: "emotions,spellchecker,advhr,insertdatetime,preview",
theme_advanced_buttons1: "newdocument,|,bold,italic,underline,|,justifyleft,justifycenter,justifyright,fontselect,fontsizeselect,formatselect",
theme_advanced_buttons2: "cut,copy,paste,|,bullist,numlist,|,outdent,indent,|,undo,redo,|,link,unlink,image,|,code,preview,|,forecolor,backcolor",
theme_advanced_buttons3: "insertdate,inserttime,|,spellchecker,advhr,,removeformat,|,sub,sup,|,charmap,emotions",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
width: '100%'
});
function UpdateTextArea() {
tinyMCE.triggerSave(false, true);
}
</script>
VB
'Above your class
Dim con As New SqlConnection(ConfigurationManager.ConnectionStrings("MySqlConnection").ConnectionString)
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
If User.IsInRole("SiteAdmin") Then
If Not IsPostBack Then
If Not IsNothing(Page.RouteData.Values("DID")) Then
AddUpdate.Attributes.Add("onclick", "UpdateTextArea()")
Dim docID As String = Page.RouteData.Values("DID").ToString
If docID = 0 Then
AddUpdate.Text = "Add Document"
Else
AddUpdate.Text = "Update Document"
End If
Dim com As New SqlCommand("SELECT * FROM DocumentMenu WHERE (CASE WHEN " & docID & "=0 THEN 1 ELSE DocumentMenuMulti END)=DocumentMenuMulti; " & _
"EXEC GetDocumentByID " & docID & "", con)
con.Open()
Dim da = New SqlDataAdapter(com)
Dim ds As New DataSet
da.Fill(ds)
'Menu
PageMenu.DataTextField = "DocumentMenuName"
PageMenu.DataValueField = "DocumentMenuID"
PageMenu.DataSource = ds.Tables(0)
PageMenu.DataBind()
'Data
Dim dr = ds.Tables(1).CreateDataReader
While dr.Read()
PageMenu.SelectedValue = dr.Item(1).ToString
PageName.Text = dr.Item(2).ToString
HeaderText.Text = dr.Item(3).ToString
ContentText.InnerHtml = httpsUtility.HtmlDecode(dr.Item(4).ToString)
KeyWords.Text = dr.Item(6).ToString
Description.Text = dr.Item(7).ToString
PageMenu.Enabled = CBool(dr.Item(9).ToString)
End While
con.Close()
Else
Response.Redirect("/DocumentManager")
End If
Else
End If
Else
Response.Redirect("/Login")
End If
End Sub
Private Sub AddUpdate_Click() Handles AddUpdate.Click
If Not IsNothing(Page.RouteData.Values("DID")) Then
Dim docID As String = Page.RouteData.Values("DID").ToString
Dim DocumentMenuLinkID As Integer = PageMenu.SelectedValue
Dim DocumentName As String = Replace(PageName.Text, "'", "''")
Dim DocumentHeader As String = Replace(HeaderText.Text, "'", "''")
Dim DocumentText As String = Replace(ContentText.InnerHtml, "'", "''")
Dim DocumentKeyWords As String = Replace(KeyWords.Text, "'", "''")
Dim DocumentDescription As String = Replace(Description.Text, "'", "''")
Dim com As New SqlCommand("EXEC UpdDocument " & docID & ",'" & DocumentMenuLinkID & "','" & DocumentName & "','" & DocumentHeader & "',N'" & DocumentText & "','" & DocumentKeyWords & "','" & DocumentDescription & "'", con)
con.Open()
Dim a As String = com.ExecuteScalar
con.Close()
If docID = 0 Then
Response.Redirect("~/DocumentManager/" + a)
End If
End If
End Sub
C#
SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings("MySqlConnection").ConnectionString);
protected void Page_Load(object sender, System.EventArgs e)
{
if (User.IsInRole("SiteAdmin"))
{
if (!IsPostBack)
{
if ((Page.RouteData.Values("DID") != null))
{
AddUpdate.Attributes.Add("onclick", "UpdateTextArea()");
string docID = Page.RouteData.Values("DID").ToString;
if (docID == 0)
{
AddUpdate.Text = "Add Document";
}
else
{
AddUpdate.Text = "Update Document";
}
SqlCommand com = new SqlCommand("SELECT * FROM DocumentMenu WHERE (CASE WHEN " + docID + "=0 THEN 1 ELSE DocumentMenuMulti END)=DocumentMenuMulti; " + "EXEC GetDocumentByID " + docID + "", con);
con.Open();
dynamic da = new SqlDataAdapter(com);
DataSet ds = new DataSet();
da.Fill(ds);
//Menu
PageMenu.DataTextField = "DocumentMenuName";
PageMenu.DataValueField = "DocumentMenuID";
PageMenu.DataSource = ds.Tables(0);
PageMenu.DataBind();
//Data
dynamic dr = ds.Tables(1).CreateDataReader;
while (dr.Read())
{
PageMenu.SelectedValue = dr.Item(1).ToString;
PageName.Text = dr.Item(2).ToString;
HeaderText.Text = dr.Item(3).ToString;
ContentText.InnerHtml = httpsUtility.HtmlDecode(dr.Item(4).ToString);
KeyWords.Text = dr.Item(6).ToString;
Description.Text = dr.Item(7).ToString;
PageMenu.Enabled = Convert.ToBoolean(dr.Item(9).ToString);
}
con.Close();
}
else
{
Response.Redirect("/DocumentManager");
}
}
else
{
}
}
else
{
Response.Redirect("/Login");
}
}
private void AddUpdate_Click()
{
if ((Page.RouteData.Values("DID") != null))
{
string docID = Page.RouteData.Values("DID").ToString;
int DocumentMenuLinkID = PageMenu.SelectedValue;
string DocumentName = Strings.Replace(PageName.Text, "'", "''");
string DocumentHeader = Strings.Replace(HeaderText.Text, "'", "''");
string DocumentText = Strings.Replace(ContentText.InnerHtml, "'", "''");
string DocumentKeyWords = Strings.Replace(KeyWords.Text, "'", "''");
string DocumentDescription = Strings.Replace(Description.Text, "'", "''");
SqlCommand com = new SqlCommand("EXEC UpdDocument " + docID + ",'" + DocumentMenuLinkID + "','" + DocumentName + "','" + DocumentHeader + "','" + DocumentText + "','" + DocumentKeyWords + "','" + DocumentDescription + "'", con);
con.Open();
string a = com.ExecuteScalar;
con.Close();
if (docID == 0)
{
Response.Redirect("~/DocumentManager/" + a);
}
}
}
目录页面
此页面将使用我们路由的内容主题显示您的所有文章。
它的设计方式,我们可以使用两个部分的相同页面,有效地只在需要时提供过滤器...
添加一个新的Web表单ContentSubj.aspx
HTML
<div id="ContentText" runat="server"></div>
<div>
<asp:GridView id="ContentSub" runat="server" AutoGenerateColumns="False" GridLines="None"ShowHeader="False"Width="100%">
<Columns>
<asp:TemplateField>
<ItemTemplate>
<div style="width: 80%; float: left;">
<asp:HyperLink ID="HyperLink1" runat="server" NavigateUrl='<%# Eval("HyperLink") %>' Text='<%# Eval("DocumentName") %>'></asp:HyperLink>
</div>
<div style="width: 19%; float: left;">
<asp:Label ID="Label2" runat="server" text='<%# Eval("DocumentLastUpdated") %>'></asp:Label>
</div>
<div style="width: 100%; float: left; clear: both;">
<asp:Label ID="Label1" runat="server" text='<%# Eval("DocumentDescription") %>'></asp:Label>
</div>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</div>
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
Page.Title = "gsclayton.net Technical Articles"
Page.MetaKeywords = "gsclayton.net, Databases, Web Design, SQL, HTML, .NET, ASP, CSS, Technical Articles"
Page.MetaDescription = "gsclayton.net Databases and Web Design, SQL, HTML, .NET, ASP, CSS, Technical Articles"
Dim Str As String = Replace(Page.RouteData.Values("Subj").ToString, "'", "''")
Subject.Text = "La " + Str + " Articles"
Dim com As New SqlCommand("EXEC GetDocuments '%" & Str & "%'", con)
con.Open()
Dim dr = com.ExecuteReader
MyDocs.DataSource = dr
MyDocs.DataBind()
dr.Close()
con.Close()
Catch ex As Exception
Response.Redirect("/Blog")
End Try
End Sub
C#
protected void Page_Load(object sender, System.EventArgs e)
{
try
{
Page.Title = "gsclayton.net Technical Articles";
Page.MetaKeywords = "gsclayton.net, Databases, Web Design, SQL, HTML, .NET, ASP, CSS, Technical Articles";
Page.MetaDescription = "gsclayton.net Databases and Web Design, SQL, HTML, .NET, ASP, CSS, Technical Articles";
string Str = Strings.Replace(Page.RouteData.Values("Subj").ToString, "'", "''");
Subject.Text = "La " + Str + " Articles";
SqlCommand com = new SqlCommand("EXEC GetDocuments '%" + Str + "%'", con);
con.Open();
dynamic dr = com.ExecuteReader;
MyDocs.DataSource = dr;
MyDocs.DataBind();
dr.Close();
con.Close();
}
catch (Exception ex)
{
Response.Redirect("/Blog");
}
}
内容页面
如果您不需要在您的家中和关于页面的自定义内容,那么只需添加内容页面并编辑页面路由...
在这些页面中,您可以添加和设置样式,但只要您有以下代码,它就可以工作。
HTML
<div id="MyContent" runat="server"></div>
<div id="LastUpd" runat="server" style="clear: both;"></div>
VB
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender
'If Not IsPostBack Then
If Not IsNothing(Page.RouteData.Values("ArticleID")) Then
Dim LastUpdated As Label = Master.FindControl("LastUpdatedLabel") 'Control on my Master Page, this can be added to your page insteadv as a labeldocID
Dim did As String = Page.RouteData.Values("ArticleID").ToString
Dim com As New SqlCommand("EXEC GetDocument '" & Replace(did, "'", "''") & "'", con)
con.Open()
Dim dr = com.ExecuteReader
While dr.Read()
HeaderLabel.Text = dr.Item(3).ToString
ContentText.InnerHtml = httpsUtility.HtmlDecode(dr.Item(4).ToString)
LastUpdated.Text = Format(CDate(dr.Item(5).ToString), "dd/MM/yyyy")
Page.Header.Title = dr.Item(3).ToString
MetaKeywords = dr.Item(6).ToString
MetaDescription = dr.Item(7).ToString
End While
dr.Close()
con.Close()
'End If
End If
End Sub
C#
protected void Page_Load(object sender, System.EventArgs e)
{
//If Not IsPostBack Then
if ((Page.RouteData.Values("ArticleID") != null)) {
Label LastUpdated = Master.FindControl("LastUpdatedLabel");
//Control on my Master Page, this can be added to your page insteadv as a labeldocID
string did = Page.RouteData.Values("ArticleID").ToString;
SqlCommand com = new SqlCommand("EXEC GetDocument '" + Strings.Replace(did, "'", "''") + "'", con);
con.Open();
dynamic dr = com.ExecuteReader;
while (dr.Read()) {
HeaderLabel.Text = dr.Item(3).ToString;
ContentText.InnerHtml = httpsUtility.HtmlDecode(dr.Item(4).ToString);
LastUpdated.Text = Strings.Format(Convert.ToDateTime(dr.Item(5).ToString), "dd/MM/yyyy");
Page.Header.Title = dr.Item(3).ToString;
MetaKeywords = dr.Item(6).ToString;
MetaDescription = dr.Item(7).ToString;
}
dr.Close();
con.Close();
}
}
包起来
这是一个旧文件,但仍包含相关的想法,所以将它用作任何你喜欢做的事情的基础!