ASP.NET MVC開發(fā):帶后臺的CMS開發(fā)

本來這一篇寫的是一個音樂商城的程序的創(chuàng)建攻柠,但我啰啰嗦嗦寫了三大篇球订,結(jié)果很多業(yè)務(wù)都沒交代清楚,干脆就刪了瑰钮,重寫一篇冒滩。這一篇重點(diǎn)的地方都有提及,包括會員管理員浪谴、文章發(fā)布开睡、權(quán)限管理,實(shí)在是入門最佳教材苟耻,遙想入門當(dāng)年篇恒,怎么遇不到這種文章呢?呵呵凶杖。由于MVC開發(fā)性能卓越胁艰,基本上可以在一天之內(nèi)完成這個開發(fā)任務(wù)。學(xué)了這個智蝠,開發(fā)個小型商業(yè)網(wǎng)站大概也就兩三天的功夫腾么。

基本的思路先畫一個思維導(dǎo)圖厘清一下思路:

本例子使用了IDentity進(jìn)行用戶驗(yàn)證,同時也使用了角色杈湾,角色設(shè)為Admin可以管理用戶解虱,也可以管理文章。普通用戶除了發(fā)表評論外就沒有其他功能了漆撞。

控制器方面殴泰,我用了AxCMSAdmin控制器,作為管理文章用浮驳。

數(shù)據(jù)庫設(shè)計如下圖悍汛,這里并不包括IDentity生成的數(shù)據(jù)庫,只包括CMS簡單業(yè)務(wù)至会。

假設(shè)你已經(jīng)有了一個完整的包含整個IDentity業(yè)務(wù)的項目离咐,項目名稱為Blog,那么我們就從新建模型開始奋献,右擊解決方案資源管理器的Models文件夾健霹,在彈出來的菜單上選擇新建類:Contents.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace AxCMS.Models
{
    public class Contents
    {
        public int ContentsId { get; set; }
        public string User { get; set; }
        public string Title { get; set; }
        public int CategoryId { get; set; }
        public DateTime PublicationDate { get; set; }
        public string Content { get; set; }
        public UserCommments UserCommments { get; set; }
        public Category Category { get; set; }
    }
}

接著旺上,再次新建類:Category.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace AxCMS.Models
{
    public class Category
    {
        public int CategoryId { get; set; }
        public string Name { get; set; }
        public List<Contents> Contentss { get; set; }
    }
}

最后再一次新建類:UserCommments.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace AxCMS.Models
{
    public class UserCommments
    {
        public int UserCommmentsId { get; set; }
        public int ContentsId { get; set; }
        public string user { get; set; }
        public string Comments { get; set; }
    }
}

全部保存之后,點(diǎn)擊生成菜單里面的生成解決方案糖埋。

好了宣吱,現(xiàn)在我們來完成一個新的控制器,右擊解決方案資源管理器的Controllers文件夾瞳别,添加新的控制器征候,選擇 "包含視圖的MVC 5控制器(使用 Entity Framework)",設(shè)置如下圖:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;

namespace CMS.Models
{
    public class testseed:DropCreateDatabaseAlways<CMSDB>
    {
        protected override void Seed(CMSDB context)
        {
            context.BlogClases.Add(new BlogClass { ClassName = "經(jīng)營" });
            context.BlogDetaileds.Add(
                new BlogDetailed
                {
                    User = "null",
                    BlogDate = DateTime.Now,
                    BlogContent="這是一次測試祟敛!",
                    BlogClass=new BlogClass { ClassName="管理"}
            });
            base.Seed(context);
        }
    }
}

打開Global.asax.cs疤坝,在protected void Application_Start() 下面輸入代碼:

 protected void Application_Start()
        {
            System.Data.Entity.Database.SetInitializer(new MvcMusicStore.Models.MusicStoreDbInitializer());
            AreaRegistration.RegisterAllAreas();
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }

運(yùn)行程序,我們可以發(fā)現(xiàn)數(shù)據(jù)庫已經(jīng)完成了并且有了一兩筆播種數(shù)據(jù)馆铁。

一般我們一個程序都在一個數(shù)據(jù)庫里面跑揉,在還沒有使用注冊的情況下,IDentity并不會給你一個默認(rèn)的數(shù)據(jù)庫埠巨,打開web.config文件历谍,將<add name="DefaultConnection" 下面的數(shù)據(jù)庫文件名改為<add name="AxCMSDBContext" 里面的文件名。

現(xiàn)在辣垒,我們在啟用IDentity的用戶管理同時望侈,也啟用角色:

第一步:打開IdentityConfig.cs,往里面增加代碼

//配置此應(yīng)用程序中使用的應(yīng)用程序角色管理器勋桶。RoleManager 在 ASP.NET Identity 中定義脱衙,并由此應(yīng)用程序使用。
public class ApplicationRoleManager : RoleManager<IdentityRole>
    {
        public ApplicationRoleManager(IRoleStore<IdentityRole,string> roleStore)
            : base(roleStore)
        {
        }

        public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
        {
            return new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
        }
    }

第二步: 修改Startup.Auth.cs,在 public void ConfigureAuth(IAppBuilder app)中加入代碼:

 app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);   //添加的角色管理器

第三步:創(chuàng)建種子數(shù)據(jù)例驹,新建ApplicationDbInitializer.cs類捐韩,將數(shù)據(jù)加入

using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System.Data.Entity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Web;

namespace AxCMS.Models
{
    public class ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext>
    {
        protected override void Seed(ApplicationDbContext context)
        {
            InitializeIdentityForEF(context);
            base.Seed(context);
        }


        public static void InitializeIdentityForEF(ApplicationDbContext db)
        {
            var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
            var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
            const string name = "Admin@alexzeng.net";//用戶名
            const string password = "Admin123@alexzeng";//密碼
            const string roleName = "Admin";//用戶要添加到的角色組

            //如果沒有Admin用戶組則創(chuàng)建該組
            var role = roleManager.FindByName(roleName);
            if (role == null)
            {
                role = new IdentityRole(roleName);
                var roleresult = roleManager.Create(role);
            }

            //如果沒有Admin@alexzeng.net用戶則創(chuàng)建該用戶
            var user = userManager.FindByName(name);
            if (user == null)
            {
                user = new ApplicationUser { UserName = name, Email = name };
                var result = userManager.Create(user, password);
                result = userManager.SetLockoutEnabled(user.Id, false);
            }

            // 把用戶Admin@alexzeng.net添加到用戶組Admin中
            var rolesForUser = userManager.GetRoles(user.Id);
            if (!rolesForUser.Contains(role.Name))
            {
                var result = userManager.AddToRole(user.Id, role.Name);
            }
        }
    }
}

最后一步:在IdentityModels.cs文件中修改:

 public ApplicationDbContext()
           
        {
            Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
        }

運(yùn)行后用Admin@alexzeng.net 進(jìn)行登錄即可。

有了Admin角色眠饮,我們可以設(shè)置為整個‘CMSAdminController’控制器都需要使用Admin權(quán)限才能進(jìn)入奥帘。其實(shí)非常簡單铜邮,打開控制器仪召,在命名空間的下面加入 [Authorize(Roles = "Admin")]就可以啦。

namespace AxCMS.Controllers
{
    [Authorize(Roles = "Admin")]
  ......

由于文章輸入依賴于用戶的輸入松蒜,我們需要對用戶輸入進(jìn)行一些限制扔茅,如果一些無效數(shù)據(jù)流入到數(shù)據(jù)庫里面,有可能會給我們的網(wǎng)站帶來一些麻煩秸苗。再回到模型召娜,打開Contents.cs文件。

注:需要加入命名空間using System.ComponentModel.DataAnnotations;

 public class Contents
    {
        public int ContentsId { get; set; }
        public string User { get; set; }
        [Required]
        [StringLength(160,MinimumLength =4)]
        [Display(Name ="標(biāo)題")]
        public string Title { get; set; }
        [Display(Name = "類別")]
        public int CategoryId { get; set; }
        public DateTime PublicationDate { get; set; }
        [Required]
        [Display(Name = "內(nèi)容")]
        public string Content { get; set; }
        public UserCommments UserCommments { get; set; }
        [Display(Name = "類別")]
        public Category Category { get; set; }
    }

運(yùn)行程序惊楼,壞了玖瘸,報錯了秸讹。不要著急,這是EF發(fā)現(xiàn)數(shù)據(jù)庫數(shù)據(jù)發(fā)生變化雅倒,重新更新一下就可以了璃诀。

打開“程序包管理控制臺”,依次輸入以下三個命令就可以了蔑匣。

 Enable-Migrations -ContextTypeName AxCMS.Models.AxCMSDBContext
 add-migration Initial
 update-database

下面對Create視圖做一些修改劣欢,打開Contents表,有ContentsId,User,Title,CategoryId,PublicationDate,Content等字段裁良,User是獲取作者的用戶名凿将,這個可以不用用戶輸入,刪除价脾。PublicationDate為當(dāng)前時間牧抵,也不用用戶輸入。

打開Create.cshtml侨把,修改如下:

@model AxCMS.Models.Contents

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Contents</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
       

        <div class="form-group">
            @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CategoryId, "標(biāo)題", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("CategoryId", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
            </div>
        </div>

        

        <div class="form-group">
            @Html.LabelFor(model => model.Content, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => model.Content, htmlAttributes: new {  @class = "form-control", @rows = 10  })
                @Html.ValidationMessageFor(model => model.Content, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

打開控制器灭忠,對HttpPost的Create進(jìn)行如下修改。

 [HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Create(FormCollection collection)
        {
            var contents = new Contents();
            if (TryUpdateModel(contents))
            {
                contents.PublicationDate = DateTime.Now;
                contents.User = User.Identity.Name;
                db.Contents.Add(contents);
                db.SaveChanges();
                return RedirectToAction("Index");
            }

            ViewBag.CategoryId = new SelectList(db.Categories, "CategoryId", "Name", contents.CategoryId);
            return View(contents);
        }

Edit也類似座硕,不過對用戶名和發(fā)布時間弛作,我們可以將其設(shè)為只讀而不用刪除,詳細(xì)代碼如下:

@model AxCMS.Models.Contents

@{
    ViewBag.Title = "Create";
}

<h2>Create</h2>


@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
    
    <div class="form-horizontal">
        <h4>Contents</h4>
        <hr />
        @Html.ValidationSummary(true, "", new { @class = "text-danger" })
       

        <div class="form-group">
            @Html.LabelFor(model => model.Title, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.EditorFor(model => model.Title, new { htmlAttributes = new { @class = "form-control" } })
                @Html.ValidationMessageFor(model => model.Title, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            @Html.LabelFor(model => model.CategoryId, "類別", htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.DropDownList("CategoryId", null, htmlAttributes: new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.CategoryId, "", new { @class = "text-danger" })
            </div>
        </div>

        

        <div class="form-group">
            @Html.LabelFor(model => model.Content, htmlAttributes: new { @class = "control-label col-md-2" })
            <div class="col-md-10">
                @Html.TextAreaFor(model => model.Content, htmlAttributes: new {  @class = "form-control", @rows = 10  })
                @Html.ValidationMessageFor(model => model.Content, "", new { @class = "text-danger" })
            </div>
        </div>

        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Create" class="btn btn-default" />
            </div>
        </div>
    </div>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

Edit在控制器中的代碼修改如下:

[HttpPost]
        [ValidateAntiForgeryToken]
        public ActionResult Edit(FormCollection collection)
        {
            var contents = new Contents();
            if (TryUpdateModel(contents))
            {
                db.Entry(contents).State = EntityState.Modified;
                db.SaveChanges();
                return RedirectToAction("Index");
            }
            ViewBag.CategoryId = new SelectList(db.Categories, "CategoryId", "Name", contents.CategoryId);
            return View(contents);
        }

好了华匾,文章這里修改得差不多了映琳,那么文章類別管理你會做了吧?

下面我們來看看如何將文章管理的鏈接接到全站的導(dǎo)航鏈接上面去蜘拉。

全站默認(rèn)模板在視圖文件夾里面萨西,打開..\Views\Shared_Layout.cshtml,修改里面的

  <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("主頁", "Index", "Home")</li>
                    <li>@Html.ActionLink("關(guān)于", "About", "Home")</li>
                    <li>@Html.ActionLink("聯(lián)系方式", "Contact", "Home")</li>
                </ul>

后面那兩個對我們沒有用旭旭,我們可以添加權(quán)限谎脯,讓擁有權(quán)限的用戶可以管理文章,管理用戶持寄。

 <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("主頁", "Index", "Home")</li>
    @if (Request.IsAuthenticated && User.IsInRole("Admin")) {
                        <li>@Html.ActionLink("管理文章", "Index", "CMSAdmin")</li>
                        <li>@Html.ActionLink("管理用戶", "Index", "UsersAdmin")</li>
                        <li>@Html.ActionLink("管理角色", "Index", "RolesAdmin")</li>
 }
                </ul>

這一節(jié)最后我們來完成一下首頁源梭,將文章數(shù)據(jù)移到首頁來,然后再加一個Details 稍味,參考CMSAdminController的Index和Details废麻,這個真心不難,這里不做討論模庐。

下一節(jié)烛愧,我們將完成用戶管理控制器:CMSUser,最后再完成用戶評論,用戶評論將在Details 頁面中顯示出來怜姿,并且對登錄用戶顯示文本框可以輸入評論慎冤,難度略有提高。

謝謝大家沧卢。轉(zhuǎn)帖的時候請把涼風(fēng)有興或者AlexZeng.net進(jìn)行署名粪薛。本文版權(quán)聲明:自由轉(zhuǎn)載-非商用-非衍生-保持署名(創(chuàng)意共享3.0許可證

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市搏恤,隨后出現(xiàn)的幾起案子违寿,更是在濱河造成了極大的恐慌,老刑警劉巖熟空,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件藤巢,死亡現(xiàn)場離奇詭異,居然都是意外死亡息罗,警方通過查閱死者的電腦和手機(jī)掂咒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來迈喉,“玉大人绍刮,你說我怎么就攤上這事“っ” “怎么了孩革?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長得运。 經(jīng)常有香客問我膝蜈,道長,這世上最難降的妖魔是什么熔掺? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任饱搏,我火速辦了婚禮,結(jié)果婚禮上置逻,老公的妹妹穿的比我還像新娘推沸。我一直安慰自己,他們只是感情好券坞,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布鬓催。 她就那樣靜靜地躺著,像睡著了一般报慕。 火紅的嫁衣襯著肌膚如雪深浮。 梳的紋絲不亂的頭發(fā)上压怠,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天眠冈,我揣著相機(jī)與錄音,去河邊找鬼。 笑死蜗顽,一個胖子當(dāng)著我的面吹牛布卡,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播雇盖,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼忿等,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了崔挖?” 一聲冷哼從身側(cè)響起贸街,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狸相,沒想到半個月后薛匪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡脓鹃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年逸尖,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片瘸右。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡娇跟,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出太颤,到底是詐尸還是另有隱情苞俘,我是刑警寧澤,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布龄章,位于F島的核電站苗胀,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瓦堵。R本人自食惡果不足惜基协,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望菇用。 院中可真熱鬧澜驮,春花似錦、人聲如沸惋鸥。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽卦绣。三九已至耐量,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間滤港,已是汗流浹背廊蜒。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工趴拧, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人山叮。 一個月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓著榴,卻偏偏與公主長得像,于是被迫代替她去往敵國和親屁倔。 傳聞我的和親對象是個殘疾皇子脑又,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)锐借,斷路器问麸,智...
    卡卡羅2017閱讀 134,628評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,737評論 25 707
  • 國家電網(wǎng)公司企業(yè)標(biāo)準(zhǔn)(Q/GDW)- 面向?qū)ο蟮挠秒娦畔?shù)據(jù)交換協(xié)議 - 報批稿:20170802 前言: 排版 ...
    庭說閱讀 10,916評論 6 13
  • 今天吃晚飯的時候嗅战,媽媽說起妄田,今天初六了,明天就是七夕了驮捍。好吧疟呐,我表示不知道。因?yàn)槊魈煳胰匀灰弦惶斓恼n东且。 說實(shí)話启具,...
    成長的溫度閱讀 362評論 0 0
  • 你家孩子厭食?不愛吃飯珊泳?每頓吃飯都讓你發(fā)愁鲁冯? 那是因?yàn)樯頌閶寢尩哪悴粣蹌邮郑粣蹌幽X的原因色查,問題絕對不是出在孩子...
    西瓜甜甜啦閱讀 440評論 21 21