ABP框架基本使用

2,642 阅读8分钟

ABP框架

中文文档

号称是C#中的springboot。

abp.io/

Gthub开源地址

ABP框架是遵循DDD原则和模式去实现分层应用程序模型,目前ASP.NET Core最流行的框架。ABP是DDD的最佳实践

ABP是一个比较重的框架,东西很多

ABP vNext是ASP.NET Core的开源WEB应用程序框架,就是再封装一层,扩展了一系列的封装,完成了很多通用的。

ABP是用于创建现代Web应用程序的完整架构和强大的基础设施! 遵循最佳实践和约定,为你提供SOLID开发经验

下载运行示例项目

方式一:直接在官网建,会下载项目压缩包

方式二:cmd命令行使用cli工具

注意,要自己手动创建一个项目文件夹

//安装cli工具
dotnet tool install -g Volo.Abp.Cli
//创建解决方案Acme.BookStore
abp new Acme.BookStore

方式三:在github上下载项目

1、访问Github,找到项目,下载源码

2、修改配置的连接字符串,并将其设为启动项目,启动项目会完成数据库的初始化。会运行迁移命令,创建种子数据。刷新数据库,会发现生成了一堆表

DbMigrator是一个控制台

3、修改web项目的数据库连接字符串,并设为控制台启动

4、使用账号密码登录,就可以进行增删改查

账号 admin,密码 1q2w3E*

从0集成ABP vNext

1、新建一个webapi项目,选择.net5,建好之后再改成.net6。

选择.net5跟ABP vNext集成更简单

2、安装包

3 通过AppModule来配置和启动程序

新建类

集成AbpModule,实现模块化

[DependsOn(typeof(AbpAspNetCoreMvcModule))]//DependsOn配置,配置AddControllers
[DependsOn(typeof(BasicProjectApplicationModule))]//必须添加这行,才能完成BasicProjectApplicationModule的服务自注册
public class BaseProjectWebModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //ioc配置
            context.Services.AddSwaggerGen(
               options =>
               {
                   options.SwaggerDoc("v1", new OpenApiInfo { Title = "BasicMVC API", Version = "v1" });
                   options.DocInclusionPredicate((docName, description) => true);
                   options.CustomSchemaIds(type => type.FullName);
               }
           );

            //配置options--初始化配置
            base.Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                options.ConventionalControllers
                    .Create(typeof(BasicProjectApplicationModule).Assembly);
            });


            //context.Services.AddTransient<IUserAppService, UserAppService>();
        }


        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {

            var app = context.GetApplicationBuilder();
            var env = context.GetEnvironment();

            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
            }

            app.UseStaticFiles();
            app.UseRouting();

            #region 配置swagger
            app.UseSwagger();
            app.UseSwaggerUI(options =>
            {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "BasicMVC API");
            });
            #endregion
        	//终结点变为ABP的了
            app.UseConfiguredEndpoints();

        }

    }

将管道模型的配置交给ABP

public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddApplication<BaseProjectWebModule>();//把IOC注册也交给ABP

            //services.AddControllers();
            //services.AddSwaggerGen(c =>
            //{
            //    c.SwaggerDoc("v1", new OpenApiInfo { Title = "Zhaoxi.BasicProject.Web", Version = "v1" });
            //});
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.InitializeApplication();//管道模型的配置交给了ABP

            //if (env.IsDevelopment())
            //{
            //    app.UseDeveloperExceptionPage();
            //    app.UseSwagger();
            //    app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Zhaoxi.BasicProject.Web v1"));
            //}

            //app.UseHttpsRedirection();

            //app.UseRouting();

            //app.UseAuthorization();

            //app.UseEndpoints(endpoints =>
            //{
            //    endpoints.MapControllers();
            //});
        }
    }

使用Autofac容器

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()//用autofac替换默认容器
            ;
    }

添加两个应用层类库(一个抽象,一个实现)

抽象

public interface IUserAppService
    {
        Task<UserDto> GetUserAsync(int id);
        Task<IEnumerable<UserDto>> GetUserListAsync();
    }

dto

public class UserDto
    {
        public int Id { get; set; }
        public string? UserName { get; set; }
        public string? Password { get; set; }
        public string? Email { get; set; }

    }

实现

public class UserAppService : IUserAppService
    , IRemoteService//空接口,标记后才能被发现为auto api controller
    , ITransientDependency//标记后就能被autofac自动注册
    //,IApplicationService
    {
        public async Task<UserDto> GetUserAsync(int id)
        {
            await Task.CompletedTask;
            return new UserDto()
            {
                Id = id,
                UserName = "小龙",
                Email = "57265177@qq.com",
                Password = "111111"
            };
        }

        public async Task<IEnumerable<UserDto>> GetUserListAsync()
        {
            await Task.CompletedTask;
            return new List<UserDto>(){
                new UserDto()
            {
                Id = 1,
                UserName = "小龙",
                Email = "57265177@qq.com",
                Password = "111111"
            }
            };
        }
    }

传统使用写法

不要这样写,这框架不是这么玩的

注册

public override void ConfigureServices(ServiceConfigurationContext context)
        {
            //ioc配置
            context.Services.AddSwaggerGen(
               options =>
               {
                   options.SwaggerDoc("v1", new OpenApiInfo { Title = "BasicMVC API", Version = "v1" });
                   options.DocInclusionPredicate((docName, description) => true);
                   options.CustomSchemaIds(type => type.FullName);
               }
           );

            //配置options--初始化配置
            base.Configure<AbpAspNetCoreMvcOptions>(options =>
            {
                options.ConventionalControllers
                    .Create(typeof(BasicProjectApplicationModule).Assembly);
            });

        	//添加下面这行注册
            context.Services.AddTransient<IUserAppService, UserAppService>();
        }

使用

[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;
    private readonly IUserAppService _IUserAppService = null;


    public WeatherForecastController(ILogger<WeatherForecastController> logger
         , IUserAppService userAppService
        )
    {
        _logger = logger;
        this._IUserAppService = userAppService;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
    	//先注入再使用
        Console.WriteLine(JsonConvert.SerializeObject(this._IUserAppService.GetUserAsync(1).Result));

        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

标准玩法--模块自注册

不要再UI层完成模块的注册

1、添加抽象类

public class BasicProjectApplicationContractsModule : AbpModule
    {

    }

实现类

[DependsOn(typeof(BasicProjectApplicationContractsModule))]//实例的要依赖于抽象的module
public class BasicProjectApplicationModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
    	//还有更简单的注册方式	
    	//用ITransientDependency表示UserService
        context.Services.AddTransient<IUserAppService, UserAppService>();
    }

}

Abp开发中所有类库必须实现类库AbpModule

1 添加抽象---实现类库

2 添加Module—这是规范,是必须的

3 模块初始化IOC注册

4 Web模块化DependsOn

5 注入使用---Add---接口ITransientDependency--- Dependency特性

创建一个 ABP 项目

1、安装abp cli

dotnet tool install -g Volo.Abp.Cli

如果已安装, 则可以使用以下命令对其进行更新:

dotnet tool update -g Volo.Abp.Cli

2、创建新项目

cmd命令行移动到项目文件夹,运行命令

abp new Acme.BookStore

3、修改数据库连接字符串

Data Source=LAPTOP-RV9GJL14;Database=VeloAbpDemo;Integrated Security=False;Connect Timeout=30;User Id =velo;Password =velo1234

注意,第二个参数名称是Database,不是AttachFileName

将下面的DbMigrator设为启动项目

4、运行项目,即可通过种子数据执行数据库迁移

5、启动项目,将web项目设为启动项目,运行

登录 admin 用户(密码为1q2w3E*)

登录成功页面

替换数据库使用 postgresql

步骤

ABP框架配置数据库为postgresql的详细步骤

ABP框架支持多种数据库类型,包括 PostgreSQL 数据库。要将 ABP 框架配置为使用 PostgreSQL 数据库,请按照以下步骤操作:

1.添加NuGet引用

在 Visual Studio 中打开项目并安装Volo.Abp.EntityFrameworkCore.PostgreSql NuGet 包。 可以使用 NuGet 包管理器或在 .csproj 文件中手动添加它。

<ItemGroup>
  <PackageReference Include="Volo.Abp.EntityFrameworkCore.PostgreSql" Version="xxxxx" />
</ItemGroup>
  1. 配置连接字符串

appsettings.json 或者是appsettings.{environment}.json文件(和你的环境息息相关)中设置 PostgreSQL 数据库的连接字符串。例如:

{
  "ConnectionStrings": {
    "Default": "Server=myServerAddress;Port=5432;Database=myDataBase;Uid=myUsername;Pwd=myPassword;"
  },
  //...
}

请替换上述示例中的连接字符串中的值为你自己的数据库服务器地址、端口号、数据库名称、用户名和密码。

  1. 配置DbContext

全局替换UseSqlServer()为UseNpgsql()。

将typeof(AbpEntityFrameworkCoreSqlServerModule)依赖替换为typeof(AbpEntityFrameworkCorePostgreSqlModule),

在应用程序模块类或者依赖的类库中进行 DbContext 的配置。 例子代码如下:

using Volo.Abp.EntityFrameworkCore;
using Volo.Abp.Modularity;

namespace YourProjectName.EntityFrameworkCore
{
    [DependsOn(
        typeof(YourProjectNameDomainModule),
        typeof(AbpEntityFrameworkCorePostgreSqlModule)
    )]
    public class YourProjectNameEntityFrameworkCoreModule : AbpModule
    {
        public override void ConfigureServices(ServiceConfigurationContext context)
        {
            Configure<AbpDbContextOptions>(options =>
            {
                options.UseNpgsql();
            });
        }
    }
}

关键点:

  • DbContext 是使用 EntityFrameworkCore 模块定义的,所以需要引用 Abp.EntityFrameworkCore 模块。
  • 通过调用 UseNpgsql() 方法为 ABP 框架配置 PostgreSQL 数据库提供程序。

4、变更时间戳格式

官方说明

www.npgsql.org/doc/types/d…

在项目的所有Program.cs中,插入下面代码

AppContext.SetSwitch("Npgsql.EnableLegacyTimestampBehavior", true);

否则会有下面报错

System.InvalidCastException: Cannot write DateTime with Kind=Local to PostgreSQL type 'timestamp with time zone', only UTC is supported. Note that it's not possible to mix DateTimes with different Kinds in an array/range. See the Npgsql.EnableLegacyTimestampBehavior AppContext switch to enable legacy behavior.

at Npgsql.Internal.TypeHandlers.DateTimeHandlers.TimestampTzHandler.ValidateAndGetLength(DateTime value, NpgsqlParameter parameter)

这个报错的意思是,无法将本地时间(Kind=Local)写入到 PostgreSQL 的 timestamp with time zone 类型中,只支持 UTC 时间。同时注意不可在数组/范围中混合使用具有不同 Kind 的 DateTime 对象。可以使用 Npgsql.EnableLegacyTimestampBehavior 应用上下文开关启用传统行为。

解决方案:

  1. 将应用程序中所有使用到的 DateTime 对象转换为 UTC 时间,然后再写入到 PostgreSQL 中;

  2. 或者,可以通过启用 Npgsql.EnableLegacyTimestampBehavior 应用上下文开关,来支持本地时间的写入操作。但是这并不推荐做法,因为不同的服务器可能会导致不一样的结果。

  3. 迁移

运行 Add-Migration 命令生成迁移

解决报错

Volo.Abp.AbpException: Could not find the bundle file '/libs/abp/core/abp.css' for the bundle 'LeptonXLite.Global'!

这个报错是由于在LeptonXLite.Global bundle中,无法找到'/libs/abp/core/abp.css'文件所导致的。可能是该文件不存在、路径不正确或者文件名有误。

解决方案:请确保'/libs/abp/core/abp.css'文件存在,并且位于正确的位置。可以检查一下路径或者文件名是否有写错,也可以重新下载文件来解决此问题。

解决方案

1、项目根目录,执行abp install-libs命令(需要安装npm、

node,安装后成功)。

会自动安装最小依赖包

提示NPM is not installed, visit nodejs.org/en/download… and install NPM

这个错误提示是因为您在执行abp install-libs命令时,所需要的npm(Node.js自带的包管理工具)没有被安装在您的电脑上。

要解决这个问题,您需要按照错误提示中给出的链接下载并安装Node.js。下载页面上会包含Node.js和npm两个文件的安装程序,在安装完Node.js后,npm也会跟着自动安装好。

安装完成后,您可以再次尝试执行abp install-libs命令,并且此时应该不会再弹出npm未安装的错误提示了。

需要安装node

在Windows上安装npm的步骤:

  1. 首先,从官方网站(nodejs.org/en/download…
  2. 打开命令提示符或PowerShell,并输入以下命令:

node -v
如果您看到输出,则表示已成功安装Node.js并且您已准备好安装npm。

  1. 在同一个命令提示符或PowerShell窗口中,输入以下命令:
npm install npm@latest -g

此命令将使用默认设置从NPM registry安装最新版本的npm。 -g选项表示您将全局安装npm。

  1. 输入以下命令验证安装是否成功:
npm -v

如果您看到npm的版本号,则表示已成功安装了npm。