创建ASP.NET Core MVC应用程序(1)-添加Controller和View

创建ASP.NET Core MVC应用程序(1)-添加Controller和View

参考文档:Getting started with ASP.NET Core MVC and Visual Studio

这系列文章是参考了.NET Core文档和源码,可能有人要问,直接看官方的英文文档不就可以了吗,为什么还要写这些文章呢?

原因如下:

  • 官方文档涉及的内容相当全面,属于那种大而全的知识仓库,不太适合初学者,很容易让人失去重要,让人掉入到具体的细节之中。
  • 对于大多数人来讲开发语言只是工具,程序员都有一个通病,就是死磕工具,把工具学深。我认为在工具上没有必要投入太多时间,以能高效地完成日常的工作项目为准即可。要需求驱动学习,你需要什么学什么。如果你学的新技术新特性只是屠龙之技或者只需要用到的时候去查一下即可的话,这种死磕这又有什么用。没有必要花120%的时间去学100%的知识,你只需要花20%的时间去学习80%的知识就可以了,剩下的等实际的项目中用到的时候去查就可以了,工具只是工具,不是工作本身。
  • 目前基本所有的文章都是基于Windows平台的Visual Studio IDE来介绍的。而我用的是一台Mac,所以我将基于Mac平台的Visual Studio Code讲解适合我们实际项目中遇到的知识。
  • 还有一点,就是这是我个人的学习总结。

这系列文章就是让你去花20%的时间去学80%的东西,剩下的20%再去看官方文档。

之前介绍了《如何在Mac下运行ASP.NET Core应用程序》,主要是讲解了如何在Mac下把ASP.NET Core跑起来,在这一篇中将进一步分析如何添加Controller、View、Model等。

Model-View-Controller (MVC)�架构模式将一个应用程序分成了三大块:ModelViewController

  • Models: 用于表示应用程序数据的类,并使用验证逻辑来约束数据的业务规则。通常模型对象用来从数据库获取和存储实体模型�数据。比如User Model 从数据库获取用户数据,并将它交给View来显示或者直接更新,更新后的数据再写入到数据库中。
  • Views: 用来显示应用程序UI的组件,该UI会显示Model数据。
  • Controllers: 是Models和Views的一个桥梁。用来处理浏览器请求,获取Model数据,并将指定视图模板作为响应返回给浏览器。视图(View)仅仅用于显示信息,控制器(Controller)用于处理并响应用户的输入和交互。比如,Controller处理路由数据查询字符串值,并将这些值传递给Model,Model再去使用这些值去查询数据库。

MVC模式帮助你创建一个关注分离的应用程序(输入逻辑业务逻辑UI逻辑),同时这个模块之间是松耦合的。UI逻辑属于View,输入逻辑属于Controller,业务逻辑属于Model。

添加Controller

namespace MyFirstApp.Controllers
{
    public class HomeController : Controller
    {
        // GET: /<controller>/
        public IActionResult Index()
        {
            return View();
        }

        // GET: /<controller>/About
        public IActionResult About()
        {
            ViewData["Message"] = "Your application description page.";

            return View();
        }

        public IActionResult Contact()
        {
            ViewData["Message"] = "Your contact page.";

            return View();
        }

        public IActionResult Error()
        {
            return View();
        }

        public IActionResult Welcome(string name, int id = 1)
        {
            ViewData["Message"] = "Hello " + name;
            ViewData["id"] = id;

            return View();
        }
    }
}

在控制器中的每一个public方法都可以作为HTTP终结点被调用。

第一个注释表示这是一个通过在根URL添加“/Home/”进行调用的HTTP GET方法。第二个注释表示这是一个通过在根URL添加"/Home/About/"来进行调用的HTTP GET方法。

MVC根据传入的请求URL调用相应的控制器类以及其中的Action方法,MVC默认使用的URL路由逻辑采用类似于这样的格式来决定具体的代码调用:

/[Controller]/[ActionName]/[Parameters]

打开Startup.cs你会看到该项目的路由规则:

当你不带任何URL段(segment)直接运行该程序时,将默认访问“Home”控制器中的"Index"方法。

第一个URL segment决定运行哪个Controller,所以http://localhost:5000/Home映射到HomeController类;URL segment第二个部分决定类里面的Action方法。所以http://localhost:5000/Home/Index会运行HomeController类中的Index方法;URL segment的第三部分(id)是路由数据。

这里通过增加一个方法来显示通过URL传递一些参数信息到Controller。

public string Welcome(string name, int id = 1)
{
    return HtmlEncoder.Default.Encode($"Hello {name}, id: {id}");
}

上述代码通过使用HtmlEncoder.Default.Encode来保护应用免受JS的恶意输入,并且使用了C#的新特性Interpolated Strings

http://localhost:5000/Home/Welcome?name=Charlire&id=1

MVC的模型绑定系统自动将查询字符串的命名参数映射到具体的方法中的参数,注意名称必须一致。

上述代码中URL segment(Parameters)没有被使用到,参数nameid都是作为查询字符串被传递的。?是一个分隔符,后面跟着的就是查询字符串,&用来分割查询字符串。

输入下面的URL:http://localhost:5000/Home/Welcome/1?name=Charlire。这一次第三个URL segment将匹配到路由参数idWelcome方法包含一个与MapRoute方法中的URL模板相匹配的id参数。随后的?(id?)表示id参数是可选的。

添加View

通过Razor视图引擎创建视图模板文件,基于Razor的视图模板使用 .cshtml 作为文件扩展名,通过使用C#提供了一个优雅的方式来创建HTML。

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

上面的Index方法使用视图模板来生成一个HTML响应给浏览器。Controller中的Action方法通常返回一个IActionResult(或一个派生于ActionResult 类),而不是像String这样的基元类型。

点击Views文件夹,在该文件夹下面新建与Controller名对应的文件夹。

然后我们导航到Views->User文件夹,运行命令yo aspnet:mvcview Index在该文件夹下面生成Index.cshtml。

Index方法只是简单地运行了return View(),来指定方法去使用一个视图模板文件来为浏览器渲染最新的响应。因为没有显式指定所要使用的视图模板文件,MVC会默认使用 /Views/User 文件夹中的 Index.cshtml

改变视图和布局页面

通用点击菜单链接,你会发现每一个页面都显示了相同的菜单布局,这个菜单布局位于 Views/Shared/_Layout.cshtml 文件。

Layout模板允许你在一个地方指定网站的HTML容器布局,并应用到网站的多个页面中。@RenderBody()是一个占位符,用来显示你指定视图的位置,“包裹在”布局页面。举个例子,当你点击About链接,Views/Home/About.cshtml视图就会在RenderBody�方法内渲染。

修改Layout文件中的标题和菜单链接

注意现在每一个页面都显示了新修改的链接,通过在Layout模板中修改一次,网站上的所有的页面都立即显示成新修改的信息。

通过查看 Views/_ViewStart.cshtml 文件:

@{
    Layout = "_Layout";
}

Views/_ViewStart.cshtml 文件将 Views/Shared/_Layout.cshtml 文件引入到每一个视图中。你可以通过Layout属性来设置一个不同的布局视图,或将它设置成null,那么将不使用任何一个布局文件。

修改 Views/User/Index.cshtml 文件如下:

@{
    ViewData["Title"] = "User List";
}

<h2>User List</h2>

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

ViewData["Title"] = "User List";ViewDataDictionaryTitle属性设置为User List。这个Title属性将用在 Views/Shared/_Layout.cshtml Layout页面的<title>�HTML元素上。

<title>@ViewData["Title"] - User MVC Application</title>

注意 Index.cshtml 视图模板中的内容是怎么和 Views/Shared/_Layout.cshtml 视图模板进行合并的,布局模板使得修改应用里所有的页面很容易。

从Controller传递数据到View

在谈到数据库和模型(Models)之前,先让我们讨论一下从控制器传递信息到视图。控制器方法会在传入的URL请求响应时被调用。控制器类是用于处理传入的浏览器请求,从数据库获取数据,并最终决定哪种类型的的响应会被回传给浏览器。

控制器主要负责提供视图模板向浏览器呈现一个响应所需的数据或对象。

最佳实践:视图模板不应该执行业务逻辑或直接与数据库进行交互,而只应该使用控制器提供给它的数据。保持这样的“关注分离”有助于保持你的代码整洁,可测试性及更易于维护。

当前,HomeController控制器中的Welcome方法接受一个nameid参数,然后直接将值输出到浏览器。我们在控制器中将使用一个视图模板来代替字符串,视图模板将生成一个动态响应,这就意味着你需要通过控制器传递适当的数据给视图来生成响应,可以让控制器将视图模板需要的动态数据(参数)放入ViewData字典中,随后视图模板可以通过访问该字典获取到这些数据。

ViewData字典是一个动态对象,你可以将任何你想要的数据加进去。在你加入数据之前,ViewData对象没有任何已定义的属性。MVC的模型绑定系统自动映射地址栏中查询字符串的命名参数到你方法中的参数。

public IActionResult Welcome(string name, int id = 1)
{
    ViewData["Message"] = "Hello " + name;
    ViewData["id"] = id;

    return View();
}

ViewData字典对象包括将要传递到视图的数据。接受,我们来创建一个Welcome视图模板。

这里将在Welcome.cshtml视图模板中创建一个循环。

@*
    For more information on enabling MVC for empty projects, visit https://go.microsoft.com/fwlink/?LinkID=397860
*@
@{
    ViewData["Title"]= "Welcome Page";
}
<h2>Welcome</h2>

<ul>
    @for(int i=0; i<(int)ViewData["id"]; i++)
    {
        <li>@ViewData["Message"]</li>
    }
</ul>

数据从URL获得并通过MVC模型绑定器传递到控制器,控制器将数据打包封装到ViewData字典中并将该对象传递给视图。接着,视图将数据以HTML的形式渲染到浏览器。

我们使用了一个ViewData字典来将数据从控制器传递到视图,接下来我们将使用视图模型(View Model)来实现相同的目的。通过View Model来传递数据比通过ViewData更受欢迎。

个人博客

我的个人博客

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容