从零开始进行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

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容