.NET 6 之 ABP vNext 初体验

马上国庆了,dotNative 预祝大家假期愉快,Happy National Day!

本文将介绍在 .net6 平台的 asp.net core webapi 框架中,如何使用 abp vnext 框架进行模块化开发,重在思想理解。

.NET 6 之 ABP vNext 初体验_第1张图片

ABP vNext 介绍

  • 官方介绍

ABP vNext 本身是一个包含许多 NuGet 包的 模块化(Module) 框架。它还提供了一个完整的基础架构来开发你自己的具有实体、服务、数据库集成、API、UI 组件等等功能的应用程序模块。

  • 专业介绍

ABP vNext 框架是一个基于 ASP.NET Core 的完整基础设施,通过遵循软件开发最佳实践和最新技术来创建现代 web 应用程序和 API,不同于老的 ABP 框架。新的 ABP vNext 框架核心库更加精简,因为将原有许多的组件从其核心库抽离成独立的组件。这样开发人员可以更加灵活的选择自己需要的功能进行集成,使项目远离臃肿的库,比起原有的 ABP 框架 ABP vNext 完全基于 ASP.NET Core 丢掉了历史包袱,设计更加合理,更加细粒度的模块化设计。

  • 通俗介绍

ABP vNext 框架是一个集成多个第三方组件类库的一个应用程序集,遵循 模块化(Module) 思想实践的最佳方式。

.NET 6 之 MiniAPI 的 ABP vNext 初体验

新建项目 Demo.Abp.WebApplication1 项目

通过 dotnet cli 命令新建 asp.net core webapi 项目,命名为 Demo.Abp.WebApplication1,执行如下命令:

dotnet new webapi -n Demo.Abp.WebApplication1

或者通过 Visual Studio Community 2022 (64 位) IDE 工具创建该项目。

.NET 6 之 ABP vNext 初体验_第2张图片

  1. 添加新建项目,选择 ASP.NET Core Web API 项目模板,点击【下一步】。

.NET 6 之 ABP vNext 初体验_第3张图片

  1. 配置新建项目,输入项目名称 ASP.NET Core Web API ,继续点击【下一步】。

.NET 6 之 ABP vNext 初体验_第4张图片

  1. 其他信息,这里只勾选【使用控制器】,然后点击【创建】。

.NET 6 之 ABP vNext 初体验_第5张图片

经过上面步骤, Demo.Abp.WebApplication1 项目就创建完毕了,项目结构如下:

.NET 6 之 ABP vNext 初体验_第6张图片

NuGet 添加 Abp 相关模块包

然后在 Demo.Abp.WebApplication1 项目中添加 nuget 包:

  • Volo.Abp.AspNetCore
  • Volo.Abp.Swashbuckle
NuGet\Install-Package Volo.Abp.AspNetCore -Version 6.0.0-rc.5

.NET 6 之 ABP vNext 初体验_第7张图片

NuGet\Install-Package Volo.Abp.Swashbuckle -Version 6.0.0-rc.5

.NET 6 之 ABP vNext 初体验_第8张图片

Program.cs 文件默认代码如下:

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

var app = builder.Build();
// Configure the HTTP request pipeline.
app.UseAuthorization();
app.MapControllers();
app.Run();

接下来我们改造默认的 Program.cs 文件,让其遵循 ABP vNext 模块化(Module)的编程风格,操作步骤如下:

  1. 首先在 Program.cs 文件中新建一个 class 类,名称为 DemoWebApiModule,并继承 AbpModule
  2. 其次通过 DependsOn 特性来定义模块的依赖关系。
  3. 然后在 Program.cs 文件中通过 AddApplication 注入自定义模块类。
  4. 最后在 InitializeApplication 初始化 http 请求管道(request pipeline)。

Abp 模块化(Module)改造

模块化改造【同步版】

Abp 模块化(Module 改造后,Program.cs 文件 同步 版本的代码如下:

using Volo.Abp;
using Volo.Abp.AspNetCore;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;

var builder = WebApplication.CreateBuilder(args);
// 重新注册 Configuration
builder.Services.ReplaceConfiguration(builder.Configuration);
// 添加自定义模块 DemoWebApiModule
builder.Services.AddApplication<DemoWebApiModule>();

/* 同上等效代码
 * 添加自定义模块 DemoWebApiModule
builder.Services.AddApplication(options => {
    options.Services.ReplaceConfiguration(builder.Configuration); // 重新注册 Configuration
});
*/

var app = builder.Build();
// 初始化 http 请求管道(request pipeline)
app.InitializeApplication();

app.Run();

// 声明 ABP 对应的模块(Module)依赖
[DependsOn(typeof(AbpAspNetCoreModule))]
// 自定义模块类 DemoWebApiModule,并继承自 AbpModule 
public class DemoWebApiModule : AbpModule 
{
    // IoC 注册服务容器
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var services = context.Services;
        services.AddControllers();
    }
    //  http 请求管道(request pipeline)初始化
    public override void OnApplicationInitialization(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

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

        app.UseRouting();
        app.UseAuthorization();

        app.UseConfiguredEndpoints(); // 替换原来的 app.MapControllers();
    }
}

说明:请求管道(request pipeline) 由各种业务逻辑对应的 中间件(middleware 组成。

到这里默认的 asp.net core webapi 项目就依据 ABP vNext 模块化(Module)的风格改造完毕。

模块化改造【异步版】

我们继续上面的 Abp 模块化(Module 【同步版】修改,此处使用【异步】模式构建,并集成 Swagger 模块,改造后代码如下:

using Microsoft.OpenApi.Models;
using Volo.Abp;
using Volo.Abp.AspNetCore;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;

var builder = WebApplication.CreateBuilder(args);
//builder.Services.ReplaceConfiguration(builder.Configuration);
await builder.Services.AddApplicationAsync<DemoWebApiModule>(options => {
    options.Services.ReplaceConfiguration(builder.Configuration);
});

var app = builder.Build();
await app.InitializeApplicationAsync();

await app.RunAsync();

[DependsOn(
    typeof(AbpAspNetCoreModule),
    typeof(AbpSwashbuckleModule)
 )]
public class DemoWebApiModule : AbpModule
{
    public override async Task ConfigureServicesAsync(ServiceConfigurationContext context)
    {
        var services = context.Services;
        services.AddControllers();
        services.AddEndpointsApiExplorer();
        services.AddAbpSwaggerGen(options => {
            options.SwaggerDoc("TestAPI", new OpenApiInfo { Title = "Test DemoWebApiModule API", Version = "v1", Description = "Module 模块化 DemoWebApiModule 自定义类。" });
            options.DocInclusionPredicate((docName, description) => true);
            options.CustomSchemaIds(type => type.FullName);
        });
        await Task.CompletedTask;
    }

    public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            //app.UseDeveloperExceptionPage();
            app.UseSwaggerUI();
            app.UseAbpSwaggerUI(options => {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "TestAPI");
            });
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        //app.UseHttpsRedirection();
        app.UseRouting();
        app.UseAuthorization();
        app.UseConfiguredEndpoints(); //代替原来的 app.MapControllers();
        await Task.CompletedTask;
    }
}

Properties —— launchSettings.json

启动配置文件,你可以在项目中 “Properties” 文件夹中找到 launchSettings.json 文件。该文件是 ASP.NET Core 应用特有的配置标准,用于应用的启动准备工作,包括环境变量,开发端口等。

launchSettings.json 文件中进行配置和右键项目—属性中所提交的更改的效果是一样的,并且支持同步更新。此文件设置了 Visual Studio 可以启动的不同环境,以下是示例项目中 launchSettings.json 文件生成的默认配置:

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:48492",
      "sslPort": 0
    }
  },
  "profiles": {
    "Demo.Abp.WebApplication1": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5220",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

运行 Module 模块化项目

我们先运行下 Demo.Abp.WebApplication1 项目,正常运行后请求默认的 WeatherForecastController

浏览器输入 weatherforecast API 地址:

http://localhost:5220/weatherforecast

API 接口访问成功,如下所示:

.NET 6 之 ABP vNext 初体验_第9张图片

​通过以上步骤我们就完成了对 asp.net core webapi 框架 MiniAPI 模式的 ABP vNext 模块化改造。

.NET 6 还原 Program.cs & Startup.cs

由于本人不太喜欢 MiniAPI 模式,因此再继续改造,还原为 .net core 3.1 时代的玩法 —— Program.cs + Startup.cs 模式(此处不知是否有同感的小伙伴呢?)。

此处为了和上面项目形成对照(原有项目保留不变),新建一个 asp.net core webapi 项目,命名为 Demo.Abp.WebApplication2,项目结构的改造对比如下图所示:

.NET 6 之 ABP vNext 初体验_第10张图片

说明:为了演示业务 Service 类中 DI 的注入方式,这里会引入一个 Abp 集成 Autofac 的模块 —— Volo.Abp.Autofac

NuGet\Install-Package Volo.Abp.Autofac -Version 6.0.0-rc.5

.NET 6 之 ABP vNext 初体验_第11张图片

这里安装 NuGet 包同上,不再叙述,下面的步骤假定安装了如下 Abp vNext 依赖模块:

  • Volo.Abp.AspNetCore
  • Volo.Abp.Swashbuckle
  • Volo.Abp.Autofac

通过这个改造过程,学会使用 Abp vNext 模块化、规范化的应用在实际项目开发中,并且会使用 Abp vNext 依赖模块( Module 模块化具有传染性)。

改造步骤

如下改造步骤,尽量详细的介绍一下项目结构中的每一个模块,相应的类使用文件夹划分,目录层次更佳清晰明了。

1、提取 DemoWebApiModule.cs 模块化文件

MiniAPI 模式中,为了避免新建文件,直接在 Program.cs 文件中新建自定义模块化类,此处为了更好的工程化对该文件单独提取,改造代码如下所示:

using Microsoft.OpenApi.Models;
using Volo.Abp;
using Volo.Abp.AspNetCore;
using Volo.Abp.Autofac;
using Volo.Abp.Modularity;
using Volo.Abp.Swashbuckle;
using Demo.Abp.WebApplication2.Services; 

namespace Demo.Abp.WebApplication2.Module;

// 使用 Abp 模块(Module)
[DependsOn(
    typeof(AbpAspNetCoreModule),
    typeof(AbpAutofacModule),
    typeof(AbpSwashbuckleModule)
)]

// 自定义类 Module 化
public class DemoWebApiModule : AbpModule
{
    // IoC 注册服务容器
    public override async Task ConfigureServicesAsync(ServiceConfigurationContext context)
    {
        //1、IoC 注册服务类
        var services = context.Services;
        services.AddControllers();
        services.AddEndpointsApiExplorer();
        services.AddAbpSwaggerGen(options => {
            options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test DemoWebApiModule API", Version = "v1", Description = "Module 模块化 DemoWebApiModule 自定义类。" });
            options.DocInclusionPredicate((docName, description) => true);
            options.CustomSchemaIds(type => type.FullName);
        });

        // 2、注册具体的业务服务(声明式)
        context.Services.AddScoped<IWeatherForecastService, WeatherForecastService>();

        await Task.CompletedTask;
    }

    // Pipeline 管道中间件初始化
    public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            //app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseAbpSwaggerUI(options => {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test DemoWebApiModule API");
            });
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        //app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();
        app.UseConfiguredEndpoints(); // 替代 app.MapControllers();

        await Task.CompletedTask;
    }
}

2、Startup.cs 文件代码改造

.net core 3.1.x 时代,默认 Program.cs + Startup.cs 模式,而在 Startup.cs 中存在两个方法:

  • ConfigureServices(),在该方法中注册依赖关系/服务(无序)。
  • Configure(),在该方法中(有序)注册中间件(Middleware),多个中间件组成 http 请求管道(Http request pipeline)。

这里为了上述两个方法命名更佳见名知意,特此修改如下:

  • ConfigureServices() 修改为 RegisterServicesAsync();
  • Configure() 修改为 SetupMiddlewaresAsync();

说明:这里是改造为异步模式,同步方式去除方法名称的 Async 后缀即可。

新建 Startup.cs 类,添加如下代码:

using Volo.Abp;
using Volo.Abp.Modularity.PlugIns;
using Demo.Abp.WebApplication2.Module;

namespace Demo.Abp.WebApplication2;

public class Startup
{
    public IConfiguration Configuration { get; }

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

    // Add services to the container. 注册服务到 Ioc 容器
    public async Task RegisterServicesAsync(IServiceCollection services, IHostBuilder host)
    {
        Console.WriteLine($"{DateTime.UtcNow},加载 DemoWebApiModule 模块...");
        
        host.UseAutofac(); // 使用 Autofac 第三方 DI

        //services.ReplaceConfiguration(Configuration);

        // 注册自定义模块 DemoWebApiModule
        await services.AddApplicationAsync<DemoWebApiModule>(options => {
            // options.UseAutofac();

            options.Services.ReplaceConfiguration(Configuration); // 等效同上代码

            // 加载插件,固定模式,可热插拔
            // options.PlugInSources.AddFolder(@"E:\CodeStuday\dotnet6\DemoAbpPulgins");
        });
    }

    // Configure the HTTP request pipeline. 配置 HTTP 请求管道(中间件管道即中间件委托链)
    public async Task SetupMiddlewaresAsync(IApplicationBuilder app, IWebHostEnvironment env)
    {
        Console.WriteLine($"{env.ApplicationName},{DateTime.UtcNow},启动中间件管道初始化 InitializeApplicationAsync...");
        await app.InitializeApplicationAsync();
    }
}

思考:当依赖模块变多,需要频繁的调整,这样就会违背开闭原则,那么该如规避该问题呢?

其实 ABP vNext 官网提供了解决方案(PlugIns,插件机制),遵循开闭原则,只需添加 NuGetVolo.Abp.Modularity.PlugIns ,便可实现 Module 模块的插件式加载,只需如下两不操作即可:

  1. 在项目根文件添加一个文件夹,如:DemoAbpPulgins(文件夹命名尽量见名知意)。
  2. 固定模式,在 AddApplicationAddApplicationAsyncoptions 中添加如上代码(注释部分)。
  3. 将模块化组件编译好的 Xxx.dll 文件拷贝到新建的根文件夹里面,保存运行即可。

以上就实现了 Abp 模块动态加载,规避了 开闭原则 之冲突点。

开闭原则:在面向对象编程中声明 “软件实体(类、模块、函数等)应该对扩展开放,但对修改关闭”;这样的实体可以允许在不修改源代码的情况下对其行为进行扩展。

3、Program.cs 文件代码改造

由于 Startup.cs 文件里面的代码是异步的,所以 Program.cs 文件也需要调整为异步模式(异步具有传染性)。

namespace Demo.Abp.WebApplication2;

public class Program
{
    public static async Task Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);

        // 此处代码,已经调整到 RegisterServicesAsync 方法,注意观察。
        //builder.Services.ReplaceConfiguration(builder.Configuration);
        //builder.Host.UseAutofac(); // 直接使用Autofacz

        var startup = new Startup(builder.Configuration);
        await startup.RegisterServicesAsync(builder.Services, builder.Host);

        var app = builder.Build();
        await startup.SetupMiddlewaresAsync(app, builder.Environment);

        await app.RunAsync();
    }
}

4、WeatherForecastService.cs 文件改造

这里使用 WeatherForecastService.cs 文件来模拟具体的业务服务,继承自 IWeatherForecastService 接口,结构如上图中 Services 文件夹部分,代码定义如下:

  • IWeatherForecastService 接口,定义业务方法规范。
using Demo.Abp.WebApplication2.Model;

namespace Demo.Abp.WebApplication2.Services;

public interface IWeatherForecastService
{
    public IEnumerable<WeatherForecast> GetWeatherForecast();
}
  • WeatherForecastService.cs 类,继承自 IWeatherForecastService 接口。
using Volo.Abp.DependencyInjection; //引入 DI 
using Demo.Abp.WebApplication2.Model;

namespace Demo.Abp.WebApplication2.Services;

// Dependency 特性声明 Service 服务生命周期
[Dependency(ServiceLifetime.Scoped, ReplaceServices = true)]
public class WeatherForecastService : IWeatherForecastService
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    // 模拟业务操作,数据库取数据
    public IEnumerable<WeatherForecast> GetWeatherForecast()
    {
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = Summaries[Random.Shared.Next(Summaries.Length)]
        }).ToArray();
    }
}

5、WeatherForecast.cs 模型类

这里使用默认的模型,代码如下:

namespace Demo.Abp.WebApplication2.Model;

public class WeatherForecast
{
    public DateTime Date { get; set; }
    public int TemperatureC { get; set; }
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
    public string? Summary { get; set; }
}

6、WeatherForecastController.cs 控制器类

此处稍作调整,为了演示业务操作中 DI 调用,把默认代码调整到 WeatherForecastService.cs 类。调整代码如下:

using Microsoft.AspNetCore.Mvc;
using Demo.Abp.WebApplication2.Model;
using Demo.Abp.WebApplication2.Services;

namespace Demo.Abp.WebApplication2.Controllers;

/// 
/// WebAPI 入口 
/// 
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    // 1、属性 DI 注入
    public IWeatherForecastService _IWeatherForecastService { get; set; }

    // 2、构造函数 DI 注入
    private readonly ILogger<WeatherForecastController> _logger;
    /// 
    /// 构造函数
    /// 
    /// 
    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> GetWeatherForecast()
    {
        _logger.LogDebug($"{DateTime.UtcNow}, hello abpvnext ...");
        return _IWeatherForecastService.GetWeatherForecast();
    }
}

7、appsettings.json 配置文件

此处就用默认生成的(这里只是为了尽量说明项目文件结构),配置如下:

{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

8、launchsettings.json 配置文件

{
  "$schema": "https://json.schemastore.org/launchsettings.json",
  "iisSettings": {
    "windowsAuthentication": false,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:36683",
      "sslPort": 0
    }
  },
  "profiles": {
    "Demo.Abp.WebApplication2": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "launchUrl": "swagger",
      "applicationUrl": "http://localhost:5165",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    },
    "IIS Express": {
      "commandName": "IISExpress",
      "launchBrowser": true,
      "launchUrl": "swagger",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

到这里就基本完成了 Startup.cs 文件的改造,接下来我们启动运行测试看下,是否正常符合预期情况。

启动运行测试

启动 Abp 集成 Swagger 模块 —— Volo.Abp.Swashbuckle 符合预期正常显示。

.NET 6 之 ABP vNext 初体验_第12张图片

如果要隐藏 ABP vNext默认端点,可以在 Swagger 配置中调用 HideAbpEndpoints 方法,

  • AbpApiDefinition
  • AbpApplicationConfiguration

完整代码如下:

services.AddAbpSwaggerGen(options => {
    options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test DemoWebApiModule API", Version = "v1", Description = "Module 模块化 DemoWebApiModule 自定义类。" });
    options.DocInclusionPredicate((docName, description) => true);
    options.CustomSchemaIds(type => type.FullName);
    options.HideAbpEndpoints(); // 隐藏 ABP vNext 的默认端点
});

运行项目,注意和上图对比,SwaggerUI 页面如下图所示:
.NET 6 之 ABP vNext 初体验_第13张图片

点击【WeatherForecast】执行业务 ServiceDI 注册并调用,运行如下所示:

.NET 6 之 ABP vNext 初体验_第14张图片

  1. curl 命令访问:
curl -X 'GET' \
  'http://localhost:5165/WeatherForecast' \
  -H 'accept: text/plain' \
  -H 'RequestVerificationToken: CfDJ8ODjDXixt1tDuxO1cuT_L2z6DM3lUqtnRF0xKJPwuuLU0SKbwulLhV35ySmCqoC3CuQksJoqHnyzRQw5ZT-sE5Q20mC3vFONoLQ2Tx5Y1Y9qvQ67mtBCqNnSPtCePtukjn1Ocd6ocr-0E2fJVLroRYU' \
  -H 'X-Requested-With: XMLHttpRequest'
  1. 浏览器输入 url 访问:
http://localhost:5165/WeatherForecast

.NET 6 之 ABP vNext 初体验_第15张图片

SwaggerUI 权限配置

在生产环境中,考虑安全性,通常需要 Swagger 接入 OAuth2 认证。

ABP vNext 集成了 Identity Server 来做权限认证,需要使用 AddAbpSwaggerGenWithOAuth 扩展,在 ModuleConfigureServices 方法中,使用 OAuth issuerscopes 来配置 Swagger

    // IoC 注册服务容器
    public override async Task ConfigureServicesAsync(ServiceConfigurationContext context)
    {
        //1、IoC 注册服务类
        var services = context.Services;
        services.AddControllers();
        services.AddEndpointsApiExplorer();
        // Swagger 配置权限
        services.AddAbpSwaggerGenWithOAuth(
            authority: "https://localhost:44341",      // authority issuer
            scopes: new Dictionary<string, string> {   // scopes                               
                {"Test", "Test DemoWebApiModule API"}                 
            },
            options => {
                options.SwaggerDoc("v1", new OpenApiInfo { Title = "Test DemoWebApiModule API", Version = "v1", Description = "Module 模块化 DemoWebApiModule 自定义类。" });
                options.DocInclusionPredicate((docName, description) => true);
                options.CustomSchemaIds(type => type.FullName);
                options.HideAbpEndpoints(); // 隐藏 ABP vNext 的默认端点
            });

        // 2、注册具体的业务服务(声明式)
        context.Services.AddScoped<IWeatherForecastService, WeatherForecastService>();

        await Task.CompletedTask;
    }

    // Pipeline 管道中间件初始化
    public override async Task OnApplicationInitializationAsync(ApplicationInitializationContext context)
    {
        var app = context.GetApplicationBuilder();
        var env = context.GetEnvironment();

        if (env.IsDevelopment())
        {
            //app.UseDeveloperExceptionPage();
            app.UseSwagger();
            app.UseAbpSwaggerUI(options => {
                options.SwaggerEndpoint("/swagger/v1/swagger.json", "Test DemoWebApiModule API");
                var configuration = context.ServiceProvider.GetRequiredService<IConfiguration>();
                options.OAuthClientId("TestSwagger");   // clientId
                options.OAuthClientSecret("!QAZ2wsx");  // clientSecret
            });
        }
        else
        {
            app.UseExceptionHandler("/Error");
        }

        //app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseRouting();
        app.UseAuthorization();
        app.UseConfiguredEndpoints(); // 替代 app.MapControllers();

        await Task.CompletedTask;
    }

说明:修改上面的代码配置后,需要提前搭建好 Identity Server 服务并启动运行,再该服务中注册 clientId & clientSecret,然后把 authority: "https://localhost:44341" 修改为 Identity Server 服务地址。

关于 Identity Server 服务的搭建,这里不是重点,想了解更多,请自行查看官网或相关资料:

  • 欢迎使用 IdentityServer4,https://identityserver4docs.readthedocs.io/zh_CN/latest/index.html
  • IdentityServer4 中文文档,http://www.identityserver.com.cn/
  • IdentityServer4 认证服务器集成 Identity & 配置持久化数据库(Sqlite),http://t.zoukankan.com/liumengchen-boke-p-11179153.html

修改配置如上代码后,运行项目 Swagger UI 如下图所示:

.NET 6 之 ABP vNext 初体验_第16张图片

总结

asp.net core webapiMiniAPI 模式开始,遵循 ABP vNext Web 框架的 Module 模块化思想并学会使用,再到 Program.cs & Startup.cs 模式的改造,使得项目工程化体验更佳、目录层级结构更清晰,再逐步引入其他模块(Module)依赖,并通过 DependsOn 特性显示声明。

遵循 ABP vNext 框架的规则,在代码层面更加直观的体现 Module 模块化开发思想。当依赖模块多,需要频繁的调整代码模块的依赖, 此时 ABP vNext 框架提供了 PlugIns 插件化机制,实现 ABP vNext 模块 插件式 的动态加载,可热插拔,符合符合 开闭原则

你可能感兴趣的:(.NET,Core,跨平台,ASP.NET,Core,2.0系列学习笔记,.net/c#,asp.net,core,abp,vnext,webapi,module模块化)