将视图添加到 MVC 应用程序

作者: 里克·安德森

注释

本教程的更新版本可在 此处 找到,并使用了最新版本的 Visual Studio。 新教程使用 ASP.NET Core MVC,这为本教程提供了 许多 改进。

本教程讲解了使用控制器和视图的 ASP.NET Core MVC。 Razor Pages 是 ASP.NET Core 中的一种新替代方法,它是一种基于页面的编程模型,使生成 Web UI 更加轻松高效。 建议在 MVC 版本之前试用 Razor Pages 教程。 Razor Pages 教程:

  • 更易于遵循。
  • 涵盖更多功能。
  • 是新应用开发的首选方法。

在本部分中,你将修改 HelloWorldController 类以使用视图模板文件来干净地封装生成客户端的 HTML 响应的过程。

你将使用 Razor 视图引擎创建视图模板文件。 基于 Razor 的视图模板具有 .cshtml 文件扩展名,并提供使用 C# 创建 HTML 输出的优雅方法。 Razor 可最大程度地减少编写视图模板时所需的字符数和击键,并启用快速流畅的编码工作流。

目前,该方法 Index 返回一个字符串,其中包含在控制器类中硬编码的消息。 将 Index 方法更改为调用控制器 View 方法,如以下代码所示:

public ActionResult Index() 
{ 
    return View(); 
}

上述 Index 方法使用视图模板生成对浏览器的 HTML 响应。 控制器方法(也称为 操作方法),如 Index 上述方法,通常返回 ActionResult (或派生自 ActionResult 的类),而不是字符串等基元类型。

右键单击 Views\HelloWorld 文件夹,然后单击“添加”,然后单击“具有布局的 MVC 5 视图页”(Razor)。

显示“解决方案资源管理器”窗口的屏幕截图。“Hello World”右键单击菜单和“添加子菜单”处于打开状态,并且选择了“布局 Razor”的 M V C 5 视图页面。

在“ 指定项名称 ”对话框中,输入 “索引”,然后单击“ 确定”。

显示“指定项名称”对话框的屏幕截图。索引位于“项名称”字段中。

“选择布局页 ”对话框中,接受默认 _Layout.cshtml 并单击“ 确定”。

这是一张显示“选择布局页面”的屏幕截图。共享子文件夹处于打开状态,并选择了 Layout.cshtml。

在上面的对话框中, 视图\共享文件夹 在左窗格中处于选中状态。 如果另一个文件夹中有自定义布局文件,则可以将其选中。 我们将在本教程的后面部分讨论布局文件

创建 MvcMovie\Views\HelloWorld\Index.cshtml 文件。

显示“解决方案资源管理器”窗口的屏幕截图。Views 文件夹和 Hello World 子文件夹处于打开状态。

添加以下突出显示的标记。

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

右键单击 Index.cshtml 文件,然后选择 “在浏览器中查看”。

Pi

还可以右键单击 Index.cshtml 文件,然后在 页面检查器中选择“视图”。 有关详细信息,请参阅 页面检查器教程

或者,运行应用程序并浏览到 HelloWorld 控制器(http://localhost:xxxx/HelloWorld)。 Index控制器中的方法没有执行太多工作;它只运行了语句,该语句return View()指定该方法应使用视图模板文件来呈现对浏览器的响应。 由于未显式指定要使用的视图模板文件的名称,因此 ASP.NET MVC 默认使用 \Views\HelloWorld 文件夹中的 Index.cshtml 视图文件。 下图显示了在视图中硬编码的字符串“Hello from our View Template!” 。

显示“索引”页以及来自视图模板的文本“Hello”的屏幕截图。

看起来相当不错。 但是,请注意,浏览器的标题栏显示“索引 - 我的 ASP.NET 应用程序”,页面顶部的大链接显示“应用程序名称”。根据浏览器窗口的缩小程度,可能需要单击右上角的三个栏才能查看“ 主页”、“ 关于”、“ 联系人”、“ 注册 ”和 “登录” 链接。

更改视图和布局页面

首先,想要更改页面顶部的“应用程序名称”链接。 该文本对于每个页面都是常见的。 实际上,该功能仅在项目中的一个位置实现,尽管它出现在应用程序的每一页上。 转到解决方案资源管理器中的 /Views/共享文件夹,打开 _Layout.cshtml 文件。 此文件称为 布局页 ,位于所有其他页面使用的共享文件夹中。

_LayoutCshtml

布局模板允许你在一个位置指定网站的 HTML 容器布局,然后将其应用于网站中的多个页面。 查找 @RenderBody() 行。 RenderBody 是一个占位符,您创建的所有与视图相关的页面都将显示在布局页中,并被包含在其中。 例如,如果选择关于链接,视图\Home\About.cshtml视图将在RenderBody方法中呈现。

更改标题元素的内容。 将布局模板中的 ActionLink 从“应用程序名称”更改为“MVC 电影”,并将控制器从中 Home 更改为 Movies。 完整的布局文件如下所示:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - Movie App</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")

</head>
<body>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                    <span class="icon-bar"></span>
                </button>
                @Html.ActionLink("MVC Movie", "Index", "Movies", null, new { @class = "navbar-brand" })
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    <li>@Html.ActionLink("Home", "Index", "Home")</li>
                    <li>@Html.ActionLink("About", "About", "Home")</li>
                    <li>@Html.ActionLink("Contact", "Contact", "Home")</li>
                </ul>
            </div>
        </div>
    </div>
    <div class="container body-content">
        @RenderBody()
        <hr />
        <footer>
            <p>&copy; @DateTime.Now.Year - My ASP.NET Application</p>
        </footer>
    </div>

    @Scripts.Render("~/bundles/jquery")
    @Scripts.Render("~/bundles/bootstrap")
    @RenderSection("scripts", required: false)
</body>
</html>

运行应用程序并注意到它现在显示“MVC 电影”。 单击关于链接,你会看到该页面也显示“MVC Movie”。 我们能够在布局模板中进行更改一次,并让网站上的所有页面反映新标题。

显示“MVC电影简介”页的屏幕截图。

首次创建 Views\HelloWorld\Index.cshtml 文件时,它包含以下代码:

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

上面的 Razor 代码显式设置布局页。 检查 Views\_ViewStart.cshtml 文件,其中包含完全相同的 Razor 标记。 Views\_ViewStart.cshtml 文件定义所有视图将使用的通用布局,因此你可以注释掉或删除 Views\HelloWorld\Index.cshtml 文件中的代码。

@*@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}*@

@{
    ViewBag.Title = "Index";
}

<h2>Index</h2>

<p>Hello from our View Template!</p>

可以使用该 Layout 属性设置不同的布局视图,或将其设置为 null 不使用布局文件。

现在,让我们更改索引视图的标题。

打开 MvcMovie\Views\HelloWorld\Index.cshtml。 有两个位置可以进行更改:首先,显示在浏览器标题中的文本,然后在辅助标头( <h2> 元素)中。 你将使它们略有不同,以便你可以看到哪些代码更改了应用的哪一部分。

@{
    ViewBag.Title = "Movie List";
}

<h2>My Movie List</h2>

<p>Hello from our View Template!</p>

若要指示要显示的 HTML 标题,上述代码将设置 Title 对象的属性(该属性 ViewBag 位于 Index.cshtml 视图模板中)。 请注意,布局模板(Views\Shared\_Layout.cshtml)在HTML <head> 部分的 <title> 元素中使用了我们之前修改的此值。

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>@ViewBag.Title - Movie App</title>
    @Styles.Render("~/Content/css")
    @Scripts.Render("~/bundles/modernizr")
</head>

使用此方法 ViewBag ,可以在视图模板和布局文件之间轻松传递其他参数。

运行该应用程序。 请注意,浏览器标题、主标题和辅助标题已更改。 如果在浏览器中看不到更改,您可能正在查看缓存的内容。请在浏览器中按 Ctrl+F5 强制服务器重新加载响应。浏览器标题是在我们设置的ViewBag.TitleIndex.cshtml视图模板中创建的,并在布局文件中添加了“- 电影应用程序”。

另请注意 Index.cshtml 视图模板中的内容如何与 _Layout.cshtml 视图模板合并,并将单个 HTML 响应发送到浏览器。 布局模板让您可以轻松地对整个应用程序中的所有页面进行更改。

显示“M V C 电影我的电影列表”页的屏幕截图。

不过,我们的这部分“数据”(在本例中是“来自我们视图模板的问候!”消息)是硬编码的。 MVC 应用程序具有“V”(视图),并且你有一个“C”(控制器),但还没有“M”(模型)。 不久,我们将演练如何创建数据库并从中检索模型数据。

将数据从控制器传递给视图

不过,在转到数据库并讨论模型之前,让我们先讨论如何将信息从控制器传递到视图。 控制器类是在响应传入 URL 请求时调用的。 控制器类用于编写处理传入浏览器请求的代码、从数据库检索数据,并最终决定要发回浏览器的响应类型。 然后,可以从控制器使用视图模板来生成 HTML 响应并设置浏览器的格式。

控制器负责提供所需的任何数据或对象,以便视图模板向浏览器呈现响应。 最佳做法: 视图模板不应执行业务逻辑或直接与数据库交互。 相反,视图模板应仅适用于控制器提供给它的数据。 维护此“关注点分离”有助于保持代码干净、可测试且更易于维护。

目前,Welcome类中的HelloWorldController操作方法采用一个namenumTimes参数,然后将值直接输出到浏览器。 与其让控制器将此响应呈现为字符串,不如更改控制器以使用视图模板。 视图模板将生成动态响应,这意味着需要将控制器中的适当数据位传递到视图,以便生成响应。 可以通过让控制器将视图模板所需的 ViewBag 动态数据(参数)放入视图模板随后可以访问的对象中来执行此操作。

返回到HelloWorldController.cs文件,更改Welcome方法,以便向ViewBag对象添加MessageNumTimes值。 ViewBag 是一个动态对象,这意味着你可以将任何内容放入其中。在将内容放入 ViewBag 对象之前,该对象没有定义的属性。 ASP.NET MVC 模型绑定系统会自动将地址栏中的查询字符串中的命名参数(namenumTimes)映射到方法中的参数。 完整的 HelloWorldController.cs 文件如下所示:

using System.Web;
using System.Web.Mvc;

namespace MvcMovie.Controllers
{
    public class HelloWorldController : Controller
    {
        public ActionResult Index()
        {
            return View();
        }

        public ActionResult Welcome(string name, int numTimes = 1)
        {
            ViewBag.Message = "Hello " + name;
            ViewBag.NumTimes = numTimes;

            return View();
        }
    }
}

现在,对象 ViewBag 包含将自动传递给视图的数据。 接下来,需要欢迎视图模板! 在“ 生成 ”菜单中,选择“ 生成解决方案 ”(或 Ctrl+Shift+B),以确保编译项目。 右键单击 Views\HelloWorld 文件夹,然后单击“添加”,然后单击“具有布局的 MVC 5 视图页”(Razor)。

显示“解决方案资源管理器”窗口的屏幕截图,

在“ 指定项名称 ”对话框中,输入 “欢迎”,然后单击“ 确定”。

“选择布局页 ”对话框中,接受默认 _Layout.cshtml 并单击“ 确定”。

显示“选择布局”页的屏幕截图。标记为“共享”的子文件夹已打开,并且选择了Layout.cshtml。

创建 MvcMovie\Views\HelloWorld\Welcome.cshtml 文件。

替换 Welcome.cshtml 文件中的标记。 你将创建一个循环,该循环会根据用户指定的次数显示“Hello”。 完整的 Welcome.cshtml 文件如下所示。

@{
    ViewBag.Title = "Welcome";
}

<h2>Welcome</h2>

<ul>
    @for (int i = 0; i < ViewBag.NumTimes; i++)
    {
        <li>@ViewBag.Message</li>
    }
</ul>

运行应用程序并浏览到以下 URL:

http://localhost:xx/HelloWorld/Welcome?name=Scott&numtimes=4

现在,数据从 URL 获取,并使用 模型绑定器传递到控制器。 控制器将数据打包到对象 ViewBag 中,并将该对象传递给视图。 然后,该视图会将数据显示为 HTML 给用户。

显示 M V C 电影欢迎页的屏幕截图。

在上面的示例中,我们使用对象 ViewBag 将数据从控制器传递到视图。 在本教程的后面部分,我们将使用视图模型将数据从控制器传递到视图。 传递数据的视图模型方法通常比视图包方法更优先。 有关详细信息,请参阅博客文章 动态与强类型视图

当然,这是模型的一种“M”类型,而不是数据库类。 让我们用学到的内容来创建一个电影数据库。