本來這一篇寫的是一個音樂商城的程序的創(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許可證)