ASP.NET MVC 是微软官方提供的以MVC模式为基础的ASP.NET Web应用程序(Web Application)框架,它由Castle的MonoRail而来。

MVC 编程模式

       MVC 是三种 ASP.NET 编程模式中的一种。

       MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式。

    (1)Model(模型)表示应用程序核心(比如数据库记录列表)。

    (2)View(视图)显示数据(数据库记录)。

    (3)Controller(控制器)处理输入(写入数据库记录)。

       MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。       

       新建一个ASP.NET MVC4应用程序,结构如下图所示:


对各个文件夹的说明:

(1)App_Data 文件夹用于存储应用程序数据。   

(2)Content 文件夹用于存放静态文件,比如样式表(CSS 文件)、图标和图像。 

(3)Controllers 文件夹包含负责处理用户输入和相应的控制器类。

(4)Models 文件夹包含表示应用程序模型的类。模型控制并操作应用程序的数据。

(5)Views 文件夹用于存储与应用程序的显示相关的 HTML 文件(用户界面)。

(6)Scripts 文件夹存储应用程序的 JavaScript 文件。

 下面就主要的Controller、Model和View做出说明。

一、控制器

1、描述

       控制器(Controller)主要负责响应用户的输入,并在响应时修改模型(Model)。通过这种方式,控制器主要关注的是应用程序流、输入数据的处理,以及对相关视图(View)输出数据的提供。

2、简单控制器

       新建一个ASP.NET MVC4应用程序,会自动生成一个HomeController和AccountController。

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

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
            return View();
        }
    }
}

  

      直接按F5运行程序即可看到index试图中的内容,此时浏览器的URL为:

       http://localhost:4573,或者修改浏览器地址为:

       http://localhost:4573/home

       http://localhost:4573/home/index

       程序默认会托管在VS2013自带的IIS中,采用的端口号为4573。如果程序托管在MyWeb.com中,则URL应为:

       http://MyWeb.com/home/index。

3、控制器操作中的参数

       前面的例子Action中返回的是字符串常量,下面就让它们通过相应URL传进来的参数动态地执行操作。

       在这里,我们使用HttpUtility.HtmlEncode来预处理用户输入。这样就能阻止用户用链接向视图中注入JavaScriptd代码或HTML标记,比如/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。


 
public string SayHello(string content)
{
    string message = HttpUtility.HtmlEncode("Hello " + content);
    return message;
}

 

  1.  
  2. public string Details(int Id)
    {
        return "ID:" + Id;
    }

     

4、路由---将URL映射到动作

       框架是如何知道将URL映射到一个特定的控制动作的?答案就在Global.asax文件的RegisterRoutes方法中。该方法定义了将一个URL模式映射到控制器或动作的路由。

using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace MvcApplication1
{
    // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
    // 请访问 http://go.microsoft.com/?LinkId=9394801
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }
    }
}

 

  1. 在RegisterRoutes方法上按F12,转到该方法的定义,如下:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;  
 
namespace MvcApplication1
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                                name: "Default",
                                url: "{controller}/{action}/{id}",
                                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                            );
        }
    }
}

   

5、控制器总结

(1)不需要做任何配置,只需浏览到/控制器/动作URL即可;

(2)控制器是一个非常简单的类,继承自System.Web.Mvc.Controller类;

(3)用控制器在浏览器中显示文本,没有用到View或Model。

二、视图

1、作用

       提供用户界面。一个控制器可以对应多个试图,一个视图可以被多个控制器使用。

       在Action名上右键→添加试图→View1。

2、指定视图

@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>View1</title>
</head>
<body>
    <div>
        <h2>@ViewBag.Message</h2>
    </div>
</body>
</html>

3、ViewData和ViewBag的区别于联系

       在前面的例子中,使用了ViewBag的Message属性从控制器往视图传递数据,ViewData是一个特殊的字典类,可以按标准语法进行使用:ViewData["CurrentTime"]=DateTime.Now;

       这种语法也可以用动态封装器ViewBag:ViewBag.CurrentTime=DateTime.Now;

注意:

(1)尽管只有当要访问的关键字是有效的C#标识符是,ViewBag才起作用,如在ViewData["Key With Spaces"]就不能使用ViewBag访问,编译不通过;

(2)动态值不能作为一个参数传递给扩展方法。因为C#编译器为了选择正确的扩展方法,在编译是必须知道每个参数真正类型。如:@Html.TextBox("name",ViewBag.Name)不会编译通过,可以改为:

       ①@Html.TextBox("name",ViewData["Name"])

       ②@Html.TextBox("name",(string)ViewBag.Name)

4、强类型视图

       现在需要编写一个显示Album实例列表的视图。一简单的方法就是通过ViewBag属性把那些Album实例添加到视图数据字典中,然后在视图中迭代他们。

(1)首先,在Models文件夹下新建一个Album类,为了简单起见,只定义一个Title属性。

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

namespace MvcApplication1.Models
{
    public class Album
    {
        public string Title { get; set; }
    }
}
  1. (2)控制器
public ActionResult List()
{
    var album = new List<Album>();
    for (int i = 0; i < 10; i++)
    {
        album.Add(new Album { Title = "Product " + i.ToString() });
    }
    //一、使用ViewBag传值
    //ViewBag.Album = album;
    //return View("ListView");
    //二、使用ViewData传值
    ViewData["Album"] = album;
    return View("ListView");
}

  

(3)视图

       在List上右键→添加视图。

@{
    Layout = null;
}
<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @*一、使用ViewBag传值*@
            @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable
            <MvcApplication1.Models.Album>))
            {
                <li>@a.Title</li>
            }*@
            @*二、使用ViewBag传值*@

            @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>))
            {
                <li>@a.Title</li>
            }

        </ul>
        <pre name="code" class="html">
        <ul>
            @foreach(dynamic d in ViewBag.Album)
            {
                <li>@d.Title</li>
            }
 
        </ul>
    </div>
</body>
</html>

运行效果:


       注意,在枚举之前需要动态的将ViewBag.Album转换为IEnumerable<Album>类型,为了使代码干净整洁,也可以使用dynamic关键字。
<ul>
    @foreach (dynamic d in ViewBag.Album)
    {
        <li>@d.Title</li>
    }
</ul> 

       请记住,ViewData是ViewDataDictionary类型的,它有一个额外的Model属性,可以用来在视图中获取指定的模型对象。由于在ViewData中只能传递一个模型对象,因此,我们利用这一点可以很容易的实现向视图传递一个特定的类对象。

       在Controller方法中,可以通过重载的List方法中传递模型实例来指定模型,代码如下:

public ActionResult List()
{
    var album = new List<Album>();
    for (int i=0;i < 10; i++) 
    {
        album.Add(new Album { Title="Product " + i.ToString() });
    }
    ViewData["Album"]=album;
    return View("ListView",album);
}

@model IEnumerable<MvcApplication1.Models.Album>

@{
    Layout = null;
}

<!DOCTYPE html>
<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @foreach(dynamic d in Model)
            {
                <li>@d.Title</li>
            }
        </ul>
    </div>
</body>
</html>

       如果不想输入模型类型的完全限定类型名,可使用using关键字声明,如下所示:

 

@using MvcApplication1.Models

@model IEnumerable<Album>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @foreach (dynamic d in Model)
            {
                <li>@d.Title</li>
            }
        </ul>
    </div>
</body>
</html>

       对于在视图中经常使用的名称空间,一个较好的方法就是在Views目录下的web.config文件中声明。

 

<system.web.webPages.razor>
    <host factoryType = "System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    < pages pageBaseType="System.Web.Mvc.WebViewPage">
        <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Optimization"/>
        <add namespace="System.Web.Routing" />
        <add namespace="MvcApplication1.Models"/>
        </namespaces>
    </pages>
</system.web.webPages.razor>
 

5、Razor视图引擎

5.1 先来看一个简单的例子。

@{
    Layout = null;
}

@{
    var items = new string[] { "one", "two", "three" };
}

<!DOCTYPE html>
<html>
<head>
    <title>ListView</title>
</head>

<body>
    <div>
        <ul>
            @foreach (var item in items)
            {
                <li>@item</li>
            }
        </ul>
    </div>
</body>
</html>

 

5.2 Html编码

       因为在很多情况下需要用视图显示用户输入,如博客评论等,所以总是存在着潜在的跨站脚本注入攻击(也成XSS),值得称赞的是,Razor表达式是Html自动编码的,如下不会弹出一个警示框,而是直接显示html代码。

 

@{
    string message = "<script>alert('haacked!');</script>";
}

 

        然而,如果想要展示Html标签,就要返回一个System.Web.IHtml对象的实例,Razor并不对它进行编码。当然也可以创建一个HtmlStringl实例或者使用Html.Raw便捷方法。

 

@{

    string message = "<script>alert('haacked!');</script>";

}
<span>@Html.Raw(message)</span>

  

  1. 效果:

 

 

       虽然这种自动的HTML编码通过对一HTML形式显示的用户输入进行编码能有效的缓和XSS的脆弱性,但是对于在JavaScript中时远远不够的。例如:

 

<script type="text/javascript">
    $(function ()
    {
        var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)';
        $("#message").html(message).show('slow');

    });
</script>

 

  1.        当在JavaScript中将用户提供的值赋给变量时,要使用JavaScript字符串编码而不仅仅是HTML编码,记住这一点是很重要的,也就是要用@Ajax.JavaScriptStringEncode方法对用户输入进行编码。

5.3 布局

       Razor的布局有助于使用应用程序中的多个视图保持一致的外观,可使用布局为网站定义公共模板(或只是其中的一部分),公共模板包含一个或多个占位符,应用程序中的其他视图为他们提供内容。

       下面看一个非常简单的布局,新建一个名称为MyLayout.cshtml的视图,由于要作为公共模板,所以将其放在/Views/Shared/路径下。

 

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>
<body>
    <h1>@ViewBag.Title</h1>
    <div id="Container">@RenderBody()</div>
</body>
</html>

 

 

 

  1.        其中的@RenderBody()称为占位符,用来标记使用这个模板的视图将渲染他们的主要内容的位置。

 

       接下来新建一个视图,将使用其作为模板。

 

@{
    Layout = "~/Views/Shared/MyLayout.cshtml";
    ViewBag.Title = "GoodLuck";
}
<p>This is the main content</p>

 

 

 

 

  1. 运行效果如下:

       布局可能有多个节,例如下面示例在前面的布局基础上添加了一个页脚节:

 

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>
<body>
    <h1>@ViewBag.Title</h1>
    <div id="Container">@RenderBody()</div>
    <footer>@RenderSection("Footer")</footer>
</body>
</html>

 

 

 

 

  1.        在不做任何改变的情况下再次运行前面的视图,将会抛出一个异常,提示没有定义的Footer节。

 

       默认情况下,视图必须为布局中定义的没一个节提供相应的内容。更新后的View1视图如下所示:

 

@{
    Layout = "~/Views/Shared/MyLayout.cshtml";
    ViewBag.Title = "GoodLuck";
}

<p>This is the main content</p>

@section Footer{
    This is the <strong>footer</strong>.
}

 

 

 

  1.  

       RenderSection方法有一个重载的版本,允许在布局中指定不需要的节,可以给required参数传递一个false值来标记Footer节是可选的:

 

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>

<body>
    <h1>@ViewBag.Title</h1>
    <div id="Container">@RenderBody()</div>
    <footer>@RenderSection("Footer", required: false)</footer>
</body>
</html>

 

 

 

 



5.4 ViewStart

       在前面的例子中,每一个视图都是用Layout属性来指定它的布局,如果多个视图使用同一个布局,就会产生冗余,并且很难维护。

       _ViewStart.cshtml页面可用来消除这种冗余,这个文件的代码先于同目录下任何视图代码的执行,这个文件也可以递归地应用到子目录下的任何视图。

@{

Layout="~/Views/Shared/_Layout.cshtml";

}

       因为这个代码先于任何视图执行,所以一个视图可以重写Layout属性的默认值,从而重新选择一个不同的布局。

5.4 指定部分视图

       除了返回视图之外,操作方法也可以通过PartialView方法以PartialResult的形式返回部分视图。

The end

ASP.NET MVC 是微软官方提供的以MVC模式为基础的ASP.NET Web应用程序(Web Application)框架,它由Castle的MonoRail而来。

MVC 编程模式

       MVC 是三种 ASP.NET 编程模式中的一种。

       MVC 是一种使用 MVC(Model View Controller 模型-视图-控制器)设计创建 Web 应用程序的模式。

    (1)Model(模型)表示应用程序核心(比如数据库记录列表)。

    (2)View(视图)显示数据(数据库记录)。

    (3)Controller(控制器)处理输入(写入数据库记录)。

       MVC 模式同时提供了对 HTML、CSS 和 JavaScript 的完全控制。Model(模型)是应用程序中用于处理应用程序数据逻辑的部分。通常模型对象负责在数据库中存取数据。View(视图)是应用程序中处理数据显示的部分。通常视图是依据模型数据创建的。Controller(控制器)是应用程序中处理用户交互的部分。通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。       

       新建一个ASP.NET MVC4应用程序,结构如下图所示:


对各个文件夹的说明:

(1)App_Data 文件夹用于存储应用程序数据。   

(2)Content 文件夹用于存放静态文件,比如样式表(CSS 文件)、图标和图像。 

(3)Controllers 文件夹包含负责处理用户输入和相应的控制器类。

(4)Models 文件夹包含表示应用程序模型的类。模型控制并操作应用程序的数据。

(5)Views 文件夹用于存储与应用程序的显示相关的 HTML 文件(用户界面)。

(6)Scripts 文件夹存储应用程序的 JavaScript 文件。

 下面就主要的Controller、Model和View做出说明。

一、控制器

1、描述

       控制器(Controller)主要负责响应用户的输入,并在响应时修改模型(Model)。通过这种方式,控制器主要关注的是应用程序流、输入数据的处理,以及对相关视图(View)输出数据的提供。

2、简单控制器

       新建一个ASP.NET MVC4应用程序,会自动生成一个HomeController和AccountController。

 

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

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "Modify this template to jump-start your ASP.NET MVC application.";
            return View();
        }
    }
}

 



       直接按F5运行程序即可看到index试图中的内容,此时浏览器的URL为:

 

       http://localhost:4573,或者修改浏览器地址为:

       http://localhost:4573/home

       http://localhost:4573/home/index

       程序默认会托管在VS2013自带的IIS中,采用的端口号为4573。如果程序托管在MyWeb.com中,则URL应为:

       http://MyWeb.com/home/index。

3、控制器操作中的参数

       前面的例子Action中返回的是字符串常量,下面就让它们通过相应URL传进来的参数动态地执行操作。

       在这里,我们使用HttpUtility.HtmlEncode来预处理用户输入。这样就能阻止用户用链接向视图中注入JavaScriptd代码或HTML标记,比如/home/sayhello?content=<script>window.location='http://www.baidu.com'</script>。


 

public string SayHello(string content)
{
    string message = HttpUtility.HtmlEncode("Hello " + content);
    return message;
}

 

 

 



public string Details(int Id)
{
    return "ID:" + Id;
}

 


 

 

4、路由---将URL映射到动作

       框架是如何知道将URL映射到一个特定的控制动作的?答案就在Global.asax文件的RegisterRoutes方法中。该方法定义了将一个URL模式映射到控制器或动作的路由。

 

using System.Linq;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;

namespace MvcApplication1
{
    // 注意: 有关启用 IIS6 或 IIS7 经典模式的说明,
    // 请访问 http://go.microsoft.com/?LinkId=9394801
    public class MvcApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
        }
    }
}

 

 

 



在RegisterRoutes方法上按F12,转到该方法的定义,如下:

 

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

namespace MvcApplication1
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                                name: "Default",
                                url: "{controller}/{action}/{id}",
                                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                            );
        }
    }
}

 

 

 



5、控制器总结

 

(1)不需要做任何配置,只需浏览到/控制器/动作URL即可;

(2)控制器是一个非常简单的类,继承自System.Web.Mvc.Controller类;

(3)用控制器在浏览器中显示文本,没有用到View或Model。

二、视图

1、作用

       提供用户界面。一个控制器可以对应多个试图,一个视图可以被多个控制器使用。

       在Action名上右键→添加试图→View1。

2、指定视图

 

@{
     Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>View1</title>
</head>
<body>
    <div>
        <h2>@ViewBag.Message</h2>
    </div>
</body>
</html>

 

 

 



3、ViewData和ViewBag的区别于联系

       在前面的例子中,使用了ViewBag的Message属性从控制器往视图传递数据,ViewData是一个特殊的字典类,可以按标准语法进行使用:ViewData["CurrentTime"]=DateTime.Now;

       这种语法也可以用动态封装器ViewBag:ViewBag.CurrentTime=DateTime.Now;

注意:

(1)尽管只有当要访问的关键字是有效的C#标识符是,ViewBag才起作用,如在ViewData["Key With Spaces"]就不能使用ViewBag访问,编译不通过;

(2)动态值不能作为一个参数传递给扩展方法。因为C#编译器为了选择正确的扩展方法,在编译是必须知道每个参数真正类型。如:@Html.TextBox("name",ViewBag.Name)不会编译通过,可以改为:

       ①@Html.TextBox("name",ViewData["Name"])

       ②@Html.TextBox("name",(string)ViewBag.Name)

4、强类型视图

       现在需要编写一个显示Album实例列表的视图。一简单的方法就是通过ViewBag属性把那些Album实例添加到视图数据字典中,然后在视图中迭代他们。

(1)首先,在Models文件夹下新建一个Album类,为了简单起见,只定义一个Title属性。

 

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

namespace MvcApplication1.Models
{
    public class Album
    {
        public string Title { get; set; }
    }
}

 

 

 



(2)控制器

 

public ActionResult List()
{
    var album = new List<Album>();
    for (int i=0;i < 10 ;i++) 
    {
        album.Add(new Album { Title="Product " + i.ToString() });
    }

    //一、使用ViewBag传值
    //ViewBag.Album = album;
    //return View("ListView");

    //二、使用ViewData传值
    ViewData["Album"] = album;
    return View("ListView");
}

 

 

 



(3)视图

       在List上右键→添加视图。

 

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @*一、使用ViewBag传值*@
            @*@foreach(MvcApplication1.Models.Album a in (ViewBag.Album as IEnumerable<MvcApplication1.Models.Album>))
            {
                <li>@a.Title</li>
            }*@

            @*二、使用ViewBag传值*@
            @foreach (MvcApplication1.Models.Album a in (ViewData["Album"] as IEnumerable<MvcApplication1.Models.Album>))
            {
                <li>@a.Title</li>
            }
        </ul>

        <pre name="code" class="html">

        <ul>
            @foreach(dynamic d in ViewBag.Album)
            {
                <li>@d.Title</li>
            }
        </ul>
    </div>
</body>
</html>

 

 

 



运行效果:

 


       注意,在枚举之前需要动态的将ViewBag.Album转换为IEnumerable<Album>类型,为了使代码干净整洁,也可以使用dynamic关键字。
<ul>
    @foreach (dynamic d in ViewBag.Album)
    {
        <li>@d.Title</li>
    }
</ul>

 



       请记住,ViewData是ViewDataDictionary类型的,它有一个额外的Model属性,可以用来在视图中获取指定的模型对象。由于在ViewData中只能传递一个模型对象,因此,我们利用这一点可以很容易的实现向视图传递一个特定的类对象。

       在Controller方法中,可以通过重载的List方法中传递模型实例来指定模型,代码如下:

 

public ActionResult List()
{
    var album = new List<Album>();
    for (int i=0;i < 10;i++) 
    {
        album.Add(new Album { Title="Product " + i.ToString() });
    }
    ViewData["Album"]=album;
    return View("ListView",album);
}

@model IEnumerable<MvcApplication1.Models.Album>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @foreach(dynamic d in Model)
            {
                <li>@d.Title</li>
            }
        </ul>
    </div>
</body>
</html>

 

 

 



       如果不想输入模型类型的完全限定类型名,可使用using关键字声明,如下所示:

 

@using MvcApplication1.Models
@model IEnumerable<Album>

@{
    Layout = null;
}

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @foreach (dynamic d in Model)
            {
                <li>@d.Title</li>
            }
        </ul>
    </div>
</body>
</html>

 

 

 



       对于在视图中经常使用的名称空间,一个较好的方法就是在Views目录下的web.config文件中声明。

 

<system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="System.Web.Mvc.WebViewPage">
        <namespaces>
            <add namespace="System.Web.Mvc" />
            <add namespace="System.Web.Mvc.Ajax" />
            <add namespace="System.Web.Mvc.Html" />
            <add namespace="System.Web.Optimization" />
            <add namespace="System.Web.Routing" />
            <add namespace="MvcApplication1.Models" />
        </namespaces>
    </pages>
</system.web.webPages.razor>

 

 

 



5、Razor视图引擎

5.1 先来看一个简单的例子。

 

@{
    Layout = null;
}

@{
    var items = new string[] { "one", "two", "three" };
}
<!DOCTYPE html>

<html>
<head>
    <title>ListView</title>
</head>
<body>
    <div>
        <ul>
            @foreach (var item in items)
            {
                <li>@item</li>
            }
        </ul>
    </div>
</body>
</html>

 

 

 



5.2 Html编码

       因为在很多情况下需要用视图显示用户输入,如博客评论等,所以总是存在着潜在的跨站脚本注入攻击(也成XSS),值得称赞的是,Razor表达式是Html自动编码的,如下不会弹出一个警示框,而是直接显示html代码。

 

@{
    string message = "<script>alert('haacked!');</script>";
}

<span>@message</span>

 

 

 



       然而,如果想要展示Html标签,就要返回一个System.Web.IHtml对象的实例,Razor并不对它进行编码。当然也可以创建一个HtmlStringl实例或者使用Html.Raw便捷方法。

 

@{
    string message = "<script>alert('haacked!');</script>";
}

<span>@Html.Raw(message)</span>

 

 

 

  1. 效果:

 

 

       虽然这种自动的HTML编码通过对一HTML形式显示的用户输入进行编码能有效的缓和XSS的脆弱性,但是对于在JavaScript中时远远不够的。例如:

 

<script type="text/javascript">
    $(function() 
    {
        var message = 'Hello @Ajax.JavaScriptStringEncode(ViewBag.Message)';
        $("#message").html(message).show('slow');
    });
</script>

 

 

 

       当在JavaScript中将用户提供的值赋给变量时,要使用JavaScript字符串编码而不仅仅是HTML编码,记住这一点是很重要的,也就是要用@Ajax.JavaScriptStringEncode方法对用户输入进行编码。

5.3 布局

       Razor的布局有助于使用应用程序中的多个视图保持一致的外观,可使用布局为网站定义公共模板(或只是其中的一部分),公共模板包含一个或多个占位符,应用程序中的其他视图为他们提供内容。

       下面看一个非常简单的布局,新建一个名称为MyLayout.cshtml的视图,由于要作为公共模板,所以将其放在/Views/Shared/路径下。

 

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>
<body>
    <h1>@ViewBag.Title</h1>
    <div id="Container">@RenderBody()</div>
</body>
</html>

 

 

 

  1.        其中的@RenderBody()称为占位符,用来标记使用这个模板的视图将渲染他们的主要内容的位置。

 

       接下来新建一个视图,将使用其作为模板。

 

@{
    Layout = "~/Views/Shared/MyLayout.cshtml";
    ViewBag.Title = "GoodLuck";
}

<p>This is the main content</p>

 

 

 

运行效果如下:

       布局可能有多个节,例如下面示例在前面的布局基础上添加了一个页脚节:

 

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>

<body>
    <h1>@ViewBag.Title</h1>
    <div id="Container">@RenderBody()</div>
    <footer>@RenderSection("Footer")</footer>
</body>
</html>

 

 

 

 

  1.        在不做任何改变的情况下再次运行前面的视图,将会抛出一个异常,提示没有定义的Footer节。

 

       默认情况下,视图必须为布局中定义的没一个节提供相应的内容。更新后的View1视图如下所示:

 

@{
    Layout = "~/Views/Shared/MyLayout.cshtml";
    ViewBag.Title = "GoodLuck";
}

    <p>This is the main content</p>
    @section Footer{
    This is the <strong>footer</strong>
}

 

 

 

 

       RenderSection方法有一个重载的版本,允许在布局中指定不需要的节,可以给required参数传递一个false值来标记Footer节是可选的:

 

<!DOCTYPE html>
<html>
<head>
    <title>@ViewBag.Title</title>
</head>
<body>
    <h1>@ViewBag.Title</h1>
    <div id="Container">@RenderBody()</div>
    <footer>@RenderSection("Footer", required: false)</footer>

</body>
</html>

 

5.4 ViewStart

       在前面的例子中,每一个视图都是用Layout属性来指定它的布局,如果多个视图使用同一个布局,就会产生冗余,并且很难维护。

       _ViewStart.cshtml页面可用来消除这种冗余,这个文件的代码先于同目录下任何视图代码的执行,这个文件也可以递归地应用到子目录下的任何视图。

@{

Layout="~/Views/Shared/_Layout.cshtml";

}

       因为这个代码先于任何视图执行,所以一个视图可以重写Layout属性的默认值,从而重新选择一个不同的布局。

5.4 指定部分视图

       除了返回视图之外,操作方法也可以通过PartialView方法以PartialResult的形式返回部分视图。

The end