MVC3学习第十二章 佟掌柜第一弹----利用MVC3实现用户的注册登录和了解MVC中的分部视图、用户控件
本章学习内容
1.通过完成用户的登录注册了解如何在MVC3视图输出提示信息
2.了解使用MVC3中的分部视图(用户控件,@Html.RenderAction(),@Html.RenderPartial,@Html.Partial(),@Html.Action()),并以此实现用户登录状态检查
1.通过完成用户的登录注册了解如何在MVC3视图输出提示信息
之前我们完成了商品和用户的相关管理,但是我们不想让每一个人都可以随意管理,我们需要只有输入正确的用户名和密码登录的用户才可以操作这些数据,这时候,我们就需要用户的登录和注册功能。
首先,我们来完成用户注册和登录功能的控制器部分,修改UserInfo控制器完整代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MyShopTest.Models; using System.Data; namespace MyShopTest.Controllers { public class UserInfoController : Controller { //数据访问 private MyShopDataEntities db = new MyShopDataEntities(); /// <summary> /// 用户列表Action /// </summary> /// <returns></returns> public ActionResult Index(string name = "", string phone = "13112345678")//可选参数 { var users = SearchUser(phones: phone, names: name);//命名参数,命名参数必须出现在所有固定参数之后 ViewBag.Name = name; ViewBag.Phone = phone; return View(users); } /// <summary> /// 实现用户查询 /// </summary> /// <param name="name"></param> /// <param name="phone"></param> /// <returns></returns> public IEnumerable<UserInfo> SearchUser(string names, string phones) { if (string.IsNullOrEmpty(phones)) { phones = "13112345678"; } var users = db.UserInfos.Where(user => user.Id > 0);//此处的查询没有任何意义,只是返回所有用户 if (!string.IsNullOrEmpty(names)) { users = users.Where(user => user.UserName.IndexOf(names) > -1); } users = users.Where(user => user.Phone == phones); return users; } /// <summary> /// 添加用户页面展示 /// </summary> /// <returns></returns> public ActionResult Create() { return View(); } /// <summary> /// 添加用户处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Create(UserInfo user) { return AddUser(user, "Index"); } private ActionResult AddUser(UserInfo user, string responseUrl) { db.UserInfos.Add(user); db.SaveChanges(); return RedirectToAction(responseUrl); } /// <summary> /// 编辑用户页面展示 /// </summary> /// <returns></returns> public ActionResult Edit(int id) { var user = db.UserInfos.Find(id); return View(user); } /// <summary> /// 编辑用户处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Edit(UserInfo user) { try { if (ModelState.IsValid) { db.Entry(user).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } else { throw new Exception(); } } catch (Exception ex) { ModelState.AddModelError("", "更改失败"); } return View(user); } /// <summary> /// 删除操作处理 /// </summary> /// <returns></returns> public ActionResult Delete(int id) { var user = db.UserInfos.Find(id); db.UserInfos.Remove(user); db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 批量删除操作处理 /// </summary> /// <param name="coll"></param> /// <returns></returns> [HttpPost] public ActionResult Deletes(FormCollection coll) { string ids = coll["ckSelect"]; foreach (var item in ids.Split(','))//循环每一项Id { if (item != "false")//筛选掉自动生成的checkbox初始值 { var user = db.UserInfos.Find(Convert.ToInt32(item)); db.UserInfos.Remove(user); } } db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 注册用户页面展示 /// </summary> /// <returns></returns> public ActionResult Register() { return View(); } /// <summary> /// 注册用户处理 /// </summary> /// <returns></returns> [HttpPost] public void Register(UserInfo user) { AddUser(user, "Login"); Response.Write("<script>alert('用户注册成功,点击确定转向登录!');window.location.href='/UserInfo/Login';</script>"); } /// <summary> /// 登录用户页面展示 /// </summary> /// <returns></returns> public ActionResult Login() { return View(); } /// <summary> /// 登录处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Login(string UserName, string UserPwd) { var user = db.UserInfos.SingleOrDefault(u => u.UserName == UserName && u.UserPwd == UserPwd); if (user != null) { Session["User"] = user; return RedirectToAction("Index"); } else { user = new UserInfo(); user.UserName = UserName; user.UserPwd = UserPwd; ModelState.AddModelError("","用户名或密码错误!"); return View(user); } } /// <summary> /// 注销 /// </summary> /// <returns></returns> public ActionResult LogOff() { Session["User"] = null; return RedirectToAction("Login"); } } }
看一下修改的代码:
/// <summary> /// 登录处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Login(string UserName, string UserPwd) { var user = db.UserInfos.SingleOrDefault(u => u.UserName == UserName && u.UserPwd == UserPwd); if (user != null) { Session["User"] = user; return RedirectToAction("Index"); } else { user = new UserInfo(); user.UserName = UserName; user.UserPwd = UserPwd; ModelState.AddModelError("","用户名或密码错误!"); return View(user); } }
根据登录用户名和密码查询对应用户,查到了则把用户赋值给session["User"],否则给出错误信息,返回Login视图;
/// <summary> /// 注销 /// </summary> /// <returns></returns> public ActionResult LogOff() { Session["User"] = null; return RedirectToAction("Login"); }
注销代码,清空用户信息session,转向登录。
/// <summary> /// 注册用户处理 /// </summary> /// <returns></returns> [HttpPost] public void Register(UserInfo user) { AddUser(user, "Login"); Response.Write("<script>alert('用户注册成功,点击确定转向登录!');window.location.href='/UserInfo/Login';</script>"); }
至于注册代码其实和添加代码一样,我们提取了添加代码为一个方法,在注册和添加方法里都调用此方法即可。使用Response.Write方法输出一个脚本,实现在MVC下简单的弹出js提示框的效果,当然并不推荐此种方式,在MVC3下弹出js提示框还可以使用返回JavascriptResult然后在视图里调用,或者保存把提示信息保存在ViewBag里等等,当然与mvc3结合最好的是网上流行的jquery ui了,本人这方面知识比较浅薄,所以暂不讲解这方面的东西。
登陆注册的控制器部分完成了,现在我们来添加对应试图,
为UserInfo添加注册试图,命名为Register.cshtml,完整代码如下:
@model MyShopTest.Models.UserInfo @{ ViewBag.Title = "注册用户"; } <h2> 注册用户</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> <p> 已有帐号,<a href="Login">点此</a>登录 </p> @using (Html.BeginForm()) { <fieldset> <legend>注册用户</legend> <div class="editor-label"> @Html.LabelFor(model => model.UserName) </div> <div class="editor-field"> @Html.EditorFor(model => model.UserName) @Html.ValidationMessageFor(model => model.UserName) </div> <div class="editor-label"> @Html.LabelFor(model => model.UserPwd) </div> <div class="editor-field"> @Html.PasswordFor(model => model.UserPwd) @Html.ValidationMessageFor(model => model.UserPwd) </div> <div class="editor-label"> @Html.LabelFor(model => model.Phone) </div> <div class="editor-field"> @Html.EditorFor(model => model.Phone) @Html.ValidationMessageFor(model => model.Phone) </div> <div class="editor-label"> @Html.LabelFor(model => model.Email) </div> <div class="editor-field"> @Html.EditorFor(model => model.Email) @Html.ValidationMessageFor(model => model.Email) <input type="hidden" name="AddTime" value="@DateTime.Now"/> </div> <p> <input type="submit" value="注册用户" /> </p> </fieldset> } <div> </div>
添加登录视图,命名为Login.cshtml,完整代码如下:
@model MyShopTest.Models.UserInfo @{ ViewBag.Title = "用户登录"; } <h2> 用户登录</h2> <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script> <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script> <p> 没有有帐号,<a href="Register">点此</a>注册 </p> @using (Html.BeginForm()) { @Html.ValidationSummary(true) <fieldset> <legend>用户登录</legend> <div class="editor-label"> @Html.LabelFor(model => model.UserName) </div> <div class="editor-field"> @Html.EditorFor(model => model.UserName) @Html.ValidationMessageFor(model => model.UserName) </div> <div class="editor-label"> @Html.LabelFor(model => model.UserPwd) </div> <div class="editor-field"> @Html.PasswordFor(model => model.UserPwd) @Html.ValidationMessageFor(model => model.UserPwd) </div> <p> <input type="submit" value="登录" /> </p> </fieldset> }
修改Home控制器,使得进入用户程序时首先定位到登录页面:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MyShopTest.Controllers { public class HomeController : Controller { public ActionResult Index() { //ViewBag.Message = "Hello World!"; //ViewBag.MyName = "韩若怅"; //ViewBag.ProjectName = "我的商店"; //List<string> list = new List<string> { "测试ViewBag作用"}; //ViewBag.List = list; //return View(); return RedirectToAction("../UserInfo/Login"); } public ActionResult About() { return View(); } } }
至此,基本的用户登录和注册功能我们已经完成了,重新编译项目,运行,我们看一下效果:
注册
自行可以测试一下功能。
2.了解使用MVC3中的分部视图(用户控件,@Html.RenderAction(),@Html.RenderPartial,@Html.Partial(),@Html.Action()),并以此实现用户登录状态检查
在之前我们实现了用户的登录和注册,并将首页定位到登录页面,要求用户的所有操作必须先登录帐号,但是新的问题出现了,
1).不是所有的用户操作都需要用户登录。
2).假如用户记住了url,直接输入url访问对应功能,我们还缺少为每个需要登录的操作进行登录检查。
现在我们来逐一解决这两个问题,
不是所有的用户操作都需要用户登录。
有的比如用户登录,注册,首页,商品浏览,详细等功能并不需要用户登录,我们为这些操作的页面添加一个母版页,在前几章里我们讲解母版页知识的时候,添加了MyMaster.cshtml,现在还没有删除,我们直接修改该母版页即可,完整代码如下:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1> 我的商店</h1> </div> <div id="logindisplay"> @Html.Partial("_LogOnPartial") </div> <div id="menucontainer"> <ul id="menu"> <li>@Html.ActionLink("主页", "Index", "Home")</li> <li>@Html.ActionLink("新闻动态", "Index", "Home")</li> <li>@Html.ActionLink("互动留言", "Index", "Home")</li> <li>@Html.ActionLink("关于我们", "About", "Home")</li> </ul> </div> </div> <div id="main"> @RenderBody() </div> <div id="footer"> <ul style="position: relative; text-align: left;"> <li style="display: inline;">@Html.ActionLink("类别管理", "Index", "Category")</li> <li style="display: inline;">@Html.ActionLink("商品管理", "Index", "Product")</li> <li style="display: inline;">@Html.ActionLink("留言管理", "Index", "FeedBack")</li> <li style="display: inline;">@Html.ActionLink("新闻管理", "Index", "News")</li> <li style="display: inline;">@Html.ActionLink("用户管理", "Index", "UserInfo")</li> </ul> </div> </div> </body> </html>
修改_LogOnPartial.cshtml完整代码如下:
@if (Session["User"] != null) { <text>欢迎 <strong>@(((MyShopTest.Models.UserInfo)Session["User"]).UserName)</strong>! [ @Html.ActionLink("注销", "LogOff", "UserInfo") ]</text> } else { <text>[ @Html.ActionLink("登录", "Login", "UserInfo") ] </text> } [ @Html.ActionLink("注册", "Register", "UserInfo")]
由于我们还缺少商品前台浏览页面,我们需要添加该页面,我们为商品浏览添加控制器的Action,修改ProductController.cs,完整代码如下:
using System; using System.Collections.Generic; using System.Data; using System.Data.Entity; using System.Linq; using System.Web; using System.Web.Mvc; using MyShopTest.Models; using System.Data.Entity.Validation; namespace MyShopTest.Controllers { public class ProductController : Controller { private MyShopDataEntities db = new MyShopDataEntities(); //列表 public ViewResult Index(string title = "") { var products = Search(title); ViewBag.Name = title; return View(products.ToList()); } //商品查询 public IEnumerable<Product> Search(string titles) { var products = db.Products.Include(p => p.Category).Where(p => p.Id > 0);//此处的查询没有任何意义,只是返回所有数据 products = products.OrderBy(p => p.AddTime);//根据时间升序排列 //products = products.OrderByDescending(p => p.Id);//根据Id降序排列 if (!string.IsNullOrEmpty(titles)) { products = products.Where(p => p.Title.IndexOf(titles) > -1 || p.Category.Name.IndexOf(titles) > -1); } return products; } //商品浏览 public ViewResult Browse(string title = "") { var products = Search(title); ViewBag.Name = title; return View(products.ToList()); } //商品展示 public ViewResult Show(int cId = 0) { var cat = db.Category.Single(c => c.Id == cId); //var cat = db.Category.Include(c => c.Products).Single(c => c.Id == cId);//两者作用一样,可以直接获取不用include,但是经测试发现没有给对应主外键的实体填写virtual修饰符时,不写Include得不到关联实体的值 return View(cat); } //详细 public ViewResult Details(int id) { Product product = db.Products.Find(id); return View(product); } //添加 public ActionResult Create() { ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name"); return View(); } //添加处理 [HttpPost] public ActionResult Create(Product product)//此时已经自动匹配好了 { try { //图片 var file = Request.Files[0]; var img = new CommonHelper().fileSaveAs(file, 0, 2); if (img.IndexOf("UpFile") > -1) { product.ImgUrl = img; } else { ModelState.AddModelError("error", img);//添加了key的错误信息,前台使用Html.ValidationMessage(key)的形式访问,如果key为空,用Html.ValidationSummary(true)显示 ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name", product.CategoryId); return View(product); } db.Products.Add(product); db.SaveChanges(); return RedirectToAction("Index"); } catch (DbEntityValidationException ex) { string mes = ex.Message; ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name", product.CategoryId); return View(product); } } //编辑 public ActionResult Edit(int id) { Product product = db.Products.Find(id); ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name", product.CategoryId); return View(product); } //编辑处理 [HttpPost] public ActionResult Edit(int id, FormCollection collection) { var product = db.Products.Find(id); //ModelState.IsValid,此处相当于后台验证,防止前台验证因为各种情况被跳过或失效 try { bool updateRes = TryUpdateModel(product);//如果字段符合则会赋值,否则保持原有 //db.Entry(product).State = EntityState.Modified; if (updateRes) { //图片 var file = Request.Files[0]; var img = new CommonHelper().fileSaveAs(file, 0, 2); if (img.IndexOf("UpFile") > -1) { product.ImgUrl = img; } //else //{ // ModelState.AddModelError("", img); // ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name", product.CategoryId); // return View(product); //} db.SaveChanges(); return RedirectToAction("Index"); } else { ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name", product.CategoryId); ModelState.AddModelError("", "更新失败!"); return View(product); } } catch (Exception) { ViewBag.CategoryId = new SelectList(db.Category, "Id", "Name", product.CategoryId); return View(product); } } //删除处理 [HttpPost] public ActionResult Delete(FormCollection coll) { string ids = coll["ckSelect"]; foreach (var item in ids.Split(','))//循环每一项Id { if (item != "false")//筛选掉自动生成的checkbox初始值 { var user = db.Products.Find(Convert.ToInt32(item)); db.Products.Remove(user); } } db.SaveChanges(); return RedirectToAction("Index"); } protected override void Dispose(bool disposing) { db.Dispose(); base.Dispose(disposing); } } }
添加浏览视图Browse.cshtml,修改完整代码如下:
@model IEnumerable<MyShopTest.Models.Product> @{ ViewBag.Title = "商品浏览"; } @using MyShopTest.Models <h2> 商品浏览</h2> @using (Html.BeginForm("Browse", "Product", FormMethod.Post)) { <p> 名称或类别:<input type="text" name="title" value="@ViewBag.Name" /> <input type="submit" value="查询" /> </p> <table> <tr> <th> 名称 </th> <th> 价格 </th> <th> 类别 </th> <th> 上架时间 </th> <th> 操作 </th> </tr> @foreach (var item in Model) { <tr> <td> @Html.CutString(item.Title, 10) </td> <td> @Html.DisplayFor(modelItem => item.Price) </td> <td> @Html.ActionLink(item.Category.Name, "Show", new { cId = item.CategoryId }) | </td> <td> @Html.DisplayFor(modelItem => item.AddTime) </td> <td> @Html.ActionLink("查看详细", "Details", new { id = item.Id }, new { target = "_blank" }) | </td> </tr> } </table> }
修改HomeController,重新定位首页,完整代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; namespace MyShopTest.Controllers { public class HomeController : Controller { public ActionResult Index() { //ViewBag.Message = "Hello World!"; //ViewBag.MyName = "韩若怅"; //ViewBag.ProjectName = "我的商店"; //List<string> list = new List<string> { "测试ViewBag作用"}; //ViewBag.List = list; //return View(); return RedirectToAction("../Product/Browse"); } public ActionResult About() { return View(); } } }
重新编译项目,运行,我们来看一下效果:
以上代码没有新知识,除了MyMaster中的 @Html.Partial("_LogOnPartial"),这个我们稍后会讲解。现在我们来为我们不需要登录的页面运用MyMaster母版页,分别在Product/Browse.cshtml,Product/Show.cshtml,Product/Details.cshtml,UserInfo/Login.cshtml,UserInfo/Register.cshtml头部 ViewBag.Title下方添加下行代码:
Layout = "~/Views/Shared/MyMaster.cshtml";
重新编译项目,运行,并未看出区别,不要着急,接下来我们来解决第二个问题:
假如用户记住了url,直接输入url访问对应功能,我们还缺少为每个需要登录的操作进行登录检查。
我们右键Shared文件夹,添加视图,命名为CheckLogin
如图,勾选创建为分部视图,至于什么是分部视图,我们后续讲解,修改完整代码如下:
@if (Session["User"] != null) { <text>欢迎 <strong>@(((MyShopTest.Models.UserInfo)Session["User"]).UserName)</strong>! [ @Html.ActionLink("注销", "LogOff", "UserInfo") ]</text> } else { Response.Redirect("~/UserInfo/Login"); }
修改_Layout.cshtml完整代码如下:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1> 我的商店</h1> </div> <div id="logindisplay"> @Html.Partial("CheckLogin") </div> <div id="menucontainer"> <ul id="menu"> <li>@Html.ActionLink("主页", "Index", "Home")</li> <li>@Html.ActionLink("新闻动态", "Index", "Home")</li> <li>@Html.ActionLink("互动留言", "Index", "Home")</li> <li>@Html.ActionLink("关于我们", "About", "Home")</li> </ul> </div> </div> <div id="main"> @RenderBody() </div> <div id="footer"> <ul style="position: relative; text-align: left;"> <li style="display: inline;">@Html.ActionLink("类别管理", "Index", "Category")</li> <li style="display: inline;">@Html.ActionLink("商品管理", "Index", "Product")</li> <li style="display: inline;">@Html.ActionLink("留言管理", "Index", "FeedBack")</li> <li style="display: inline;">@Html.ActionLink("新闻管理", "Index", "News")</li> <li style="display: inline;">@Html.ActionLink("用户管理", "Index", "UserInfo")</li> </ul> </div> </div> </body> </html>
重新编译项目,运行,
点击商品或者类别、用户、管理会要求登录,
如果已经登录,查看浏览商品也可以显示出用户信息:
至此我们已经解决了上述的两个问题,可以看到在解决上述两个问题的时候我们通过建立了不同的母版页,然后在母版页里进行了相关检查,其实最终的检查操作是由我们建立的“分部视图“来完成的,什么是分部视图呢?很多时候我们想创建一个内容和代码都可以重用的组件,在webform,我们可以创建一个web用户控件或web服务器控件。但是在MVC,我们应该用分部视图,在这个概念的角度看,对任何情景的应用情景都应该有用。说的更明白一些,它就是razo下的用户控件。
@Html.Partial("_LogOnPartial")
此段代码表示直接引用指定名称的分部视图,分部视图的内容显示在此处指定位置。至于分部视图里的代码我们就不说了,无非是检查当前登录用户输出对应信息之类的。
我们再看看_Layout.cshtml
@Html.Partial("CheckLogin")
也是一样,引用分部视图,然后在分部视图里执行检查操作,现在有一个问题,我们不想在CheckLogin视图里写if、else的逻辑处理,我们想这些操作在控制器里完成,至于试图只需要显示一下信息就行了,这样更符合MVC3的初衷,OK,我们改造一下:
修改UsrtInfo控制器完整代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using MyShopTest.Models; using System.Data; namespace MyShopTest.Controllers { public class UserInfoController : Controller { //数据访问 private MyShopDataEntities db = new MyShopDataEntities(); /// <summary> /// 用户列表Action /// </summary> /// <returns></returns> public ActionResult Index(string name = "", string phone = "13112345678")//可选参数 { var users = SearchUser(phones: phone, names: name);//命名参数,命名参数必须出现在所有固定参数之后 ViewBag.Name = name; ViewBag.Phone = phone; return View(users); } /// <summary> /// 实现用户查询 /// </summary> /// <param name="name"></param> /// <param name="phone"></param> /// <returns></returns> public IEnumerable<UserInfo> SearchUser(string names, string phones) { if (string.IsNullOrEmpty(phones)) { phones = "13112345678"; } var users = db.UserInfos.Where(user => user.Id > 0);//此处的查询没有任何意义,只是返回所有用户 if (!string.IsNullOrEmpty(names)) { users = users.Where(user => user.UserName.IndexOf(names) > -1); } users = users.Where(user => user.Phone == phones); return users; } /// <summary> /// 添加用户页面展示 /// </summary> /// <returns></returns> public ActionResult Create() { return View(); } /// <summary> /// 添加用户处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Create(UserInfo user) { return AddUser(user, "Index"); } private ActionResult AddUser(UserInfo user, string responseUrl) { db.UserInfos.Add(user); db.SaveChanges(); return RedirectToAction(responseUrl); } /// <summary> /// 编辑用户页面展示 /// </summary> /// <returns></returns> public ActionResult Edit(int id) { var user = db.UserInfos.Find(id); return View(user); } /// <summary> /// 编辑用户处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Edit(UserInfo user) { try { if (ModelState.IsValid) { db.Entry(user).State = EntityState.Modified; db.SaveChanges(); return RedirectToAction("Index"); } else { throw new Exception(); } } catch (Exception ex) { ModelState.AddModelError("", "更改失败"); } return View(user); } /// <summary> /// 删除操作处理 /// </summary> /// <returns></returns> public ActionResult Delete(int id) { var user = db.UserInfos.Find(id); db.UserInfos.Remove(user); db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 批量删除操作处理 /// </summary> /// <param name="coll"></param> /// <returns></returns> [HttpPost] public ActionResult Deletes(FormCollection coll) { string ids = coll["ckSelect"]; foreach (var item in ids.Split(','))//循环每一项Id { if (item != "false")//筛选掉自动生成的checkbox初始值 { var user = db.UserInfos.Find(Convert.ToInt32(item)); db.UserInfos.Remove(user); } } db.SaveChanges(); return RedirectToAction("Index"); } /// <summary> /// 注册用户页面展示 /// </summary> /// <returns></returns> public ActionResult Register() { return View(); } /// <summary> /// 注册用户处理 /// </summary> /// <returns></returns> [HttpPost] public void Register(UserInfo user) { AddUser(user, "Login"); Response.Write("<script>alert('用户注册成功,点击确定转向登录!');window.location.href='/UserInfo/Login';</script>"); } /// <summary> /// 登录用户页面展示 /// </summary> /// <returns></returns> public ActionResult Login() { return View(); } /// <summary> /// 登录处理 /// </summary> /// <returns></returns> [HttpPost] public ActionResult Login(string UserName, string UserPwd) { var user = db.UserInfos.SingleOrDefault(u => u.UserName == UserName && u.UserPwd == UserPwd); if (user != null) { Session["User"] = user; return RedirectToAction("Index"); } else { user = new UserInfo(); user.UserName = UserName; user.UserPwd = UserPwd; ModelState.AddModelError("", "用户名或密码错误!"); return View(user); } } /// <summary> /// 注销 /// </summary> /// <returns></returns> public ActionResult LogOff() { Session["User"] = null; return RedirectToAction("Login"); } [ChildActionOnly] public PartialViewResult CheckLogin() { if (Session["User"] == null) { Response.Redirect("/UserInfo/Login"); //return RedirectToAction("Login"); return null; } else { var user = ((MyShopTest.Models.UserInfo)Session["User"]); return PartialView("CheckLogin", user); } } } }
把CheckLogin.cshtml移动到UserInfo下,修改完整代码如下:
@model MyShopTest.Models.UserInfo
欢迎 <strong>@Model.UserName</strong>!
修改_Layout.cshtml完整代码如下:
<!DOCTYPE html> <html> <head> <title>@ViewBag.Title</title> <link href="@Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" /> <script src="@Url.Content("~/Scripts/jquery-1.5.1.min.js")" type="text/javascript"></script> </head> <body> <div class="page"> <div id="header"> <div id="title"> <h1> 我的商店</h1> </div> <div id="logindisplay"> @{Html.RenderAction("CheckLogin","UserInfo");} </div> <div id="menucontainer"> <ul id="menu"> <li>@Html.ActionLink("主页", "Index", "Home")</li> <li>@Html.ActionLink("新闻动态", "Index", "Home")</li> <li>@Html.ActionLink("互动留言", "Index", "Home")</li> <li>@Html.ActionLink("关于我们", "About", "Home")</li> </ul> </div> </div> <div id="main"> @RenderBody() </div> <div id="footer"> <ul style="position: relative; text-align: left;"> <li style="display: inline;">@Html.ActionLink("类别管理", "Index", "Category")</li> <li style="display: inline;">@Html.ActionLink("商品管理", "Index", "Product")</li> <li style="display: inline;">@Html.ActionLink("留言管理", "Index", "FeedBack")</li> <li style="display: inline;">@Html.ActionLink("新闻管理", "Index", "News")</li> <li style="display: inline;">@Html.ActionLink("用户管理", "Index", "UserInfo")</li> </ul> </div> </div> </body> </html>
编译项目运行,可以看到依然实现了我们之前的结果,现在我们来解析一下代码:
User控制器:
[ChildActionOnly] public PartialViewResult CheckLogin() { if (Session["User"] == null) { Response.Redirect("/UserInfo/Login"); //return RedirectToAction("Login"); return null; } else { var user = ((MyShopTest.Models.UserInfo)Session["User"]); return PartialView("CheckLogin", user); } }
创建检测用户的Action,ChildActionOnly表示只能通过视图里的Html.RenderAction访问,而不能直接通过地址栏访问,在这个Action里我们实现了用户检测的逻辑,如果失败要求登陆,如果成功则返回将用户信息对应视图,注意一下,这里我们在分部视图的Action里实现跳转使用的是Response.Redirect而不是RedirectToAction,因为使用RedirectToAction会报错,提示子视图不能跳转
_Layout.cshtml,
@{Html.RenderAction("CheckLogin","UserInfo");}
调用分部视图的代码换成了这个,应该也很好理解。
asp.net MVC3.0 中@Html.Partial,@Html.Action,@Html.RenderPartial,@Html.RenderAction
1、带有Render的方法返回值是void,在方法内部进行输出;不带的返回值类型为MvcHtmlString,所以只能这样使用:
@Html.Partial 对应 @{Html.RenderPartial(....);}@Html.Action 对应 @{Html.RenderAction(....);}
2、Html.Partial可以直接提供用户控件名作为参数,
而Html.Action需要有对应的Action,在Action内部返回PartailResult(即retun PartialView())。
3、对于简单的没有任何逻辑的用户控件,推荐使用Html.Partial;对于需要设置一些Model的用户控件,推荐使用Html.Action。当然,有 Model数据也是可以使用Html.Partial方法的,可以看方法的重载。
4、使用Html.Action有个好处,就是可以根据不同的场景选择不同的用户控件。比如:@Html.Action("UserInfoControl")在对应的 UserInfoControl这个Action中,在用户未登录的时候,可以retun PartialView("LogOnUserControl");登录后,可以retun PartialView("UserInfoControl");
可以参考http://hi.baidu.com/wyg_bd/item/6e96283be4730dcd382ffa44