惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
博客园_首页
雷峰网
雷峰网
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
WordPress大学
WordPress大学
腾讯CDC
T
Tailwind CSS Blog
A
About on SuperTechFans
H
Hackread – Cybersecurity News, Data Breaches, AI and More
The GitHub Blog
The GitHub Blog
T
The Blog of Author Tim Ferriss
G
Google Developers Blog
The Cloudflare Blog
D
DataBreaches.Net
Recent Announcements
Recent Announcements
Engineering at Meta
Engineering at Meta
B
Blog
博客园 - 聂微东
阮一峰的网络日志
阮一峰的网络日志
月光博客
月光博客
博客园 - 司徒正美
MongoDB | Blog
MongoDB | Blog
Google DeepMind News
Google DeepMind News
Apple Machine Learning Research
Apple Machine Learning Research

博客园 - HUGO.CM

安装OpenCode后,无法使用。解决方案 修改Abp中Auto API Controllers中 默认生成的 Put、Delete请求 vs2022 开发Python 中文报错:SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xc4 in position 0: invalid continuation byte Abp9.0.4运行DbMigrator,报错“The LINQ expression '@__organizationUnitIds_0' could not be translated. ...” 执行abp命令时,出现死循环解决方案 ABP与BootstrapBlazor 本地化相关处理 【机译】ABP Helper Methods Blazor文件上传异常:Did not receive any data in the allotted time Abp报错:AbpException: No theme registered! Use AbpThemingOptions to register themes. Abp分布式实体缓存 Abp vNext 在控制台输出SQL 【译】在 ABP 框架项目中配置多个数据库上下文 ABP浏览页面报错:Could not find the bundle file '/libs/abp/core/abp.css' for the bundle 'LeptonXLite.Global' 或 'Basic.Global' 运行abp install-libs再报错npm ERR! code E404 Abp配置文件设置IdentityServer客户端 精简版Abp开发教程 - 第二章: 创建实体与数据库 精简版Abp开发教程 - 第一章: 创建解决方案 Abp vNext 使用Mysql数据库 Abp vNext 修改默认表前缀 Abp vNext 使用sql2005、sql2008等脚本报错解决
精简版Abp开发教程 - 第三章: 创建应用程序
HUGO.CM · 2020-10-12 · via 博客园 - HUGO.CM

我们基于官方教程并结合下列教程,继续。

创建Book Dto

Acme.BookStore.Application.Contracts中添加BookDto.csCreateUpdateBookDto.cs

namespace Acme.BookStore.Application.Contracts.Dtos
{
    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; }
    }
}
namespace Acme.BookStore.Application.Contracts.Dtos
{
    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; }
    }
}

创建AutoMapper配置

Acme.BookStore.Application中添加BookStoreApplicationAutoMapperProfile.cs

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

创建服务接口

Acme.BookStore.Application.Contracts中添加IBookAppService.cs

namespace Acme.BookStore.Application.Contracts.IServices
{
    public interface IBookAppService :
        ICrudAppService< //定义CRUD方法
            BookDto, //用于展示
            Guid, //实体主键类型
            PagedAndSortedResultRequestDto, //用于分页
            CreateUpdateBookDto> //用于新增或修改
    {

    }
}

创建服务实现

Acme.BookStore.Application中添加BookAppService.cs

namespace Acme.BookStore.Application.Services
{
    public class BookAppService :
        CrudAppService<
            Book, //Book实体
            BookDto, //用于展示
            Guid, //实体主键类型
            PagedAndSortedResultRequestDto, //用于分页
            CreateUpdateBookDto>, //用于新增或修改
        IBookAppService //实现IBookAppService
    {
        public BookAppService(IRepository<Book, Guid> repository)
            : base(repository)
        {

        }
    }
}

创建Swagger API

改造Startup类

Acme.BookStore.WebApi中修改Startup.cs

namespace Acme.BookStore.WebApi
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplication<BookStoreWebApiModule>();//添加Application
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.InitializeApplication();//初始化Application
        }
    }
}

在Abp中,原本在Startup中的配置,全部搬到BookStoreWebApiModule中进行配置。
所以Startup最终就剩这几句代码。

编辑BookStoreWebApiModule类

Acme.BookStore.WebApi中添加BookStoreWebApiModule.cs

namespace Acme.BookStore.WebApi
{
    public class BookStoreWebApiModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            var hostingEnvironment = context.Services.GetHostingEnvironment();
            var configuration = context.Services.GetConfiguration();

            ConfigureAutoApiControllers();
            ConfigureSwaggerServices(context.Services);
        }

        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {
            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();

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

            app.UseSwagger();
            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Acme.BookStore.WebApi");
            });

            app.UseRouting();
            app.UseConfiguredEndpoints();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapGet("/", async context =>
                {
                    context.Response.Redirect("/swagger");
                });
            });
        }


        private void ConfigureAutoApiControllers()
        {
            Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                //自动创建Controller
                options.ConventionalControllers.Create(typeof(BookStoreApplicationModule).Assembly);
            });
        }


        private void ConfigureSwaggerServices(IServiceCollection services)
        {
            services.AddSwaggerGen(
                options =>
                {
                    options.SwaggerDoc("v1", new OpenApiInfo
                    { Title = "Acme.BookStore.WebApi", Version = "v1.0" });
                    options.DocInclusionPredicate((docName, description) => true);
                    options.CustomSchemaIds(type => type.FullName);
                }
            );
        }
    }
}

这里我们主要是重载2个方法ConfigureServicesOnApplicationInitialization方法。基本可以理解对应Startup的ConfigureServicesConfigure

Acme.BookStore.WebApi中编辑appsettings.json,添加数据库连接

{
    "Logging": {
        "LogLevel": {
            "Default": "Information",
            "Microsoft": "Warning",
            "Microsoft.Hosting.Lifetime": "Information"
        }
    },
    "AllowedHosts": "*",
    "ConnectionStrings": {
        "Default": "Server=(LocalDb)\\MSSQLLocalDB;Database=Acme.BookStore;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
}

有问题?

如果这时候我们运行Acme.BookStore.WebApi,发现报错了!我们该引用的都引用了,为什么还报错?
因为Abp是以Module来定义模块的。解决方案里各个项目层不都是创建了Module类并继承AbpModule吗?
如果你自己写的模块需要使用其他模块(依赖注入),那么须在Module类上添加DependsOn特性代码。不然基本会报错:Some services are not able to be constructed


namespace Acme.BookStore.WebApi
{
    [DependsOn(typeof(AbpAspNetCoreMvcModule),//用到Abp自动生成自动创建Controller方法
        typeof(BookStoreApplicationModule),//用到了Application层,提供服务
        typeof(BookStoreEntityFrameworkCoreModule))]//用到了数据库实现
    public class BookStoreWebApiModule : AbpModule
    {
       ...
    }
}

同理,其他项目中Module类是不是也应该添加DependsOn特性!
Acme.BookStore.Application中编辑BookStoreApplicationModule.cs

namespace Acme.BookStore.Application
{
    [DependsOn(typeof(AbpAutoMapperModule),
        typeof(BookStoreDomainModule),
        typeof(BookStoreApplicationContractsModule))]
    public class BookStoreApplicationModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<AbpAutoMapperOptions>(options =>
            {
                options.AddMaps<BookStoreApplicationModule>();
            });
        }
    }
}

除了添加DependsOn外,我们还得添加Map配置。options.AddMaps<BookStoreApplicationModule>();会去加载继承Profile的类。

Acme.BookStore.EntityFrameworkCore中编辑BookStoreEntityFrameworkCoreModule.cs

namespace Acme.BookStore.EntityFrameworkCore
{
    [DependsOn(typeof(BookStoreDomainModule),
        typeof(AbpEntityFrameworkCoreSqlServerModule))]
    public class BookStoreEntityFrameworkCoreModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.AddAbpDbContext<BookStoreDbContext>(options =>
            {
                options.AddDefaultRepositories();//添加Abp默认Repositories实现
            });

            Configure<AbpDbContextOptions>(options =>
            {
                options.UseSqlServer();//使用SqlServer数据库
            });
        }
    }
}

除了添加DependsOn外,我们还得配置数据库及数据仓库。

这时,再运行!发现swagger可以正常浏览了。我们测试一下Book添加方法(post /api/app/book)。先点Try it out按钮,再直接点击Execute按钮。
咦?报错了An internal error occurred during your request!
经过不停错误查找,原来是Acme.BookStore.ApplicationBookAppService所继承的CrudAppService中的ObjectMapper属性报错了。
CrudAppService自带的CreateAsync方法中代码使用ObjectMapper.Map<Book,BookDto>(input)
几经周折,发现需要使用Autofac才行。于是乎,在Acme.BookStore.WebApiProgram.cs添加UseAutofac(),代码如下:

namespace Acme.BookStore.WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                })
                .UseAutofac();
    }
}

这里添加完后,我们还得在Acme.BookStore.WebApiBookStoreWebApiModule添加AbpAutofacModule的依赖。

[DependsOn(typeof(AbpAutofacModule), 
        typeof(AbpAspNetCoreMvcModule),//用到Abp自动生成自动创建Controller方法
        typeof(BookStoreApplicationModule),//用到了Application层,提供服务
        typeof(BookStoreEntityFrameworkCoreModule))]//用到了数据库实现
    public class BookStoreWebApiModule : AbpModule
    {
        ...
    }

这时,再运行!发现swagger可以正常浏览了。我们测试一下Book添加方法(post /api/app/book)。先点Try it out按钮,再直接点击Execute按钮。
成功了!再试试其他方法,都返回正确结果。


至此Book应用程序创建成功。