ASP.NET Core Razor 页面 VS MVC

2017 年 8 月 23 日 DotNet

(点击上方蓝字,可快速关注我们)


来源:Sweet-Tang

cnblogs.com/tdfblog/p/7400865.html


作为.NET Core 2.0发行版的一部分,还有一些ASP.NET的更新。其中之一是添加了一个新的Web框架来创建“页面”,而不需要复杂的ASP.NET MVC。


新的Razor页面是一个比较简单的MVC框架版本,在某些方面是老的“.aspx” WebForms的演变。


在本文中,我们将介绍使用ASP.NET Razor页面和MVC的一些细节。


  • Razor页面基础知识


  • ASP.NET MVVM vs MVC


  • Razor页面的优点和缺点


  • 使用Handlers实现多个GET、POST Action方法


  • 为什么您应该使用Razor Pages


  • ASP.NET Razor页面与MVC代码的区别


基础知识:什么是ASP.NET Razor页面?


Razor页面与ASP.NET MVC开发使用的视图组件非常相似,它们具有所有相同的语法和功能。


最关键的区别是模型和控制器代码也包含在Razor页面中。


它更像是一个MVVM(Model-View-ViewModel)框架,它支持双向数据绑定,更简单的开发体验,具有独立的关注点。


下面是一个Razor页面最基本的示例,在@functions块中内嵌代码,不过推荐将PageModel代码放在一个单独的文件中。这更像是我们在ASP.NET WebForms文件中编写代码的方式。


@page

@model IndexModel

@using Microsoft.AspNetCore.Mvc.RazorPages


@functions {

    public class IndexModel : PageModel

    {

        public string Message { get; private set; } = "In page model: ";

        public void OnGet()

        {

            Message += $" Server seconds  { DateTime.Now.Second.ToString() }";

        }

    }

}

<h2>In page sample</h2>

<p>

    @Model.Message

</p>


我们现在两个选择:ASP.NET MVVM 或 MVC


我们现在有两个选择,一个MVC,另一个是MVVM框架。我不打算介绍MVC vs MVVM的所有细节。


在这篇文章(http://www.dotnettricks.com/learn/designpatterns/understanding-mvc-mvp-and-mvvm-design-patterns)中用一些例子很详细说明了这一点。MVVM框架最关注的是数据模型的双向绑定。


MVC适用于具有大量动态服务器视图、单页应用程序、REST API和AJAX调用的应用程序。Razor页面非常适用于只读或执行基本数据输入的简单页面。


MVC最近在大多数编程语言的Web应用程序中非常流行,但是它也有其利弊。ASP.NET WebForms被设计为一个MVVM解决方案,您可以认为Razor页面是WebForms的演变。


Razor页面的优点和缺点


我(Matt Watson)一直在做ASP.NET开发大约15年了,精通所有的ASP.NET框架。根据我在使用新的Razor页面过程中,下面是我总结的利弊以及我是如何看待使用它们。


优点:更有条理,更少的“潜规则”


我不知道您,但是我第一次使用ASP.NET MVC,花了很多时间试图弄清楚它是如何工作的。命名规则和动态创建路由导致了很多我不习惯的规则。事实上,从路径“/Home/”到HomeController.Index(),它从“Views\Home\Index.cshtml”中加载一个视图文件,在刚开始使用时觉得很神奇。


Razor页面没有任何“潜规则”,文件更有条理。您有一个Razor视图和后台代码文件,就像WebForms一样,不像与MVC对应的控制器、视图和模型存放在不同目录中具有单独的文件。


MVC项目和Razor页面项目比较(将在本文后面介绍更多的代码差异)。



MVC与Razor页面文件比较


优点:单一责任


如果您以前曾经使用过MVC框架,您可能会看到一些巨大的控制器类,其中包含许多不同的Action。它们就像一种随着时间的推移而增加的病毒。


使用Razor页面,每个页面都是独立的,视图和代码组织在一起,这遵循单一责任原则。


使用Handlers实现多个GET、POST Action


默认情况下,Razor页面设计为具有单个OnGetAsync和OnPostAsync Action方法;如果您想在单个页面中具有不同的Action,则需要使用所谓的Handler。如您的页面有AJAX回调、多个表单提交或其它场景,则需要使用它。


例如,如果您使用Kendo Grid并希望通过AJAX调用加载Grid数据,则需要使用Handler来处理该AJAX调用。任何类型的单页面应用程序将使用大量Handler,或者您将所有这些AJAX调用指向MVC控制器。


我在页面中添加了一个名为OnGetHelloWorldAsync()的方法,我们该怎么调用它?


从我的研究来看, 调用Handler有三种不同的方式:


  1. Querystring – 示例:“/managepage/2177/?handler=helloworld”


  2. 为视图中的定义路由:@page"{handler?}",然后在Url中包括“/helloworld”


  3. 在视图中定义提交按钮 - 示例:<input type="submit" asp-page-handler="JoinList" value="Join" />


可以在这里了解更多(https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/?tabs=visual-studio#multiple-handlers-per-page)有关单页面多个Handlers 的方式。


为什么您应该使用Razor页面的!


Razor页面是网页应用程序中的完美解决方案,我可能提出一个争议。它一目了然,你的应用程序中的任何HTML“页面”都是真实的页面。


目前,MVC Action 可以返回HTML视图、JSON、文件或任何内容。使用Razor页面将页面加载和AJAX回调的服务之间强制分离。


想想,这种强制分离解决了很多问题。



这将阻止MVC控制器包含大量的Action,MVC应用程序中的Action混合了不同的“页面”,而且还包含AJAX回调和其它功能。


当然,我还没有实际中使用这种开发方式,这可能是失败,也可能是成功的,只有时间才能告诉社区如何使用Razor页面。


ASP.NET Razor页面与MVC的代码比较


作为Razor页面的一部分,我在MVC和Razor页面中构建了一个非常简单Form表单。让我们来看看之间的代码。它只有一个文本框和提交按钮。


这是MVC视图:


@model RazorPageTest.Models.PageClass

<form asp-action="ManagePage">

    <div class="form-horizontal">

        <h4>Client</h4>

        <hr />

        <div asp-validation-summary="ModelOnly" class="text-danger"></div>

        <input type="hidden" asp-for="PageDataID" />

        <div class="form-group">

            <label asp-for="Title" class="col-md-2 control-label"></label>

            <div class="col-md-10">

                <input asp-for="Title" class="form-control" />

                <span asp-validation-for="Title" class="text-danger"></span>

            </div>

        </div>

        <div class="form-group">

            <div class="col-md-offset-2 col-md-10">

                <input type="submit" value="Save" class="btn btn-default" />

            </div>

        </div>

    </div>

</form>


这是MVC控制器(数据模型是PageClass,只有两个属性,很简单)。


public class HomeController : Controller

{

    public IConfiguration Configuration;


    public HomeController(IConfiguration config)

    {

        Configuration = config;

    }


    public async Task<IActionResult> ManagePage(int id)

    {

        PageClass page;


        using (var conn = new SqlConnection(Configuration.GetConnectionString("contentdb")))

        {

            await conn.OpenAsync();


            var pages = await conn.QueryAsync<PageClass>("select * FROM PageData Where PageDataID = @p1", new { p1 = id });


            page = pages.FirstOrDefault();

        }


        return View(page);

    }


    [HttpPost]

    [ValidateAntiForgeryToken]

    public async Task<IActionResult> ManagePage(int id, PageClass page)

    {


        if (ModelState.IsValid)

        {

            try

            {

                //Save to the database

                using (var conn = new SqlConnection(Configuration.GetConnectionString("contentdb")))

                {

                    await conn.OpenAsync();

                    await conn.ExecuteAsync("UPDATE PageData SET Title = @Title WHERE PageDataID = @PageDataID", new { page.PageDataID, page.Title});

                }

            }

            catch (Exception)

            {

               //log it

            }

            return RedirectToAction("Index", "Home");

        }

        return View(page);

    }

}


现在我们来比较一下Razor页面。


Razor 页面:


@page "{id:int}"

@model RazorPageTest2.Pages.ManagePageModel


<form asp-action="ManagePage">

    <div class="form-horizontal">

        <h4>Manage Page</h4>

        <hr />

        <div asp-validation-summary="ModelOnly" class="text-danger"></div>

        <input type="hidden" asp-for="PageDataID" />

        <div class="form-group">

            <label asp-for="Title" class="col-md-2 control-label"></label>

            <div class="col-md-10">

                <input asp-for="Title" class="form-control" />

                <span asp-validation-for="Title" class="text-danger"></span>

            </div>

        </div>


        <div class="form-group">

            <div class="col-md-offset-2 col-md-10">

                <input type="submit" value="Save" class="btn btn-default" />

            </div>

        </div>

    </div>

</form>


这是Razor PageModel,也称之为后台代码:


public class ManagePageModel : PageModel

{

    public IConfiguration Configuration;


    public ManagePageModel(IConfiguration config)

    {

        Configuration = config;

    }


    [BindProperty]

    public int PageDataID { get; set; }

    [BindProperty]

    public string Title { get; set; } 


    public async Task<IActionResult> OnGetAsync(int id)

    {

        using (var conn = new SqlConnection(Configuration.GetConnectionString("contentdb")))

        {

            await conn.OpenAsync();

            var pages = await conn.QueryAsync("select * FROM PageData Where PageDataID = @p1", new { p1 = id });


            var page = pages.FirstOrDefault();


            this.Title = page.Title;

            this.PageDataID = page.PageDataID;

        }


        return Page();

    }


    public async Task<IActionResult> OnPostAsync(int id)

    {


        if (ModelState.IsValid)

        {

            try

            {

                //Save to the database

                using (var conn = new SqlConnection(Configuration.GetConnectionString("contentdb")))

                {

                    await conn.OpenAsync();

                    await conn.ExecuteAsync("UPDATE PageData SET Title = @Title WHERE PageDataID = @PageDataID", new { PageDataID, Title });

                }

            }

            catch (Exception)

            {

               //log it

            }

            return RedirectToPage("/");

        }

        return Page();

    }

}


差异解密


两者之间的代码几乎相同,以下是主要的区别:


  • MVC视图代码部分完全相同,除了Razor页面顶上的@page;


  • ManagePageModel具有OnGetAsync和OnPostAsync方法,取代了MVC控制器中两个“ManagePage” Action;


  • ManagePageModel包含之前单独在PageClass中的两个属性。


在MVC中HTTP POST请求,将对象传递给MVC的Action(例如ManagePage(int id,PageClass page));使用Razor页面,可以使用数据双向绑定。


为了让Razor页面正确地使用双向数据绑定,我两个属性(PageDataID、Title)使用了[BindProperty]标记。


总结


我真的很喜欢Razor页面,可以看到在我正在开发的ASP.NET Core项目中使用它们。我喜欢Razor页面的原因是应用程序中的真实页面,并使用MVC实现所有AJAX/REST API。我


承认还有其它功能,Razor页面实现不了。好消息是MVC是超级灵活的,但这也使得它变得更加复杂。Razor Pages的真正美丽是它的简单。


参考:


Introduction to Razor Pages in ASP.NET Core(https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/)


.NET Core 2.0 Changes – 4 Key Things to Know(https://stackify.com/net-core-2-0-changes/)


看完本文有收获?请转发分享给更多人

关注「DotNet」,提升.Net技能 

登录查看更多
0

相关内容

MVC 模式(Model-View-Controller)是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller)。
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
Python导论,476页pdf,现代Python计算
专知会员服务
259+阅读 · 2020年5月17日
【CVPR2020-谷歌】多目标(车辆)跟踪与检测框架 RetinaTrack
专知会员服务
44+阅读 · 2020年4月10日
MIT新书《强化学习与最优控制》
专知会员服务
275+阅读 · 2019年10月9日
告别 PS !3 行代码 5 秒搞定抠图的 AI 神器!
程序人生
6+阅读 · 2019年7月11日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
百度开源项目OpenRASP快速上手指南
黑客技术与网络安全
5+阅读 · 2019年2月12日
JavaScript 背包问题详解
前端大全
7+阅读 · 2018年1月17日
开源巨献:阿里巴巴最热门29款开源项目
算法与数据结构
5+阅读 · 2017年7月14日
Arxiv
3+阅读 · 2018年10月18日
Arxiv
4+阅读 · 2018年5月4日
VIP会员
相关资讯
告别 PS !3 行代码 5 秒搞定抠图的 AI 神器!
程序人生
6+阅读 · 2019年7月11日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
百度开源项目OpenRASP快速上手指南
黑客技术与网络安全
5+阅读 · 2019年2月12日
JavaScript 背包问题详解
前端大全
7+阅读 · 2018年1月17日
开源巨献:阿里巴巴最热门29款开源项目
算法与数据结构
5+阅读 · 2017年7月14日
Top
微信扫码咨询专知VIP会员