asp.net core系列 39 Razor 介绍与详细示例

一. Razor介绍

  在使用ASP.NET Core Web开发时, ASP.NET Core MVC 提供了一个新特性Razor。 这样开发Web包括了MVC框架和Razor框架。对于Razor来说它是一个新特性,在官方介绍ASP.NET Core的优点中提到“Razor Pages可以使基于页面的编码方式更简单高效”。

  1.1 Razor结构介绍

    (1) Pages文件夹

                            存放所有Razor页面,包括Razor 页面和支持文件。 每个 Razor 页面都是一对文件:

                            一个 .cshtml 文件,其中包含使用 Razor 语法的 C# 代码的 HTML 标记。

                            一个 .cshtml.cs 文件,其中包含处理页面事件的 C# 代码。

                     支持文件的名称以下划线开头。 例如,_Layout.cshtml 文件可配置所有页面通用的 UI 元素。 此文件设置页面顶部的导航菜单和页面底部的版权声明(后面讲布局时再介绍)。

    (2) wwwroot 文件夹

                            包含静态文件,如 HTML 文件、JavaScript 文件和 CSS 文件(后面再讲)。

    (3) appSettings.json

扫描二维码关注公众号,回复: 5461783 查看本文章

                            包含配置数据,如连接字符串。参考asp.net core 系列第 10和11篇

    (4) Program.cs

                            包含程序的入口点,启动主机。参考asp.net core 系列第 16和17篇

    (5) startup.cs

                            包含配置应用行为的代码,例如,是否需要同意 cookie。参考asp.net core 系列第 2篇

    

  1.2  启动Razor关键代码

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        // Includes support for Razor Pages and controllers.
        services.AddMvc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseMvc();
    }
}

   1.3  @page指令

    对于每一个Razor 页面,在.cshtml视图文件中,@page指令必须是页面上的第一个 Razor 指令。@page 使文件转换为一个 MVC 操作 ,这意味着它将直接处理请求, 而不通过控制器(Controllers)处理。@page 将影响其他 Razor 构造的行为。下面是一个直接处理请求的示例:

     //index.cshtml.cs 
    public class IndexModel : PageModel
    {
        public string Message { get; private set; } = "PageModel in C#";

        //加载时调用
        public void OnGet()
        {
            Message += $" Server time is { DateTime.Now }";
        }
    }    

    //Index.cshtml,直接输出后端的Message属性信息,也这是Razor的优势,使用页面的编码方式更简单高效。
    @page
    @using RazorPagesIntro.Pages
    @model IndexModel

    <h2>Separate page model</h2>
    <p>
            @Model.Message
    </p>

  1.4 页面url路径

    URL路径是与页面的关联,由页面在文件系统中的位置决定,下表显示了Razor Page路径和匹配的URL:

文件路径 访问网址
/Pages/Index.cshtml /     or     /Index
/Pages/Contact.cshtml /Contact
/Pages/Store/Contact.cshtml /Store/Contact
/Pages/Store/Index.cshtml /Store  or  /Store/Index

二. 完整示例介绍

  

  2.1 安装EF数据提供程序

    这里使用内存数据库Microsoft.EntityFrameworkCore.InMemory,Entity Framework Core 和内存数据库一起使用, 这对测试非常有用。

    PM> Install-Package Microsoft.EntityFrameworkCore.InMemory

    

  2.2 新建数据模型类(POCO )和EF上下文类 

   public class Customer
    {
        public int Id { get; set; }

         //保存不能为空,字符长度小于100
        [Required, StringLength(100)]
        public string Name { get; set; }
    }

   public class AppDbContext : DbContext
    {
        public AppDbContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet<Customer> Customers { get; set; }
    }

  2.3 启动类关键代码

    public class Startup
    {
        public IHostingEnvironment HostingEnvironment { get; }

        public void ConfigureServices(IServiceCollection services)
        {            
            // 使用内存数据库
            services.AddDbContext<AppDbContext>(options =>
                              options.UseInMemoryDatabase("name"));
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app)
        {
            app.UseMvc();
        }
    }

  2.4 新增页 Pages/Create

@page
@model StudyRazorDemo.Pages.CreateModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
<html>
<body>
    <p>
        Enter your name.
    </p>
    <div asp-validation-summary="All"></div>
    <form method="POST">
        <!-- 这里的Customer对象来自后端-->
        <div>Name: <input asp-for="Customer.Name" /></div>
        <input type="submit" />
    </form>
</body>
</html>
    public class CreateModel : PageModel
    {
        private readonly AppDbContext _db;

        public CreateModel(AppDbContext db)
        {
            _db = db;
        }

        //模型绑定,通过绑定使用相同的属性显示窗体字段<input asp-for="Customer.Name" />来减少代码,并接受输入,是双向绑定。
        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnPostAsync()
        {
            //验证Customer对象属性值
            if (!ModelState.IsValid)
            {
                return Page();
            }

            //添加到EF上下文,再保存到内存数据库
            _db.Customers.Add(Customer);
            await _db.SaveChangesAsync();

            // 重定向到index主页
            return RedirectToPage("/Index");
        }
    }

  点击提交后,cs后端的Customer对象将自动绑定来自前端转来的值,如下图所示:

  

  2.5 查询主页Pages/Index 关键代码

<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>ID</th>
                <th>Name</th>
            </tr>
        </thead>
        <tbody>
            <!--Customers集合对象来自cs后端 -->
            @foreach (var contact in Model.Customers)
            {
                <tr>
                    <td>@contact.Id</td>
                    <td>@contact.Name</td>
                    <td>
                        <a asp-page="./Edit" asp-route-id="@contact.Id">edit</a>

                        <button type="submit" asp-page-handler="delete"
                                asp-route-id="@contact.Id">
                            delete
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <a asp-page="./Create">Create</a>
</form>
        public IList<Customer> Customers { get; private set; }

        //代替OnGet方法
        public async Task OnGetAsync()
        {
            //异步获取数据,EF上下文不跟踪该集合对象
            Customers = await _db.Customers.AsNoTracking().ToListAsync();
        }

    所有asp- 开头的都是TagHelper内置标记,查询如下图所示:

  2.6 修改页Pages/Edit关键代码

    在主页中(<a asp-page="./Edit" asp-route-id="@contact.Id">edit</a> )是导航到编辑页。例如:http://localhost:5000/Edit/1。

    第一行包含 @page "{id:int}" 指令,是用来路由约束,如果页面请求未包含可转换为 int 的路由数据,则运行时返回 HTTP 404。若要使 ID可选,请将 ? 追加到路由约束( @page "{id:int?}" )

@page "{id:int}"
@model StudyRazorDemo.Pages.EditModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h1>Edit Customer - @Model.Customer.Id</h1>

<form method="post">
    <!--验证失败时,提示所有错误信息 -->
    <div asp-validation-summary="All"></div>

    <input asp-for="Customer.Id" type="hidden" />
    <div>
        <label asp-for="Customer.Name"></label>
        <div>
            <input asp-for="Customer.Name" />

            <!--后端验证Name,当失败时提示错误信息 -->
            <span asp-validation-for="Customer.Name"></span>
        </div>
    </div>

    <div>
        <button type="submit">Save</button>
    </div>
</form>
        [BindProperty]
        public Customer Customer { get; set; }

        public async Task<IActionResult> OnGetAsync(int id)
        {
            Customer = await _db.Customers.FindAsync(id);

            if (Customer == null)
            {
                return RedirectToPage("/Index");
            }
            return Page();
        }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            _db.Attach(Customer).State = EntityState.Modified;

            try
            {
                await _db.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                throw new Exception($"Customer {Customer.Id} not found!");
            }

            return RedirectToPage("/Index");
        }

    通过ID来修改数据,如下图所示:

  2.7 删除 Pages/index

     删除动作是在index页面完成。使用处理事件asp-page-handler="delete" 来指定后端的action 为delete方法处理。 按照约定,方法命名为: OnPost[handler]Async ,方法参数为 asp-route-id传来的值。

        /// <summary>
        /// index后端,根据ID删除
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public async Task<IActionResult> OnPostDeleteAsync(int id)
        {
            var contact = await _db.Customers.FindAsync(id);

            if (contact != null)
            {
                _db.Customers.Remove(contact);
                await _db.SaveChangesAsync();
            }

            return RedirectToPage();
        }

  

 参考文献

  详细的razor教程

   razor 页面介绍

  

猜你喜欢

转载自www.cnblogs.com/MrHSR/p/10490918.html
今日推荐