项目

插件模块

模块 也可以作为插件加载。这意味着您无需在解决方案中直接引用模块的程序集;相反,您可以在应用程序启动时像加载其他模块一样加载它。

基本用法

WebApplicationBuilder.AddApplicationAsync<T>() 扩展方法可以获取配置插件源的选项。

示例:从文件夹加载插件

await builder.AddApplicationAsync<MyPlugInDemoWebModule>(options =>
{
    options.PlugInSources.AddFolder(@"D:\Temp\MyPlugIns");
});
  • 这是典型 ASP.NET Core 应用程序的 Startup 类。
  • PlugInSources.AddFolder 获取一个文件夹路径,并加载该文件夹中的程序集(通常是 dll 文件)。

就这样。ABP 将在给定文件夹中发现模块,配置并初始化它们,就像常规模块一样。

插件源

options.PlugInSources 实际上是 IPlugInSource 实现的列表,AddFolder 只是以下表达式的简写形式:

options.PlugInSources.Add(new FolderPlugInSource(@"D:\Temp\MyPlugIns"));

AddFolder() 仅查找给定文件夹中的程序集文件,但不查找子文件夹。您可以传递 SearchOption.AllDirectories 作为第二个参数,以递归方式从子文件夹中搜索插件。

还有两个内置的插件源实现:

  • PlugInSources.AddFiles() 获取程序集(通常是 dll)文件列表。这是使用 FilePlugInSource 类的简写形式。
  • PlugInSources.AddTypes() 获取模块类类型列表。如果您使用此方法,需要自己加载模块的程序集,但在需要时提供了灵活性。这是使用 TypePlugInSource 类的简写形式。

如果需要,您可以创建自己的 IPlugInSource 实现,并像其他插件源一样添加到 options.PlugInSources 中。

示例:创建一个简单插件

在解决方案中创建一个简单的类库项目

simple-plugin-library

您可以添加模块中需要使用的 ABP 包。至少,您应该将 Volo.Abp.Core 包添加到项目中。在要安装包的 .csproj 文件所在文件夹中执行以下命令:

abp add-package Volo.Abp.Core

如果尚未安装,您首先需要安装 ABP CLI。有关其他安装选项,请参阅 包详情页面

每个 模块 必须声明一个从 AbpModule 派生的类。这里是一个简单的模块类,它在应用程序启动时解析服务并初始化:

using Microsoft.Extensions.DependencyInjection;
using Volo.Abp;
using Volo.Abp.Modularity;

namespace MyPlugIn
{
    public class MyPlungInModule : AbpModule
    {
        public override void OnApplicationInitialization(ApplicationInitializationContext context)
        {
            var myService = context.ServiceProvider
                .GetRequiredService<MyService>();
            
            myService.Initialize();
        }
    }
}

MyService 可以是注册到 依赖注入 系统中的任何类,如下所示:

using Microsoft.Extensions.Logging;
using Volo.Abp.DependencyInjection;

namespace MyPlugIn
{
    public class MyService : ITransientDependency
    {
        private readonly ILogger<MyService> _logger;

        public MyService(ILogger<MyService> logger)
        {
            _logger = logger;
        }

        public void Initialize()
        {
            _logger.LogInformation("MyService has been initialized");
        }
    }
}

构建项目,打开构建文件夹,找到 MyPlugIn.dll

simple-plug-in-dll-file

MyPlugIn.dll 复制到插件文件夹(此示例中为 D:\Temp\MyPlugIns)。

如果使用 build folder 文件夹作为 PlugInSources,请删除 MyPlugIn.deps.json 文件。

如果您已如上所述配置了主应用程序(请参阅基本用法部分),您应该在应用程序启动时看到 MyService has been initialized 日志。

示例:创建带有 Razor 页面的插件

创建包含视图的插件需要更多注意。

此示例假设您已使用应用程序启动模板和 MVC / Razor Pages UI 创建了一个新的 Web 应用程序

在解决方案中创建一个新的类库项目:

simple-razor-plugin

编辑 .csproj 文件内容:

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>net9.0</TargetFramework>
        <OutputType>Library</OutputType>
        <IsPackable>true</IsPackable>
    </PropertyGroup>

    <ItemGroup>
      <PackageReference Include="Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared" Version="9.3.3" />
    </ItemGroup>

</Project>
  • Sdk 更改为 Microsoft.NET.Sdk.Web
  • 添加了 OutputTypeIsPackable 属性。
  • 添加了 Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared NuGet 包。

依赖 Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared 包不是必需的。您可以引用更基础的包,如 Volo.Abp.AspNetCore.Mvc。但是,如果您要构建 UI 页面/组件,建议引用 Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared 包,因为它是最高级别的包,不依赖特定的 主题 。如果依赖特定主题没有问题,您可以直接引用主题的包,以便在插件中使用主题特定功能。

然后在插件中创建模块类:

using System.IO;
using System.Reflection;
using Microsoft.AspNetCore.Mvc.ApplicationParts;
using Microsoft.Extensions.DependencyInjection;
using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared;
using Volo.Abp.Modularity;

namespace MyMvcUIPlugIn
{
    [DependsOn(typeof(AbpAspNetCoreMvcUiThemeSharedModule))]
    public class MyMvcUIPlugInModule : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            PreConfigure<IMvcBuilder>(mvcBuilder =>
            {
                //添加插件程序集
                mvcBuilder.PartManager.ApplicationParts.Add(new AssemblyPart(typeof(MyMvcUIPlugInModule).Assembly));

                //如果插件模块包含 razor 视图,添加 CompiledRazorAssemblyPart。
                mvcBuilder.PartManager.ApplicationParts.Add(new CompiledRazorAssemblyPart(typeof(MyMvcUIPlugInModule).Assembly));
            });
        }
    }
}
  • 依赖 AbpAspNetCoreMvcUiThemeSharedModule,因为我们添加了相关的 NuGet 包。
  • 将插件的程序集作为 AssemblyPartCompiledRazorAssemblyPart 添加到 ASP.NET Core MVC 的 PartManager 中。这是 ASP.NET Core 要求的。否则,插件中的控制器或视图将无法工作。

现在您可以在 Pages 文件夹中添加 razor 页面,如 MyPlugInPage.cshtml

@page
@model MyMvcUIPlugIn.Pages.MyPlugInPage
<h1>欢迎来到我的插件页面</h1>
<p>此页面位于插件模块内! :)</p>

现在,您可以构建插件项目。它将产生以下输出:

simple-razor-plug-in-dll-file

MyMvcUIPlugIn.dll 复制到插件文件夹(此示例中为 D:\Temp\MyPlugIns)。

如果您已如上所述配置了主应用程序(请参阅基本用法部分),您应该能够在应用程序运行时访问 /MyPlugInPage URL:

simple-plugin-output

讨论

在现实世界中,您的插件可能有一些外部依赖项。此外,您的应用程序可能设计为支持插件。所有这些都是您自己的系统需求。ABP 所做的只是在应用程序启动时加载模块。您在模块内部做什么取决于您自己。

但是,我们可以为一些常见情况提供一些建议。

库依赖

对于包/dll 依赖项,您可以将相关的 dll 复制到插件文件夹中。ABP 会自动加载文件夹中的所有程序集,您的插件将按预期工作。

有关此情况的更多说明,请参阅 Microsoft 的文档

数据库架构

如果您的模块使用关系数据库和 Entity Framework Core,它将需要在数据库中拥有其表。当应用程序使用插件时,有不同的方法确保表已创建。一些示例:

  1. 插件可以检查数据库表是否存在,并在应用程序启动时创建表,或者在插件已更新并需要一些架构更改时迁移它们。您可以使用 EF Core 的迁移 API 来实现这一点。
  2. 您可以改进 DbMigrator 应用程序,以查找插件的迁移并执行它们。

可能有其他解决方案。例如,如果您的数据库管理员不允许您在应用程序代码中更改数据库架构,您可能需要手动将 SQL 文件发送给数据库管理员以应用于数据库。

插件示例

我们有一个示例,您可以从 abp-sample 存储库 下载。

在本文档中