• 七天学会ASP.NET MVC (五)——Layout页面使用和用户角色管理


    day5

    目录

    实验22——添加页脚

    实验23——实现用户角色管理

    实验24——实现项目外观一致性

    实验25——使用Action  过滤器让页眉和页脚代码更有效

    总结

    实验22——添加页脚

    在本实验中,我们会在Employee 页面添加页脚,通过本实验理解分部视图。

    什么是“分部视图”?

    从逻辑上看,分部视图是一种可重用的视图,不会直接显示,包含于其他视图中,作为其视图的一部分来显示。用法与用户控件类似,但不需要编写后台代码。

    1. 创建分部视图的 ViewModel

    右击 ViewModel 文件夹,新建 FooterViewModel 类,如下:

       1:  public class FooterViewModel
       2:  {
       3:     public string CompanyName { get; set; }
       4:     public string Year { get; set; }
       5:  }

    2. 创建分部视图

    右击“~/Views/Shared”文件夹,选择添加->视图。

    输入View 名称”Footer”,选择复选框“Create as a partial view”,点击添加按钮。

    注意:View中的Shared 共享文件夹是为每个控制器都可用的文件夹,不是某个特定的控制器所属。

    3. 在分部View 中显示数据

    打开Footer.cshtml,输入以下HTML 代码。

       1:  @using WebApplication1.ViewModels
       2:   
       3:  @model FooterViewModel
       4:   
       5:  <div style="text-align:right;background-color: silver;color: darkcyan;border: 1px solid gray;margin-top:2px;padding-right:10px;">
       6:   
       7:     @Model.CompanyName © @Model.Year
       8:   
       9:  </div>

    4.  在Main ViewModel 中包含Footer 数据

    打开 EmployeeListViewModel 类,添加新属性,保存 Footer数据,如下:

       1:  public class EmployeeListViewModel
       2:  {
       3:      public List<EmployeeViewModel> Employees { get; set; }
       4:   
       5:      public string UserName { get; set; }
       6:   
       7:      public FooterViewModel FooterData { get; set; }//New Property
       8:  }

    在本实验中Footer会作为Index View的一部分显示,因此需要将Footer的数据传到Index View页面中。Index View 是EmployeeListViewModel的强类型View,因此Footer需要的所有数据都应该封装在EmployeeListViewModel中。

    5. 设置Footer 数据

    打开 EmployeeController ,在Index  action 方法中设置FooterData 属性值,如下:

       1:  public ActionResult Index()
       2:  {
       3:     ...
       4:     ...
       5:      employeeListViewModel.FooterData = new FooterViewModel();
       6:      employeeListViewModel.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value
       7:      employeeListViewModel.FooterData.Year = DateTime.Now.Year.ToString();
       8:      return View("Index", employeeListViewModel);
       9:  }

    6. 显示Footer

    打开Index.cshtml 文件,在Table 标签后显示Footer 分部View,如下:

       1:  </table>
       2:          @{
       3:              Html.RenderPartial("Footer", Model.FooterData);
       4:          }
       5:      </div>
       6:  </body>
       7:  </html>

    7. 运行,打开Index View

    关于实验22

     Html.Partial的作用是什么?与Html.RenderPartial区别是什么?

    与Html.RenderPartial作用相同,Html.Partial会在View 中用来显示分部View。

    Html.RenderPartial会将分部View的结果直接写入HTTP 响应流中,而 Html.Partial会返回 MvcHtmlString值。

    什么是MvcHtmlString,为什么 Html.Partial返回的是MvcHtmlString 而不是字符串?

    根据MSDN规定,”MvcHtmlString”代表了一个 HTML编码的字符串,不需要二次编码。代码如下:

       1:  @{
       2:     string MyString = "My Simple String";
       3:  }
       4:  @MyString

    以上代码会转换为:

    Razor显示了全部的内容,许多人会认为已经看到加粗的字符串,是Razor Html在显示内容之前将内容编码,这就是为什么使用纯内容来代替粗体。

    当不适用razor编码时,使用 MvcHtmlString,MvcHtmlString是razor的一种表示,即“字符串已经编码完毕,不需要其他编码”。

    如:

       1:  @{
       2:     string MyString = "My Simple String";
       3:  }
       4:  @MvcHtmlString.Create(MyString)

    输出:

    Html.RenderAction 和 Html.Action两者之间有什么不同?更推荐使用哪种方法?

    Html.RenderAction会将Action 方法的执行结果直接写入HTTP 响应请求流中,而 Html.Action会返回MVC HTML 字符串。更推荐使用Html.RenderAction,因为它更快。当我们想在显示前修改action执行的结果时,推荐使用Html.Action。

    实验23——实现用户角色管理

    在实验23中我们将实现管理员和非管理员登录的功能。需求很简单:非管理员用户没有创建新Employee的权限。实验23会帮助大家理解MVC提供的Session 和Action过滤器。

    因此我们将实验23分为两部分:

    第一部分:非管理员用户登录时,隐藏 Add New 链接

    1. 创建标识用户身份的枚举类型

    右击Model 文件夹,选择添加新项目。选择“Code File”选项。

    输入“UserStatus”名,点击添加。

    “Code File”选项会创建一个“.cs”文件.

    创UserStatus枚举类型,如下:

       1:  namespace WebApplication1.Models
       2:  {
       3:      public enum UserStatus
       4:      {
       5:          AuthenticatedAdmin,
       6:          AuthentucatedUser,
       7:          NonAuthenticatedUser
       8:      }
       9:  }

     2. 修改业务层功能

    删除  IsValidUser函数,创建新函数“GetUserValidity“,如下:

       1:  public UserStatus GetUserValidity(UserDetails u)
       2:  {
       3:      if (u.UserName == "Admin" && u.Password == "Admin")
       4:      {
       5:          return UserStatus.AuthenticatedAdmin;
       6:      }
       7:      else if (u.UserName == "Sukesh" && u.Password == "Sukesh")
       8:      {
       9:          return UserStatus.AuthentucatedUser;
      10:      }
      11:      else
      12:      {
      13:          return UserStatus.NonAuthenticatedUser;
      14:      }
      15:  }

    3. 修改DoLogin action方法

    打开 AuthenticationController, 修改DoLogin action:

       1:  [HttpPost]
       2:  public ActionResult DoLogin(UserDetails u)
       3:  {
       4:      if (ModelState.IsValid)
       5:      {
       6:          EmployeeBusinessLayer bal = new EmployeeBusinessLayer();
       7:          //New Code Start
       8:          UserStatus status = bal.GetUserValidity(u);
       9:          bool IsAdmin = false;
      10:          if (status==UserStatus.AuthenticatedAdmin)
      11:          {
      12:              IsAdmin = true;
      13:          }
      14:          else if (status == UserStatus.AuthentucatedUser)
      15:          {
      16:              IsAdmin = false;
      17:          }
      18:          else
      19:          {
      20:              ModelState.AddModelError("CredentialError", "Invalid Username or Password");
      21:              return View("Login");
      22:          }
      23:          FormsAuthentication.SetAuthCookie(u.UserName, false);
      24:          Session["IsAdmin"] = IsAdmin;
      25:          return RedirectToAction("Index", "Employee");
      26:          //New Code End
      27:      }
      28:      else
      29:      {
      30:          return View("Login");
      31:      }
      32:  }

    在上述代码中,已经出现Session 变量来识别用户身份。

    什么是Session?

    Session是Asp.Net的特性之一,可以在MVC中重用,可用于暂存用户相关数据,session变量周期是穿插于整个用户生命周期的。

    4. 移除存在的 AddNew 链接

    打开“~/Views/Employee”文件夹下 Index.cshtml View,移除”Add New“超链接。

    <!-- Remove following line from Index.cshtml -->
    
    <a  href="/Employee/AddNew">Add New</a>

    5. 创建分部View

    右击“~/Views/Employee”文件夹,选择添加View,设置View名称”“AddNewLink”“,选中”Create a partial View“复选框。

    6. 输入分部View的内容

    在新创建的分部视图中输入以下内容:

    <a  href="/Employee/AddNew">Add New</a>

    7.  新建 Action 方法

    打开 EmployeeController,新建Action 方法”GetAddNewLink“,如下:

       1:  public ActionResult GetAddNewLink()
       2:  {
       3:      if (Convert.ToBoolean(Session["IsAdmin"]))
       4:      {
       5:          return Partial View("AddNewLink");
       6:      }
       7:      else
       8:      {
       9:          return new EmptyResult();
      10:      }
      11:  }

    8.  显示  AddNew 链接

    打开 Index.html,输入以下代码:

       1:  <a href="/Authentication/Logout">Logout</a>
       2:  </div>
       3:  <hr />
       4:  @{
       5:    Html.RenderAction("GetAddNewLink");
       6:  }
       7:  <div>
       8:  <table border="1">
       9:  <tr>

    Html.RenderAction 执行Action 方法,并将结果直接写入响应流中。

    9. 运行

    测试1

    测试2

    第二部分: 直接URL 安全

    以上实验实现了非管理员用户无法导航到AddNew链接。这样还不够,如果非管理员用户直接输入AddNew URL,则会直接跳转到此页面。

    非管理员用户还是可以直接访问AddNew方法,为了解决这个问题,我们会引入MVC action 过滤器。Action 过滤器使得在action方法中添加一些预处理和后处理的逻辑判断问题。在整个实验中,会注重ActionFilters预处理的支持和后处理的功能。

    1. 安装过滤器

    新建文件夹Filters,新建类”AdminFilter“。

    2. 创建过滤器

    通过继承 ActionFilterAttribute ,将 AdminFilter类升级为”ActionFilter“,如下:

       1:  public class AdminFilter:ActionFilterAttribute
       2:  {
       3:   
       4:  }

    注意:使用”ActionFilterAttribute “需要在文件顶部输入”System.Web.Mvc“。

    3. 添加安全验证逻辑

    在ActionFliter中重写 OnActionExecuting方法:

       1:  public override void OnActionExecuting(ActionExecutingContext filterContext)
       2:  {
       3:      if (!Convert.ToBoolean(filterContext.HttpContext.Session["IsAdmin"]))
       4:      {
       5:          filterContext.Result = new ContentResult()
       6:          {
       7:              Content="Unauthorized to access specified resource."
       8:          };
       9:      }
      10:  }

    4. 绑定过滤器

    在AddNew和 SaveEmployee方法中绑定过滤器,如下:

       1:  [AdminFilter]
       2:  public ActionResult AddNew()
       3:  {
       4:      return View("CreateEmployee",new Employee());
       5:  }
       6:  ...
       7:  ...
       8:  [AdminFilter]
       9:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
      10:  {
      11:      switch (BtnSubmit)
      12:      {
      13:          case "Save Employee":
      14:              if (ModelState.IsValid)
      15:              {
      16:                  EmployeeBusinessLayer empBal = new EmployeeBusinessLayer();
      17:  ....
      18:  ....

    5. 运行

    关于实验23

    可以通过浏览器直接调用GetAddNewLink方法吗?

     可以直接调用,也可直接停止”GetAddNewLink“的运行。

    Html.Action有什么作用?

    与Html.RenderAction作用相同,Html.Action会执行action 方法,并在View中显示结果。

    语法:

       1:  @Html.Action("GetAddNewLink");

    Html.RenderAction 和 Html.Action两者之间有什么不同?更推荐使用哪种方法?

    Html.RenderAction会将Action 方法的执行结果直接写入HTTP 响应请求流中,而 Html.Action会返回MVCHTMLString。更推荐使用Html.RenderAction,因为它更快。当我们想在显示前修改action执行的结果时,推荐使用Html.Action。

    什么是 ActionFilter ?

    与AuthorizationFilter类似,ActionFilter是ASP.NET MVC过滤器中的一种,允许在action 方法中添加预处理和后处理逻辑。

    实验24——实现项目外观的一致性

    在ASP.NET能够保证外观一致性的是母版页的使用。MVC却不同于ASP.NET,在RAZOR中,母版页称为布局页面。

    在开始实验之前,首先来了解布局页面

    1. 带有欢迎消息的页眉

    2. 带有数据的页脚

    最大的问题是什么?

    带有数据的页脚和页眉作为ViewModel的一部分传从Controller传给View。

    现在最大的问题是在页眉和页脚移动到布局页面后,如何将数据从View传给Layout页面。

    解决方案——继承

    可使用继承原则,通过实验来深入理解。

    1. 创建ViewModel基类

    在ViewModel 文件夹下新建ViewModel 类 ”BaseViewModel“,如下:

       1:  public class BaseViewModel
       2:  {
       3:      public string UserName { get; set; }
       4:      public FooterViewModel FooterData { get; set; }//New Property
       5:  }
     

    BaseViewModel可封装布局页所需要的所有值。

    2. 准备 EmployeeListViewModel

    删除EmployeeListViewModel类的 UserName和 FooterData属性,并继承 BaseViewModel:

       1:  public class EmployeeListViewModel:BaseViewModel
       2:  {
       3:      public List<EmployeeViewModel> Employees { get; set; }
       4:  }

    3.  创建布局页面

    右击shared文件夹,选择添加>>MVC5 Layout Page。输入名称”MyLayout“,点击确认

       1:  <!DOCTYPE html>
       2:   
       3:  <html>
       4:  <head>
       5:      <meta name="viewport" content="width=device-width" />
       6:      <title>@ViewBag.Title</title>
       7:  </head>
       8:  <body>
       9:      <div>
      10:          @RenderBody()
      11:      </div>
      12:  </body>
      13:  </html>

    4. 将布局转换为强类型布局

       1:  @using WebApplication1.ViewModels
       2:  @model BaseViewModel

    5. 设计布局页面

    在布局页面添加页眉,页脚和内容,内容,三部分,如下:

       1:  <html>
       2:  <head>
       3:      <meta name="viewport" content="width=device-width" />
       4:      <title>@RenderSection("TitleSection")</title>
       5:      @RenderSection("HeaderSection",false)
       6:  </head>
       7:  <body>
       8:      <div style="text-align:right">
       9:          Hello, @Model.UserName
      10:          <a href="/Authentication/Logout">Logout</a>
      11:      </div>
      12:      <hr />
      13:      <div>
      14:      @RenderSection("ContentBody")
      15:      </div>
      16:      @Html.Partial("Footer",Model.FooterData)
      17:  </body>
      18:  </html>

    如上所示,布局页面包含三部分,TitleSection, HeaderSection 和 ContentBody,内容页面将使用这些部分来定义合适的内容。

    6. 在 Index View中绑定布局页面

    打开Index.cshtml,在文件顶部会发现以下代码:

       1:  @{
       2:      Layout = null;
       3:  }

    修改:

       1:  @{
       2:      Layout = "~/Views/Shared/MyLayout.cshtml";
       3:  }

    7.设计Index View

    • 从Index View中去除页眉和页脚
    • 在Body标签中复制保留的内容,并存放在某个地方。
    • 复制Title标签中的内容
    • 移除View中所有的HTML 内容,确保只移动了HTML,@model 且没有移动layout语句
    • 在复制的内容中定义TitleSection和 Contentbody

    完整的View代码如下:

       1:  @using WebApplication1.ViewModels
       2:  @model EmployeeListViewModel
       3:  @{
       4:      Layout = "~/Views/Shared/MyLayout.cshtml";
       5:  }
       6:   
       7:  @section TitleSection{
       8:      MyView
       9:  }
      10:  @section ContentBody{       
      11:      <div>        
      12:          @{
      13:              Html.RenderAction("GetAddNewLink");
      14:          }
      15:          <table border="1">
      16:              <tr>
      17:                  <th>Employee Name</th>
      18:                  <th>Salary</th>
      19:              </tr>
      20:              @foreach (EmployeeViewModel item in Model.Employees)
      21:              {
      22:                  <tr>
      23:                      <td>@item.EmployeeName</td>
      24:                      <td style="background-color:@item.SalaryColor">@item.Salary</td>
      25:                  </tr>
      26:              }
      27:          </table>
      28:      </div>
      29:  }

    8. 运行

    9. 在 CreateEmployee 中绑定布局页面

    打开 Index.cshtml,修改顶部代码:

       1:  @{
       2:      Layout = "~/Views/Shared/MyLayout.cshtml";
       3:  }

    10. 设计 CreateEmployee  View

    与第7步中的程序类似,定义 CreateEmployee View中的Section ,在本次定义中只添加一项,如下:

       1:  @using WebApplication1.Models
       2:  @model Employee
       3:  @{
       4:      Layout = "~/Views/Shared/MyLayout.cshtml";
       5:  }
       6:   
       7:  @section TitleSection{
       8:      CreateEmployee
       9:  }
      10:   
      11:  @section HeaderSection{
      12:  <script src="~/Scripts/Validations.js"></script>
      13:  <script>
      14:      function ResetForm() {
      15:          document.getElementById('TxtFName').value = "";
      16:          document.getElementById('TxtLName').value = "";
      17:          document.getElementById('TxtSalary').value = "";
      18:      }
      19:  </script>
      20:  }
      21:  @section ContentBody{ 
      22:      <div>
      23:          <form action="/Employee/SaveEmployee" method="post" id="EmployeeForm">
      24:              <table>
      25:              <tr>
      26:                  <td>
      27:                      First Name:
      28:                  </td>
      29:                  <td>
      30:                      <input type="text" id="TxtFName" name="FirstName" value="@Model.FirstName" />
      31:                  </td>
      32:              </tr>
      33:              <tr>
      34:                  <td colspan="2" align="right">
      35:                      @Html.ValidationMessage("FirstName")
      36:                  </td>
      37:              </tr>
      38:              <tr>
      39:                  <td>
      40:                      Last Name:
      41:                  </td>
      42:                  <td>
      43:                      <input type="text" id="TxtLName" name="LastName" value="@Model.LastName" />
      44:                  </td>
      45:              </tr>
      46:              <tr>
      47:                  <td colspan="2" align="right">
      48:                      @Html.ValidationMessage("LastName")
      49:                  </td>
      50:              </tr>
      51:   
      52:              <tr>
      53:                  <td>
      54:                      Salary:
      55:                  </td>
      56:                  <td>
      57:                      <input type="text" id="TxtSalary" name="Salary" value="@Model.Salary" />
      58:                  </td>
      59:              </tr>
      60:              <tr>
      61:                  <td colspan="2" align="right">
      62:                      @Html.ValidationMessage("Salary")
      63:                  </td>
      64:              </tr>
      65:   
      66:              <tr>
      67:                  <td colspan="2">
      68:   
      69:                      <input type="submit" name="BtnSubmit" value="Save Employee" onclick="return IsValid();" />
      70:                      <input type="submit" name="BtnSubmit" value="Cancel" />
      71:                      <input type="button" name="BtnReset" value="Reset" onclick="ResetForm();" />
      72:                  </td>
      73:              </tr>
      74:              </table>
      75:      </div>
      76:  }

    11. 运行

    Index View是  EmployeeListViewModel类型的强View类型,是 BaseViewModel的子类,这就是为什么Index View可一直发挥作用。CreateEmployee View 是CreateEmployeeViewModel的强类型,并不是BaseViewModel的子类,因此会出现以上错误。

    12. 准备 CreateEmployeeViewModel

    使CreateEmployeeViewModel 继承 BaseViewModel,如下:

       1:  public class CreateEmployeeViewModel:BaseViewModel
       2:  {
       3:  ...

    13. 运行

    报错,该错误好像与步骤11中的错误完全不同,出现这些错误的根本原因是未初始化AddNew action方法中的Header和Footer数据。

    14. 初始化Header和Footer 数据

    修改AddNew方法:

       1:  public ActionResult AddNew()
       2:  {
       3:      CreateEmployeeViewModel employeeListViewModel = new CreateEmployeeViewModel();
       4:      employeeListViewModel.FooterData = new FooterViewModel();
       5:      employeeListViewModel.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value
       6:      employeeListViewModel.FooterData.Year = DateTime.Now.Year.ToString();
       7:      employeeListViewModel.UserName = User.Identity.Name; //New Line
       8:      return View("CreateEmployee", employeeListViewModel);
       9:  }

    15. 初始化 SaveEmployee中的Header和 FooterData

       1:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
       2:  {
       3:      switch (BtnSubmit)
       4:      {
       5:          case "Save Employee":
       6:              if (ModelState.IsValid)
       7:              {
       8:                  ...
       9:              }
      10:              else
      11:              {
      12:                  CreateEmployeeViewModel vm = new CreateEmployeeViewModel();
      13:                  ...
      14:                  vm.FooterData = new FooterViewModel();
      15:                  vm.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value
      16:                  vm.FooterData.Year = DateTime.Now.Year.ToString();
      17:                  vm.UserName = User.Identity.Name; //New Line
      18:                  return View("CreateEmployee", vm); // Day 4 Change - Passing e here
      19:              }
      20:          case "Cancel":
      21:              return RedirectToAction("Index");
      22:      }
      23:      return new EmptyResult();
      24:  }

    16. 运行

    关于实验24

    RenderBody 有什么作用?

    之前创建了Layout 页面,包含一个Razor语句如:

       1:  @Html.RenderBody()

    首先我们先来了RenderBody是用来做什么的?

    在内容页面,通常会定义Section,声明Layout页面。但是奇怪的是,Razor允许定义在Section外部定义一些内容。所有的非section内容会使用RenderBody函数来渲染,下图能够更好的理解:

    布局是否可嵌套?

    可以嵌套,创建Layout页面,可使用其他存在的Layout页面,语法相同。

    是否需要为每个View定义Layout页面?

    会在View文件夹下发现特殊的文件“__ViewStart.cshtml”,在其内部的设置会应用所有的View。

    例如:在__ViewStart.cshtml中输入以下代码,并给所有View 设置 Layout页面。

       1:  @{
       2:      Layout = "~/Views/Shared/_Layout.cshtml";
       3:  }

    是否在每个Action 方法中需要加入Header和Footer数据代码?

    不需要,可在Action 过滤器的帮助下删除重复的代码。

    是否强制定义了所有子View中的Section?

    是的,如果Section定义为需要的section,默认的值会设置为true。如下

       1:  @RenderSection("HeaderSection",false) // Not required
       2:  @RenderSection("HeaderSection",true) // required
       3:  @RenderSection("HeaderSection") // required

    实验25——使用Action Fliter让Header和Footer数据更有效

    在实验23中,我们已经知道了使用 ActionFilter的一个优点,现在来看看使用 ActionFilter的其他好处

    1. 删除Action 方法中的冗余代码

    删除Index,AddNew, SaveEmployee方法中的Header和Footer数据代码。

    Header代码如:

       1:  bvm.UserName = HttpContext.Current.User.Identity.Name;

    Footer代码如:

       1:  bvm.FooterData = new FooterViewModel();
       2:  bvm.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value
       3:  bvm.FooterData.Year = DateTime.Now.Year.ToString();

    2.创建HeaderFooter 过滤器

    在Filter文件夹下新建类”HeaderFooterFilter“,并通过继承ActionFilterAttribute类升级为Action Filter

    3. 升级ViewModel

    重写 HeaderFooterFilter类的 OnActionExecuted方法,在该方法中获取当前View Model ,并绑定Header和Footer数据。

       1:  public class HeaderFooterFilter : ActionFilterAttribute
       2:  {
       3:      public override void OnActionExecuted(ActionExecutedContext filterContext)
       4:      {
       5:          ViewResult v = filterContext.Result as ViewResult;
       6:          if(v!=null) // v will null when v is not a ViewResult
       7:          {
       8:                  BaseViewModel bvm = v.Model as BaseViewModel;
       9:                  if(bvm!=null)//bvm will be null when we want a view without Header and footer
      10:                  {
      11:                          bvm.UserName = HttpContext.Current.User.Identity.Name;
      12:                          bvm.FooterData = new FooterViewModel();
      13:                          bvm.FooterData.CompanyName = "StepByStepSchools";//Can be set to dynamic value
      14:                          bvm.FooterData.Year = DateTime.Now.Year.ToString();            
      15:                  }
      16:          }
      17:      }
      18:  }

    4. 绑定过滤器

    在Index中,AddNew,SaveEmployee的action 方法中绑定 HeaderFooterFilter

       1:  [HeaderFooterFilter]
       2:  public ActionResult Index()
       3:  {
       4:      EmployeeListViewModel employeeListViewModel = new EmployeeListViewModel();
       5:  ...
       6:  }
       7:  ...
       8:  [AdminFilter]
       9:  [HeaderFooterFilter]
      10:  public ActionResult AddNew()
      11:  {
      12:      CreateEmployeeViewModel employeeListViewModel = new CreateEmployeeViewModel();
      13:      //employeeListViewModel.FooterData = new FooterViewModel();
      14:      //employeeListViewModel.FooterData.CompanyName = "StepByStepSchools";
      15:  ...
      16:  }
      17:  ...
      18:  [AdminFilter]
      19:  [HeaderFooterFilter]
      20:  public ActionResult SaveEmployee(Employee e, string BtnSubmit)
      21:  {
      22:      switch (BtnSubmit)
      23:      {
      24:          ...

    5. 运行

    总结

    本文主要介绍了ASP.NET MVC中页眉页脚的添加和Layout页面的使用,并实现了用户角色分配及Action Filter的使用,下一节中我们将是最难和最有趣的一篇,请持续关注吧!

    在学习了本节Layout页面及用户角色管理之后,你是否也跃跃欲试想要进行MVC开发?不妨试试 ComponentOne Studio ASP.NET MVC 这款轻量级控件,它与Visual Studio无缝集成,完全与MVC6和ASP.NET 5.0兼容,将大幅提高工作效率.

    原文链接:http://www.codeproject.com/Articles/1000435/Learn-MVC-Project-in-days-Day

  • 相关阅读:
    pythone 请求响应字典
    python strip()
    python,datetime
    How Flask Routing Works
    python __file__ 与argv[0]
    Python的zip函数
    Python中的__new__()方法与实例化
    python,dict的setdefault方法
    python yield
    python with用法
  • 原文地址:https://www.cnblogs.com/ywsoftware/p/9082715.html
Copyright © 2020-2023  润新知