从零开始进行ABP项目开发(八) ——基于RazorPage的多页面应用

我们创建了项目ZL.Poem.WebApi用来向外界暴露Api,这个项目本身就是一个网站,这里我们在这个项目中增加一些页面,实现一些基本功能。我们使用Asp.Net Core引入的轻量级的页面技术RazorPage来实现这些功能。

RazorPage让我想起了WebForm的编程模型:前端页面和后端代码,也有MVC的痕迹,后端代码实际是前端视图的控制器和模型的集成。

创建基本页面

我们先在项目中创建Pages目录,然后创建两个Razor页面:

创建Razor页面

这两个页面分别为Index.cshtml和SearchPoet.cshtml。

项目结构

然后,我们在项目属性->调试中修改启动路径:

修改启动路径

修改为index,现在,启动项目,会发现起始页面已经是Index页面了。

简单的Index页面

为了说明Razor页面的工作过程,我们编写一个简单的功能:在页面中显示分类列表。

修改Index.cshtml.cs:

using System.Collections.Generic;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ZL.Poem.Application.Poems;

namespace ZL.Poem.WebApi.Pages
{
    public class IndexModel : PageModel
    {
        private IPoemAppService _appService;
        public List<CategoryDto> Categories;

        /// <summary>
        /// 这里通过依赖注入获取IPoemAppService
        /// </summary>
        /// <param name="appService"></param>
        public IndexModel(IPoemAppService appService)
        {
            _appService = appService;
        }

        /// <summary>
        /// 相应Get动作
        /// </summary>
        public void OnGet()
        {
            Categories=_appService.GetAllCategories();
        }
    }
}

代码很简单:1)增加了IndexModel的构造函数,目的是让依赖注入框架可以将IPoemAppService作为参数传入。2)增加了Categories列表,这是用来在页面上显示的数据。3)在OnGet中获取Categories列表。

页面代码也很简单:

@page
@model ZL.Poem.WebApi.Pages.IndexModel
@{
    ViewData["Title"] = "Index";
}

<h1>Index</h1>

<table class="table">
    <thead>
        <tr>
            <th>
                分类
            </th>
            
        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.Categories)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.CategoryName)
                </td>
                
            </tr>
        }
    </tbody>
</table>

与MVC的视图基本一样,采用Razor语法。这段代码很简单,就是显示分类列表。

简单的Razor页面

增加布局页面

现在我们为网站的视图页面增加模板页,这样就不需要为每个页面都设置相同的布局内容。首先,我们在Pages目录下创建Shared目录,然后增加一个Razor页面,命名为_Layout。请注意,在创建时,取消“生成PageModel”类的选项,这样就不会生成后台模型代码。

增加布局页面

页面代码如下:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewData["Title"]</title>
</head>
<body>
    @RenderBody()
</body>
</html>

然后在Pages目录中增加_ViewStart.cshtml,这个页面定义其它页面使用的模板页:

@{
    Layout = "_Layout";
}

还有页面_ViewImports.cshtml,这个页面定义其它页面需要的引用,这里我们需要引用TagHelpers:

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

增加诗人查询页面和诗查询页面

下面增加主要的两个页面,诗人查询和诗查询。

在Pages目录下增加一个Razor页面,命名为SearchPoet.cshtml,后台代码如下:

using Abp.Application.Services.Dto;
using Microsoft.AspNetCore.Mvc.RazorPages;
using ZL.Poem.Application.Poems;

namespace ZL.Poem.WebApi.Pages
{
    /// <summary>
    /// 诗人查询的后台代码
    /// </summary>
    public class SearchPoetModel : PageModel
    {
        /// <summary>
        /// 服务
        /// </summary>
        private IPoemAppService _appService;

        /// <summary>
        /// 查询结果
        /// </summary>
        public PagedResultDto<PoetDto> poetResults { get; set; }

        /// <summary>
        /// 当前的查询关键字
        /// </summary>
        public string CurrentFilter { get; set; }

        /// <summary>
        /// 每页显示条数
        /// </summary>
        public int PageSize { get; set; }

        /// <summary>
        /// 当前页面
        /// </summary>
        public int CurrentPage { get; set; }

        /// <summary>
        /// 这里通过依赖注入获取IPoemAppService
        /// </summary>
        /// <param name="appService"></param>
        public SearchPoetModel(IPoemAppService appService)
        {
            _appService = appService;
            PageSize = 20;
            CurrentPage = 0;
            CurrentFilter = "";
        }

        /// <summary>
        /// 响应Http Get
        /// </summary>
        /// <param name="SearchString">
        /// 查询的关键字
        /// </param>
        /// <param name="pageIndex">
        /// 页面Index
        /// </param>
        public void OnGet(string SearchString,int? pageIndex)
        {
            if (pageIndex.HasValue && pageIndex.Value>0)
            {
                CurrentPage = pageIndex.Value;
            }
            CurrentFilter = SearchString;
            var req = new SearchPoetDto
            {
                Keyword = CurrentFilter,
                SkipCount = CurrentPage * PageSize,
                MaxResultCount = PageSize
            };
            poetResults = _appService.SearchPoets(req);
        }
    }
}

代码比较简单:1)在构造函数中,通过依赖注入引入IPoemAppService。2)在OnGet中响应http的Get,通过传入的查询关键字和页面索引进行查询。

对应的cshtml代码:

@page
@model ZL.Poem.WebApi.Pages.SearchPoetModel
@{
    ViewData["Title"] = "诗人查询";
}

<h1>诗人查询</h1>

<form asp-page="./SearchPoet" method="get">
    <div class="form-actions no-color">
        <p>
            Find by name:
            <input type="text" name="SearchString" value="@Model.CurrentFilter" />
            <input type="submit" value="查询" class="btn btn-default" /> |
            <a asp-page="./SearchPoet">显示全部</a>
        </p>
    </div>
</form>

<table class="table">
    <thead>
        <tr>
            <th>
                姓名
            </th>

        </tr>
    </thead>
    <tbody>
        @foreach (var item in Model.poetResults.Items)
        {
            <tr>
                <td>
                    @Html.DisplayFor(modelItem => item.Name)
                </td>

            </tr>
        }
    </tbody>
</table>

@{
    var HasPreviousPage = Model.CurrentPage > 0;
    var HasNextPage = Model.CurrentPage * Model.PageSize < Model.poetResults.TotalCount;

    var prevDisabled = !HasPreviousPage ? "disabled" : "";
    var nextDisabled = !HasNextPage ? "disabled" : "";
}

@if (HasPreviousPage)
{
    <a asp-page="./SearchPoet"
       asp-route-pageIndex="@(Model.CurrentPage - 1)"
       asp-route-SearchString="@Model.CurrentFilter"
       class="btn btn-default @prevDisabled">
        前一页
    </a>
}
@if (HasNextPage)
{
    <a asp-page="./SearchPoet"
       asp-route-pageIndex="@(Model.CurrentPage + 1)"
       asp-route-SearchString="@Model.CurrentFilter"
       class="btn btn-default @nextDisabled">
        后一页
    </a>
}

诗的查询与此类似,这里不再列出。运行效果如下图:


没有样式的页面

从效果图上看,页面没有使用样式,下面,我们需要在页面中引入bootstrap和jquery等客户端库。

引入客户端库

在项目目录下,检查是否有wwwroot目录,如果没有,创建这个目录,并在目录下创建lib子目录,用来保存第三方库。


引入库

选择需要引入的库:


选项库

然后再_Layout.cshtml中增加对css文件和js文件的引用:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewData["Title"]</title>

    <environment names="Development,Production">
         <link href="~/lib/bootstrap/dist/css/bootstrap.css" rel="stylesheet" asp-append-version="true" />
    </environment>
</head>
<body>
    @RenderBody()

    <environment names="Development,Production">
        <script src="~/lib/jquery3.3.1/dist/jquery.min.js" asp-append-version="true"></script>
        <script src="~/lib/bootstrap/dist/js/bootstrap.js" asp-append-version="true"></script>
    </environment>
</body>
</html>

还有,就是需要注意,再Startup Configure中增加 app.UseStaticFiles();:

  public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {

            app.UseAbp();

            app.UseSwagger();
            //Enable middleware to serve swagger - ui assets(HTML, JS, CSS etc.)
            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Poem API V1");
            }); //URL: /swagger 


            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseHsts();
            }

            //使用静态文件
            app.UseStaticFiles();

            app.UseHttpsRedirection();
            app.UseMvc();

        }

到这里,我们完成了基于RazorPage的多页面客户端。接下来,我们编写基于单页面的客户端和基于Xamarin的移动客户端,来说明Web Api的使用。

本文同步发布在我的个人网站 http://www.jiagoushi.cn

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

推荐阅读更多精彩内容