点耐特经典收藏mvc

ASP.NET MVC开发:带后台的CMS开发

2016-11-20  本文已影响1540人  凉风有兴

本来这一篇写的是一个音乐商城的程序的创建,但我啰啰嗦嗦写了三大篇,结果很多业务都没交代清楚,干脆就删了,重写一篇。这一篇重点的地方都有提及,包括会员管理员、文章发布、权限管理,实在是入门最佳教材,遥想入门当年,怎么遇不到这种文章呢?呵呵。由于MVC开发性能卓越,基本上可以在一天之内完成这个开发任务。学了这个,开发个小型商业网站大概也就两三天的功夫。

基本的思路先画一个思维导图厘清一下思路:

本例子使用了IDentity进行用户验证,同时也使用了角色,角色设为Admin可以管理用户,也可以管理文章。普通用户除了发表评论外就没有其他功能了。

控制器方面,我用了AxCMSAdmin控制器,作为管理文章用。

数据库设计如下图,这里并不包括IDentity生成的数据库,只包括CMS简单业务。

假设你已经有了一个完整的包含整个IDentity业务的项目,项目名称为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; }
    }
}

全部保存之后,点击生成菜单里面的生成解决方案。

好了,现在我们来完成一个新的控制器,右击解决方案资源管理器的Controllers文件夹,添加新的控制器,选择 "包含视图的MVC 5控制器(使用 Entity Framework)",设置如下图:

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 = "经营" });
            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);
        }

运行程序,我们可以发现数据库已经完成了并且有了一两笔播种数据。

一般我们一个程序都在一个数据库里面,在还没有使用注册的情况下,IDentity并不会给你一个默认的数据库,打开web.config文件,将<add name="DefaultConnection" 下面的数据库文件名改为<add name="AxCMSDBContext" 里面的文件名。

现在,我们在启用IDentity的用户管理同时,也启用角色:

第一步:打开IdentityConfig.cs,往里面增加代码

//配置此应用程序中使用的应用程序角色管理器。RoleManager 在 ASP.NET Identity 中定义,并由此应用程序使用。
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);   //添加的角色管理器

第三步:创建种子数据,新建ApplicationDbInitializer.cs类,将数据加入

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用户组则创建该组
            var role = roleManager.FindByName(roleName);
            if (role == null)
            {
                role = new IdentityRole(roleName);
                var roleresult = roleManager.Create(role);
            }

            //如果没有Admin@alexzeng.net用户则创建该用户
            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());
        }

运行后用Admin@alexzeng.net 进行登录即可。

有了Admin角色,我们可以设置为整个‘CMSAdminController’控制器都需要使用Admin权限才能进入。其实非常简单,打开控制器,在命名空间的下面加入 [Authorize(Roles = "Admin")]就可以啦。

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

由于文章输入依赖于用户的输入,我们需要对用户输入进行一些限制,如果一些无效数据流入到数据库里面,有可能会给我们的网站带来一些麻烦。再回到模型,打开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 ="标题")]
        public string Title { get; set; }
        [Display(Name = "类别")]
        public int CategoryId { get; set; }
        public DateTime PublicationDate { get; set; }
        [Required]
        [Display(Name = "内容")]
        public string Content { get; set; }
        public UserCommments UserCommments { get; set; }
        [Display(Name = "类别")]
        public Category Category { get; set; }
    }

运行程序,坏了,报错了。不要着急,这是EF发现数据库数据发生变化,重新更新一下就可以了。

打开“程序包管理控制台”,依次输入以下三个命令就可以了。

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

下面对Create视图做一些修改,打开Contents表,有ContentsId,User,Title,CategoryId,PublicationDate,Content等字段,User是获取作者的用户名,这个可以不用用户输入,删除。PublicationDate为当前时间,也不用用户输入。

打开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, "标题", 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进行如下修改。

 [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也类似,不过对用户名和发布时间,我们可以将其设为只读而不用删除,详细代码如下:

@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);
        }

好了,文章这里修改得差不多了,那么文章类别管理你会做了吧?

下面我们来看看如何将文章管理的链接接到全站的导航链接上面去。

全站默认模板在视图文件夹里面,打开..\Views\Shared_Layout.cshtml,修改里面的

  <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("主页", "Index", "Home")</li>
                    <li>@Html.ActionLink("关于", "About", "Home")</li>
                    <li>@Html.ActionLink("联系方式", "Contact", "Home")</li>
                </ul>

后面那两个对我们没有用,我们可以添加权限,让拥有权限的用户可以管理文章,管理用户。

 <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>

这一节最后我们来完成一下首页,将文章数据移到首页来,然后再加一个Details ,参考CMSAdminController的Index和Details,这个真心不难,这里不做讨论。

下一节,我们将完成用户管理控制器:CMSUser,最后再完成用户评论,用户评论将在Details 页面中显示出来,并且对登录用户显示文本框可以输入评论,难度略有提高。

谢谢大家。转帖的时候请把凉风有兴或者AlexZeng.net进行署名。本文版权声明:自由转载-非商用-非衍生-保持署名(创意共享3.0许可证

上一篇下一篇

猜你喜欢

热点阅读