ABP 上的应用程序服务 URL 映射

Application service URL mapping on ABP

我是ABP新手,我this oficial tutorial成功了。

然后我添加了另一个 class (Planta) 并再次按照教程进行操作(没有删除 The Book class),但即使我可以创建 table并在其上提供数据(已验证),应用程序无法加载 table,当我检查 swagger 时,我发现了这个...

我原以为它是 Planta 而不是 BookAppServicePlanta,但我找不到哪里搞砸了。


我尝试解决的问题


这是我所做的(详情如下):

  1. 我在 Acme.BookStore.Domain/Planta/Planta.cs 上创建了 class 植物群:
  2. 将实体添加到 Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs
  3. 将实体映射到 Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContextModelCreatingExtensions.cs
  4. 上的 table
  5. 删除了数据库,并删除了以前的迁移
  6. 创建了数据播种器Acme.BookStore.Domain/BookStoreDataSeederContributor_Plant.cs
  7. 添加了新的迁移,并且 运行 Acme.BookStore.DbMigrator
  8. 已创建Acme.BookStore.Application.Contracts/PlantDto.cs
  9. 已将其添加到 Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs
  10. 创建了 Acme.BookStore.Application.Contracts/CreateUpdatePlantDto.cs(并将其也添加到自动映射器中,如 8 所示))
  11. 创建界面Acme.BookStore.Application.Contracts/IBookAppServicePlanta.cs
  12. 已在 Acme.BookStore.Application/BookAppServicePlanta.cs
  13. 上实施
  14. 运行 申请

额外信息: 我为 Planta 及其表单创建了页面(教程第 2 部分和第 3 部分),但即使我仔细检查了这些文件,我也不相信问题出在这些文件上,因为 swagger 问题。


  1. 我在 Acme.BookStore.Domain/Planta/Planta.cs 上创建了 class 植物群:

     using System;
     using Volo.Abp.Domain.Entities.Auditing;
    
     namespace Acme.BookStore.Plantas
     {
         public class Planta : AuditedAggregateRoot<Guid>
         {
             public string Nombre { get; set; }
             public string Descripcion { get; set; }
             public string Dirección { get; set; }
             public string Lat { get; set; }
             public string Long { get; set; }
             public string Extra1 { get; set; }
             public string Extra2 { get; set; }
             public string Extra3 { get; set; }
    
         }
     }
    
  2. 将实体添加到 Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContext.cs

     using Microsoft.EntityFrameworkCore;
     using Acme.BookStore.Users;
     using Volo.Abp.Data;
     using Volo.Abp.EntityFrameworkCore;
     using Volo.Abp.EntityFrameworkCore.Modeling;
     using Volo.Abp.Identity;
     using Volo.Abp.Users.EntityFrameworkCore;
     using Acme.BookStore.Books;
     using Acme.BookStore.Plantas;
    
     namespace Acme.BookStore.EntityFrameworkCore
     {
         /* This is your actual DbContext used on runtime.
          * It includes only your entities.
          * It does not include entities of the used modules, because each module has already
          * its own DbContext class. If you want to share some database tables with the used modules,
          * just create a structure like done for AppUser.
          *
          * Don't use this DbContext for database migrations since it does not contain tables of the
          * used modules (as explained above). See BookStoreMigrationsDbContext for migrations.
          */
         [ConnectionStringName("Default")]
         public class BookStoreDbContext : AbpDbContext<BookStoreDbContext>
         {
             public DbSet<AppUser> Users { get; set; }
             public DbSet<Book> Books { get; set; }
             public DbSet<Planta> Plantas { get; set; }
    
             /* Add DbSet properties for your Aggregate Roots / Entities here.
              * Also map them inside BookStoreDbContextModelCreatingExtensions.ConfigureBookStore
              */
    
             public BookStoreDbContext(DbContextOptions<BookStoreDbContext> options)
                 : base(options)
             {
    
             }
    
             protected override void OnModelCreating(ModelBuilder builder)
             {
                 base.OnModelCreating(builder);
    
                 /* Configure the shared tables (with included modules) here */
    
                 builder.Entity<AppUser>(b =>
                 {
                     b.ToTable(AbpIdentityDbProperties.DbTablePrefix + "Users"); //Sharing the same table "AbpUsers" with the IdentityUser
    
                     b.ConfigureByConvention();
                     b.ConfigureAbpUser();
    
                     /* Configure mappings for your additional properties
                      * Also see the BookStoreEfCoreEntityExtensionMappings class
                      */
                 });
    
                 /* Configure your own tables/entities inside the ConfigureBookStore method */
    
                 builder.ConfigureBookStore();
             }
         }
     }
    
  3. 将实体映射到 Acme.BookStore.EntityFrameworkCore/EntityFrameworkCore/BookStoreDbContextModelCreatingExtensions.cs

    上的 table
     using Acme.BookStore.Books;
     using Acme.BookStore.Plantas;
     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);
                 });
    
                 builder.Entity<Planta>(p =>
                 {
                     p.ToTable(BookStoreConsts.DbTablePrefix + "Plantas",
                               BookStoreConsts.DbSchema);
                     p.ConfigureByConvention(); //auto configure for the base class props
                     p.Property(y => y.Nombre).IsRequired().HasMaxLength(128);
                 });
             }
         }
     }
    
  4. 删除了数据库,并删除了以前的迁移

  5. 创建了数据播种器Acme.BookStore.Domain/BookStoreDataSeederContributor_Plant.cs

     using System;
     using System.Threading.Tasks;
     using Acme.BookStore.Plantas;
     using Volo.Abp.Data;
     using Volo.Abp.DependencyInjection;
     using Volo.Abp.Domain.Repositories;
    
     namespace Acme.BookStore
     {
         public class BookStoreDataSeederContributor_Plant
             : IDataSeedContributor, ITransientDependency
         {
             private readonly IRepository<Planta, Guid> _plantaRepository;
    
             public BookStoreDataSeederContributor_Plant(IRepository<Planta, Guid> plantaRepository)
             {
                 _plantaRepository = plantaRepository;
             }
    
             public async Task SeedAsync(DataSeedContext context)
             {
                 if (await _plantaRepository.GetCountAsync() > 0)
                 {
                     return;
                 }
    
                 await _plantaRepository.InsertAsync(
                     new Planta
                     {
                         Nombre = "Armijo Guajardo",
                         Descripcion = "excel god",
                         Dirección = "las lilas 123",
                         Lat = "564.765.98",
                         Long  = "100.102.04",
                         Extra1 = "bla",
                         Extra2 = "bla bla",
                         Extra3 = "bla bla bla"
                     },
                     autoSave: true
                 );
             }
         }
     }
    
  6. 添加了一个新的迁移,并且运行 Acme.BookStore.DbMigrator

  7. 已创建Acme.BookStore.Application.Contracts/PlantDto.cs

     using System;
     using Volo.Abp.Application.Dtos;
    
     namespace Acme.BookStore.Plantas
     {
         public class PlantDto : AuditedEntityDto<Guid>
         {
             public string Nombre { get; set; }
             public string Descripcion { get; set; }
             public string Dirección { get; set; }
             public string Lat { get; set; }
             public string Long { get; set; }
             public string Extra1 { get; set; }
             public string Extra2 { get; set; }
             public string Extra3 { get; set; }
         }
     }
    
  8. 添加到 Acme.BookStore.Application/BookStoreApplicationAutoMapperProfile.cs

     using Acme.BookStore.Books;
     using Acme.BookStore.Plantas;
     using AutoMapper;
    
     namespace Acme.BookStore
     {
         public class BookStoreApplicationAutoMapperProfile : Profile
         {
             public BookStoreApplicationAutoMapperProfile()
             {
                 CreateMap<Book, BookDto>();
                 CreateMap<CreateUpdateBookDto, Book>();
                 CreateMap<Planta, PlantDto>();
                 CreateMap<CreateUpdatePlantDto, Planta>();
             }
         }
     }
    
  9. 创建了 Acme.BookStore.Application.Contracts/CreateUpdatePlantDto.cs(并将其添加到自动映射器中,如 8 所示))

     using System;
     using System.ComponentModel.DataAnnotations;
    
     namespace Acme.BookStore.Plantas
     {
         public class CreateUpdatePlantDto
         {
             [Required]
             [StringLength(128)]
             public string Nombre { get; set; }
    
             [Required]
             [StringLength(128)]
             public string Descripcion { get; set; }
    
             [Required]
             [StringLength(128)]
             public string Dirección { get; set; }
             [Required]
    
             [StringLength(128)]
             public string Lat { get; set; }
    
             [Required]
             [StringLength(128)]
             public string Long { get; set; }
    
             [Required]
             [StringLength(128)]
             public string Extra1 { get; set; }
    
             [Required]
             [StringLength(128)]
             public string Extra2 { get; set; }
    
             [Required]
             [StringLength(128)]
             public string Extra3 { get; set; }
         }
     }
    
  10. 创建了界面Acme.BookStore.Application.Contracts/IBookAppServicePlanta.cs

    using System;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.Application.Services;
    
    namespace Acme.BookStore.Plantas
    {
        public interface IBookAppServicePlanta :
            ICrudAppService< //Defines CRUD methods
                PlantDto, //Used to show books
                Guid, //Primary key of the book entity
                PagedAndSortedResultRequestDto, //Used for paging/sorting
                CreateUpdatePlantDto> //Used to create/update a book
        {
    
        }
    }
    
  11. 已在 Acme.BookStore.Application/BookAppServicePlanta.cs

    上实施
    using System;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.Application.Services;
    using Volo.Abp.Domain.Repositories;
    
    
    namespace Acme.BookStore.Plantas
    {
        public class BookAppServicePlanta :
            CrudAppService<
                Planta, //The Book entity
                PlantDto, //Used to show books
                Guid, //Primary key of the book entity
                PagedAndSortedResultRequestDto, //Used for paging/sorting
                CreateUpdatePlantDto>, //Used to create/update a book
            IBookAppServicePlanta //implement the IBookAppService
        {
            public BookAppServicePlanta(IRepository<Planta, Guid> repository)
                : base(repository)
            {
    
            }
        }
    }
    
  12. 运行 申请


[编辑]

Acme.BookStore.Web/BookStoreWebAutoMapperProfile.cs 看起来像这样

    using Acme.BookStore.Books;
    using Acme.BookStore.Plantas;
    using AutoMapper;

    namespace Acme.BookStore.Web
    {
        public class BookStoreWebAutoMapperProfile : Profile
        {
            public BookStoreWebAutoMapperProfile()
            {
                CreateMap<BookDto, CreateUpdateBookDto>();
                CreateMap<PlantDto, CreateUpdatePlantDto>();
            }
        }
    }

[编辑] 我创建了一个teting文件Acme.BookStore.Application.Tests/BookAppServicePlanta_test.cs,他们都成功了。

    using System;
    using System.Linq;
    using System.Threading.Tasks;
    using Shouldly;
    using Volo.Abp.Application.Dtos;
    using Volo.Abp.Validation;
    using Xunit;

    namespace Acme.BookStore.Plantas
    {
        public class BookAppService_Tests : BookStoreApplicationTestBase
        {
            private readonly IBookAppServicePlanta _plantaAppService;

            public BookAppService_Tests()
            {
                _plantaAppService = GetRequiredService<IBookAppServicePlanta>();
            }

            [Fact]
            public async Task Should_Get_List_Of_Books()
            {
                //Act
                var result = await _plantaAppService.GetListAsync(
                    new PagedAndSortedResultRequestDto()
                );

                //Assert
                result.TotalCount.ShouldBeGreaterThan(0);
                result.Items.ShouldContain(b => b.Nombre == "Armijo Guajardo");
            }

            [Fact]
            public async Task Should_Create_A_Valid_Planta()
            {
                //Act
                var result = await _plantaAppService.CreateAsync(
                    new CreateUpdatePlantDto
                    {
                        Nombre = "Pedro Cano",
                        Descripcion = "Cirujano",
                        Dirección = "Pedro de Valdivia",
                        Lat = "123213213",
                        Long = "456456456",
                        Extra1 = "emmmm",
                        Extra2 = "no se",
                        Extra3 = "que poner"
                    }
                );

                //Assert
                result.Id.ShouldNotBe(Guid.Empty);
                result.Nombre.ShouldBe("Pedro Cano");
            }
            [Fact]
            public async Task Should_Not_Create_A_Planta_Without_Name()
            {
                var exception = await Assert.ThrowsAsync<AbpValidationException>(async () =>
                {
                    await _plantaAppService.CreateAsync(
                        new CreateUpdatePlantDto
                        {
                            Descripcion = "Cirujano",
                            Dirección = "Pedro de Valdivia",
                            Lat = "123213213",
                            Long = "456456456",
                            Extra1 = "emmmm",
                            Extra2 = "no se",
                            Extra3 = "que poner"
                        }
                    );
                });
                exception.ValidationErrors
                    .ShouldContain(err => err.MemberNames.Any(mem => mem == "Nombre"));
                }
        }
    }

我对 ABP 不熟悉,但是快速查看文档,您似乎没有遵循命名约定。

应用程序服务应遵循以下命名约定:EntityAppService

但您似乎 copied/pasted 之前的 class BookAppService 只是在末尾添加了 Planta。它应该是 PlantaAppService 而不是。

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

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

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


namespace Acme.BookStore.Plantas
{
    public class PlantaAppService:
        CrudAppService<
            Planta, //The Book entity
            PlantDto, //Used to show books
            Guid, //Primary key of the book entity
            PagedAndSortedResultRequestDto, //Used for paging/sorting
            CreateUpdatePlantDto>, //Used to create/update a book
        IPlantaAppService //implement the IPlantaAppService
    {
        public BookAppServicePlanta(IRepository<Planta, Guid> repository)
            : base(repository)
        {

        }
    }
}