Abp vnext Web应用程序开发教程 1 —— 创建服务器端

关于本教程

本教程基于版本3.1

在本教程系列中,您将构建一个名为Acme.BookStore的基于ABPWeb应用程序。该应用程序用于管理书籍及其作者的列表。它是使用以下技术开发的:

  • 实体框架核心作为ORM提供者。
  • MVC/Razor页面作为UI框架。

本教程分为以下部分:

第1部分:创建服务器端(此部分)

第2部分:图书列表页面

第3部分:创建、更新和删除书籍

第4部分:集成测试

第5部分:授权

第6部分:作者:领领域层

第7部分:作者:数据库集成

第8部分:作者:应用程序层

第9部分:作者:用户界面

第10部分:书与作者的关系

下载源代码

MVC (Razor Pages) UI with EF Core

创建解决方案

在开始开发之前,请按照入门教程来创建一个名为Acme.BookStore的新解决方案并运行它。

创建书籍实体

启动模板中的领域层分为两个项目:

  • Acme.BookStore.Domain包含您的实体领域服务和其他核心域对象。
  • Acme.BookStore.Domain.Shared包含constantsenums或其他领域相关的那些能够与客户共享的对象。

因此,在解决方案的领域层(Acme.BookStore.Domain项目)中定义您的实体。

应用程序的主要实体是Book。在Acme.BookStore.Domain项目中创建一个Books文件夹(命名空间),并在其中添加一个Book类:

using System;
using Volo.Abp.Domain.Entities.Auditing;

namespace Acme.BookStore.Books
{
    public class Book : AuditedAggregateRoot<Guid>
    {
        public string Name { get; set; }

        public BookType Type { get; set; }

        public DateTime PublishDate { get; set; }

        public float Price { get; set; }
    }
}
  • ABP框架为实体提供了两个基本基类:AggregateRootEntity聚合根域驱动设计概念,可以将其视为直接查询和使用的根实体(有关更多信息,请参见实体文档)。

  • Book从实体继承了AuditedAggregateRoot,其在AggregateRoot类的顶部添加了一些基本的审计属性(比如CreationTimeCreatorIdLastModificationTime…)。ABP会自动为您管理这些属性。

  • Guid主键类型Book实体。

为了简单起见,本教程将实体属性使用public get / set修饰。如果您了解有关DDD最佳做法的更多信息,请参见实体文档

BookType枚举

Book实体使用BookType枚举。在Acme.BookStore.Domain.Shared项目中创建一个Books文件夹(命名空间)并在其中添加一个BookType内部文件:

namespace Acme.BookStore.Books
{
    public enum BookType
    {
        Undefined,
        Adventure,
        Biography,
        Dystopia,
        Fantastic,
        Horror,
        Science,
        ScienceFiction,
        Poetry
    }
}

最终的文件夹/文件结构应如下所示:

在这里插入图片描述

将图书实体添加到DbContext

EF Core要求将实体与您的DbContext关联。最简单的方法是在Acme.BookStore.EntityFrameworkCore项目的BookStoreDbContext类中添加一个DbSet属性,如下所示:

public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
{
    public DbSet<Book> Books { get; set; }
    //...
}

将图书实体映射到数据库表

Acme.BookStore.EntityFrameworkCore项目中打开BookStoreDbContextModelCreatingExtensions.cs文件,然后添加Book实体的映射代码。最终类应为:

using Acme.BookStore.Books;
using Microsoft.EntityFrameworkCore;
using Volo.Abp;
using Volo.Abp.EntityFrameworkCore.Modeling;

namespace Acme.BookStore.EntityFrameworkCore
{
    public static class BookStoreDbContextModelCreatingExtensions
    {
        public static void ConfigureBookStore(this ModelBuilder builder)
        {
            Check.NotNull(builder, nameof(builder));

            /* Configure your own tables/entities inside here */

            builder.Entity<Book>(b =>
            {
                b.ToTable(BookStoreConsts.DbTablePrefix + "Books",
                          BookStoreConsts.DbSchema);
                b.ConfigureByConvention(); //auto configure for the base class props
                b.Property(x => x.Name).IsRequired().HasMaxLength(128);
            });
        }
    }
}
  • BookStoreConsts含有用于表的架构和表前缀的常量值。您不必使用它,但是建议您在单点中控制表前缀。

  • ConfigureByConvention()方法优雅地配置/映射继承的属性。始终将其用于所有实体。

添加数据库迁移

启动模板使用EF Core Code First Migrations来创建和维护数据库架构。在菜单工具> NuGet软件包管理器下,打开软件包管理器控制台(PMC)
在这里插入图片描述

选择Acme.BookStore.EntityFrameworkCore.DbMigrations作为默认项目并执行以下命令:

Add-Migration "Created_Book_Entity"

在这里插入图片描述

这将在Acme.BookStore.EntityFrameworkCore.DbMigrations项目的Migrations文件夹内创建一个新的迁移类。

在更新数据库之前,请阅读以下部分,以了解如何将一些初始数据插入到数据库中。

如果使用的不是Visual Studio,则可以使用此处文档中dotnet-ef工具。

添加样本种子数据

在运行应用程序之前,最好在数据库中包含一些初始数据。本节介绍ABP框架的数据种子系统。如果您不想创建种子数据,则可以跳过本节,但是建议您遵循它来学习此有用的ABP Framework功能。

创建一个从*.Domain项目中的IDataSeedContributor派生的类,并复制以下代码:

using System;
using System.Threading.Tasks;
using Acme.BookStore.Books;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Domain.Repositories;

namespace Acme.BookStore
{
    public class BookStoreDataSeederContributor
        : IDataSeedContributor, ITransientDependency
    {
        private readonly IRepository<Book, Guid> _bookRepository;

        public BookStoreDataSeederContributor(IRepository<Book, Guid> bookRepository)
        {
            _bookRepository = bookRepository;
        }

        public async Task SeedAsync(DataSeedContext context)
        {
            if (await _bookRepository.GetCountAsync() <= 0)
            {
                await _bookRepository.InsertAsync(
                    new Book
                    {
                        Name = "1984",
                        Type = BookType.Dystopia,
                        PublishDate = new DateTime(1949, 6, 8),
                        Price = 19.84f
                    },
                    autoSave: true
                );

                await _bookRepository.InsertAsync(
                    new Book
                    {
                        Name = "The Hitchhiker's Guide to the Galaxy",
                        Type = BookType.ScienceFiction,
                        PublishDate = new DateTime(1995, 9, 27),
                        Price = 42.0f
                    },
                    autoSave: true
                );
            }
        }
    }
}

如果数据库中当前没有书,则此代码仅使用IRepository<Book, Guid>(默认存储库)将两本书插入数据库。

更新数据库

运行Acme.BookStore.DbMigrator应用程序以更新数据库:
在这里插入图片描述

.DbMigrator是一个控制台应用程序,可以运行该应用程序以迁移数据库架构并将数据植入开发生产环境中。

创建应用程序服务

应用程序层分为两个项目:

  • Acme.BookStore.Application.Contracts包含您的DTO应用程序服务接口。
  • Acme.BookStore.Application 包含您的应用程序服务的实现。

在本部分中,您将创建一个应用程序服务,以使用ABP框架的CrudAppService基类来get, create, update和delete书籍。

BookDto

CrudAppService基类需要定义实体的基本DTO。在Acme.BookStore.Application.Contracts项目中创建一个Books文件夹(命名空间),并在其中添加一个BookDto类:

using System;
using Volo.Abp.Application.Dtos;

namespace Acme.BookStore.Books
{
    public class BookDto : AuditedEntityDto<Guid>
    {
        public string Name { get; set; }

        public BookType Type { get; set; }

        public DateTime PublishDate { get; set; }

        public float Price { get; set; }
    }
}
  • DTO类用于在表示层和应用程序层之间传输数据。有关更多详细信息,请参见数据传输对象文档

  • BookDto 用于将书籍数据传输到表示层,以便在UI上显示书籍信息。

  • BookDto派生自AuditedEntityDto<Guid>,其具有与上面定义的Book实体一样的审计属性。

在将书籍返回到表示层时,需要将Book实体映射到BookDto对象。当您定义正确的映射时,AutoMapper库可以自动执行此转换。启动模板带有预先配置的AutoMapper。因此,您只需在Acme.BookStore.Application项目的BookStoreApplicationAutoMapperProfile类中定义映射即可:

using Acme.BookStore.Books;
using AutoMapper;

namespace Acme.BookStore
{
    public class BookStoreApplicationAutoMapperProfile : Profile
    {
        public BookStoreApplicationAutoMapperProfile()
        {
            CreateMap<Book, BookDto>();
        }
    }
}

有关详细信息,请参见对象到对象映射文档。

CreateUpdateBookDto

Acme.BookStore.Application.Contracts项目的Books文件夹(命名空间)中创建一个CreateUpdateBookDto类:

using System;
using System.ComponentModel.DataAnnotations;

namespace Acme.BookStore.Books
{
    public class CreateUpdateBookDto
    {
        [Required]
        [StringLength(128)]
        public string Name { get; set; }

        [Required]
        public BookType Type { get; set; } = BookType.Undefined;

        [Required]
        [DataType(DataType.Date)]
        public DateTime PublishDate { get; set; } = DateTime.Now;

        [Required]
        public float Price { get; set; }
    }
}
  • DTO类用于在创建或更新书籍时从用户界面获取书籍信息。

  • 它定义了数据注释属性(如[Required])来定义属性的验证。DTO会由ABP框架自动验证

就像上面BookDto所做的一样,我们应该定义从CreateUpdateBookDto对象到Book实体的映射。最终类如下所示:

using Acme.BookStore.Books;
using AutoMapper;

namespace Acme.BookStore
{
    public class BookStoreApplicationAutoMapperProfile : Profile
    {
        public BookStoreApplicationAutoMapperProfile()
        {
            CreateMap<Book, BookDto>();
            CreateMap<CreateUpdateBookDto, Book>();
        }
    }
}

IBookAppService

下一步是为应用程序服务定义接口。在Acme.BookStore.Application.Contracts项目的Books文件夹(命名空间)中创建一个IBookAppService接口:

using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;

namespace Acme.BookStore.Books
{
    public interface IBookAppService :
        ICrudAppService< //Defines CRUD methods
            BookDto, //Used to show books
            Guid, //Primary key of the book entity
            PagedAndSortedResultRequestDto, //Used for paging/sorting
            CreateUpdateBookDto> //Used to create/update a book
    {

    }
}
  • 框架不需要为应用程序服务定义接口。但是,建议将其作为最佳实践。

  • ICrudAppService定义了通用CRUD方法:GetAsyncGetListAsyncCreateAsyncUpdateAsyncDeleteAsync。不需要扩展它。相反,您可以从空IApplicationService接口继承并手动定义自己的方法(将在下一部分为作者完成)。

  • ICrudAppService中有一些变体,你可以在每个方法中使用单独的DTO,也可以分别单独指定(例如使用不同的DTO进行创建和更新)。

BookAppService

现在是实现IBookAppService接口的时候了。创建一个新类,在Acme.BookStore.Application项目的Books命名空间(文件夹)中命名BookAppService

using System;
using Volo.Abp.Application.Dtos;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;

namespace Acme.BookStore.Books
{
    public class BookAppService :
        CrudAppService<
            Book, //The Book entity
            BookDto, //Used to show books
            Guid, //Primary key of the book entity
            PagedAndSortedResultRequestDto, //Used for paging/sorting
            CreateUpdateBookDto>, //Used to create/update a book
        IBookAppService //implement the IBookAppService
    {
        public BookAppService(IRepository<Book, Guid> repository)
            : base(repository)
        {

        }
    }
}
  • BookAppService派生自CrudAppService<...>,它实现由ICrudAppService定义的所有CRUD(创建,读取,更新,删除)方法。

  • BookAppService注入IRepository<Book, Guid>,这是Book实体的默认存储库。ABP自动为每个聚合根(或实体)创建默认存储库。请参阅存储库文档

  • BookAppService使用IObjectMapper服务(请参考)将Book对象映射到BookDto对象以及将Book对象映射到CreateUpdateBookDto对象。启动模板使用AutoMapper库作为对象映射提供程序。我们之前已经定义了映射,因此它将按预期工作。

自动API控制器

在典型的ASP.NET Core应用程序中,您创建API控制器以将应用程序服务公开为HTTP API端点。这允许浏览器或第三方客户端通过HTTP调用它们。

ABP可以按照约定自动将您的应用程序服务配置为MVC API控制器。

Swagger UI

启动模板配置为使用Swashbuckle.AspNetCore库运行Swagger UI。通过在浏览器上按CTRL+F5并导航到https://localhost:<port>/swagger/来运行该应用程序。(替换<port>为您自己的端口号。)

您将看到一些内置服务端点以及该Book服务及其REST样式端点:
在这里插入图片描述

Swagger有一个不错的接口来测试API。

如果您尝试执行[GET] /api/app/bookAPI以获取书籍列表,则服务器会返回这样的JSON结果:

{
  "totalCount": 2,
  "items": [
    {
      "name": "The Hitchhiker's Guide to the Galaxy",
      "type": 7,
      "publishDate": "1995-09-27T00:00:00",
      "price": 42,
      "lastModificationTime": null,
      "lastModifierId": null,
      "creationTime": "2020-07-03T21:04:18.4607218",
      "creatorId": null,
      "id": "86100bb6-cbc1-25be-6643-39f62806969c"
    },
    {
      "name": "1984",
      "type": 3,
      "publishDate": "1949-06-08T00:00:00",
      "price": 19.84,
      "lastModificationTime": null,
      "lastModifierId": null,
      "creationTime": "2020-07-03T21:04:18.3174016",
      "creatorId": null,
      "id": "41055277-cce8-37d7-bb37-39f62806960b"
    }
  ]
}

这很酷,因为我们没有编写任何代码来创建API控制器,但是现在我们有了一个可以正常使用的REST API

下一部分

请参阅本教程的下一部分

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Abp VNext是一个开源的应用框架,它提供了一种快速构建现代化、模块化和可扩展的企业级应用程序的方式。在Abp VNext中,前后的分离是一种常见的项目实践方式,它可以提供更好的团队协作、灵活性和可维护性。 下面是一些Abp VNext前后分离项目实践的建议: 1. 前后分离架构:在Abp VNext中,可以使用前后分离的架构来开发应用程序。前部分可以使用任何流行的前框架,如Angular、React或Vue.js。后部分则使用Abp VNext提供的后框架。 2. API接口设计:在前后分离项目中,需要定义清晰的API接口,以便前后开发人员可以进行协作。可以使用Swagger等工具来自动生成API文档,并确保接口的一致性和易用性。 3. 跨域支持:由于前后分离项目中前和后运行在不同的域名或口上,因此需要配置跨域支持。在Abp VNext中,可以使用CorsPolicy来配置跨域访问权限。 4. 认证和授权:在前后分离项目中,需要考虑用户认证和授权的问题。Abp VNext提供了强大的身份验证和授权功能,可以轻松地集成到前后分离项目中。 5. 模块化开发Abp VNext支持模块化开发,可以将功能模块拆分为独立的模块,以便不同的团队可以并行开发。前后分离项目中,可以将前和后的模块进行对应,实现更好的解耦和扩展性。 6. 前后协作:在前后分离项目中,前后开发人员需要进行紧密的协作。可以使用版本控制工具如Git来管理代码,并使用项目管理工具如Jira来进行任务管理和进度跟踪。 以上是Abp VNext前后分离项目实践的一些建议,希望对你有帮助!如果你有其他问题,请随时提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值