Skip to content

Commit 7c2582f

Browse files
committed
Merge branch 'dev' into issue-23231-v2
2 parents 7621fc7 + c0402ac commit 7c2582f

File tree

184 files changed

+2050
-1633
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

184 files changed

+2050
-1633
lines changed

Directory.Packages.props

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,10 @@
1818
<PackageVersion Include="BunnyCDN.Net.Storage" Version="1.0.4" />
1919
<PackageVersion Include="Azure.Messaging.ServiceBus" Version="7.19.0" />
2020
<PackageVersion Include="Azure.Storage.Blobs" Version="12.24.0" />
21-
<PackageVersion Include="Blazorise" Version="1.7.7" />
22-
<PackageVersion Include="Blazorise.Components" Version="1.7.7" />
23-
<PackageVersion Include="Blazorise.DataGrid" Version="1.7.7" />
24-
<PackageVersion Include="Blazorise.Snackbar" Version="1.7.7" />
21+
<PackageVersion Include="Blazorise" Version="1.8.0" />
22+
<PackageVersion Include="Blazorise.Components" Version="1.8.0" />
23+
<PackageVersion Include="Blazorise.DataGrid" Version="1.8.0" />
24+
<PackageVersion Include="Blazorise.Snackbar" Version="1.8.0" />
2525
<PackageVersion Include="Castle.Core" Version="5.1.1" />
2626
<PackageVersion Include="Castle.Core.AsyncInterceptor" Version="2.1.0" />
2727
<PackageVersion Include="CommonMark.NET" Version="0.15.1" />
@@ -128,11 +128,11 @@
128128
<PackageVersion Include="NUglify" Version="1.21.15" />
129129
<PackageVersion Include="Nullable" Version="1.3.1" />
130130
<PackageVersion Include="Octokit" Version="14.0.0" />
131-
<PackageVersion Include="OpenIddict.Abstractions" Version="6.4.0" />
132-
<PackageVersion Include="OpenIddict.Core" Version="6.4.0" />
133-
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="6.4.0" />
134-
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="6.4.0" />
135-
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="6.4.0" />
131+
<PackageVersion Include="OpenIddict.Abstractions" Version="7.0.0" />
132+
<PackageVersion Include="OpenIddict.Core" Version="7.0.0" />
133+
<PackageVersion Include="OpenIddict.Server.AspNetCore" Version="7.0.0" />
134+
<PackageVersion Include="OpenIddict.Validation.AspNetCore" Version="7.0.0" />
135+
<PackageVersion Include="OpenIddict.Validation.ServerIntegration" Version="7.0.0" />
136136
<PackageVersion Include="Oracle.EntityFrameworkCore" Version="9.23.80" />
137137
<PackageVersion Include="Polly" Version="8.5.2" />
138138
<PackageVersion Include="Polly.Extensions.Http" Version="3.0.0" />
Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Module Installer Projects
2+
3+
Each ABP module includes an `.Installer` project (e.g., `Volo.Abp.Account.Installer`) that serves as a **Virtual File System container** for module installation and resource management. These projects are essential for the ABP CLI to understand and install modules properly.
4+
5+
## Purpose of Installer Projects
6+
7+
Installer projects have three main purposes:
8+
9+
1. **Virtual File System Integration**: Register the module's embedded resources with ABP's Virtual File System
10+
2. **Resource Packaging**: Package module metadata files (`.abpmdl` and `.abppkg`) as embedded resources
11+
3. **CLI Integration**: Enable the ABP CLI to understand module structure and install modules automatically
12+
13+
## Structure of Installer Projects
14+
15+
### Project Files
16+
17+
- **`{ModuleName}.Installer.csproj`**: References `Volo.Abp.VirtualFileSystem` and embeds module metadata files
18+
- **`InstallationNotes.md`**: Documentation for the module
19+
- **`Volo/Abp/{ModuleName}/Abp{ModuleName}InstallerModule.cs`**: The core module class that registers embedded resources
20+
21+
### Example Installer Module
22+
23+
```csharp
24+
using Volo.Abp.Modularity;
25+
using Volo.Abp.VirtualFileSystem;
26+
27+
namespace Volo.Abp.Account;
28+
29+
[DependsOn(typeof(AbpVirtualFileSystemModule))]
30+
public class AbpAccountInstallerModule : AbpModule
31+
{
32+
public override void ConfigureServices(ServiceConfigurationContext context)
33+
{
34+
Configure<AbpVirtualFileSystemOptions>(options =>
35+
{
36+
options.FileSets.AddEmbedded<AbpAccountInstallerModule>();
37+
});
38+
}
39+
}
40+
```
41+
42+
### Project Configuration
43+
44+
The `.csproj` file embeds module metadata as content:
45+
46+
```xml
47+
<Project Sdk="Microsoft.NET.Sdk">
48+
<PropertyGroup>
49+
<TargetFramework>net9.0</TargetFramework>
50+
<GenerateEmbeddedFilesManifest>true</GenerateEmbeddedFilesManifest>
51+
<RootNamespace />
52+
</PropertyGroup>
53+
54+
<ItemGroup>
55+
<ProjectReference Include="..\..\..\..\framework\src\Volo.Abp.VirtualFileSystem\Volo.Abp.VirtualFileSystem.csproj" />
56+
</ItemGroup>
57+
58+
<ItemGroup>
59+
<!-- Embed module definition file -->
60+
<Content Include="..\..\Volo.Abp.Account.abpmdl">
61+
<Pack>true</Pack>
62+
<PackagePath>content\</PackagePath>
63+
</Content>
64+
65+
<!-- Embed package definition files -->
66+
<Content Include="..\..\**\*.abppkg*">
67+
<Pack>true</Pack>
68+
<PackagePath>content\</PackagePath>
69+
</Content>
70+
</ItemGroup>
71+
</Project>
72+
```
73+
74+
## Module Metadata Files
75+
76+
### `.abpmdl` (Module Definition)
77+
78+
The module definition file describes the module's structure and packages:
79+
80+
```json
81+
{
82+
"folders": {
83+
"items": {
84+
"src": {},
85+
"test": {}
86+
}
87+
},
88+
"packages": {
89+
"Volo.Abp.Account.Web": {
90+
"path": "src/Volo.Abp.Account.Web/Volo.Abp.Account.Web.abppkg",
91+
"folder": "src"
92+
},
93+
"Volo.Abp.Account.Application": {
94+
"path": "src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.abppkg",
95+
"folder": "src"
96+
}
97+
}
98+
}
99+
```
100+
101+
### `.abppkg` (Package Definition)
102+
103+
Each package has a definition file that specifies its role:
104+
105+
```json
106+
{
107+
"role": "lib.application"
108+
}
109+
```
110+
111+
Common roles:
112+
- `lib.application`: Application layer package
113+
- `lib.mvc`: MVC/Web layer package
114+
- `lib.domain`: Domain layer package
115+
- `lib.domain-shared`: Shared domain layer package
116+
- `lib.efcore`: Entity Framework Core package
117+
118+
## How Installer Projects Work
119+
120+
### 1. CLI Installation Process
121+
122+
When you run `abp add-module Volo.Abp.Account`:
123+
124+
1. **Download Installer Package**: CLI downloads `Volo.Abp.Account.Installer` from NuGet
125+
2. **Read Module Definition**: CLI reads the embedded `.abpmdl` file to understand module structure
126+
3. **Read Package Definitions**: CLI reads `.abppkg` files to understand package roles
127+
4. **Install Packages**: CLI installs appropriate packages to correct project types based on roles
128+
5. **Add Dependencies**: CLI adds module dependencies to project module classes
129+
130+
### 2. Virtual File System Integration
131+
132+
The `InstallerModule` registers itself with the Virtual File System:
133+
134+
```csharp
135+
options.FileSets.AddEmbedded<AbpAccountInstallerModule>();
136+
```
137+
138+
This makes embedded resources available at runtime and enables:
139+
- Access to module metadata
140+
- Resource file management
141+
- Module configuration
142+
143+
## Creating Installer Projects for New Modules
144+
145+
### Required Files
146+
147+
1. **Project File**: `{ModuleName}.Installer.csproj`
148+
2. **Module Class**: `Abp{ModuleName}InstallerModule.cs`
149+
3. **Documentation**: `InstallationNotes.md`
150+
4. **Module Definition**: `{ModuleName}.abpmdl` (in module root)
151+
5. **Package Definitions**: `{PackageName}.abppkg` (in each package)
152+
153+
### Template Structure
154+
155+
```
156+
modules/your-module/
157+
├── src/
158+
│ ├── Volo.Abp.YourModule.Installer/
159+
│ │ ├── Volo.Abp.YourModule.Installer.csproj
160+
│ │ ├── InstallationNotes.md
161+
│ │ └── Volo/
162+
│ │ └── Abp/
163+
│ │ └── YourModule/
164+
│ │ └── AbpYourModuleInstallerModule.cs
165+
│ └── [other packages]/
166+
├── Volo.Abp.YourModule.abpmdl
167+
└── [other module files]
168+
```
169+
170+
### Package Definition Examples
171+
172+
For different package types:
173+
174+
```json
175+
// Application package
176+
{ "role": "lib.application" }
177+
178+
// MVC package
179+
{ "role": "lib.mvc" }
180+
181+
// Domain package
182+
{ "role": "lib.domain" }
183+
184+
// EF Core package
185+
{ "role": "lib.efcore" }
186+
```
187+
188+
## Why Installer Projects Appear "Empty"
189+
190+
Installer projects appear minimal because their primary function is infrastructure, not business logic:
191+
192+
- **No Business Logic**: Business logic belongs in the actual module packages
193+
- **Pure Infrastructure**: They only handle module installation and resource management
194+
- **CLI Integration**: They enable automated module installation through the ABP CLI
195+
- **Resource Management**: They package and distribute module metadata
196+
197+
## Best Practices
198+
199+
1. **Follow Naming Convention**: Use `{ModuleName}.Installer` for the project name
200+
2. **Include Documentation**: Always provide `InstallationNotes.md` with module information
201+
3. **Proper Dependencies**: Only depend on `Volo.Abp.VirtualFileSystem`
202+
4. **Embed All Metadata**: Include both `.abpmdl` and `.abppkg` files
203+
5. **Test Installation**: Verify your installer works with `abp add-module` command
204+
205+
## Troubleshooting
206+
207+
### Common Issues
208+
209+
1. **Missing .abpmdl file**: Ensure the module definition file exists in the module root
210+
2. **Missing .abppkg files**: Each package needs a definition file
211+
3. **Incorrect roles**: Use appropriate roles for each package type
212+
4. **CLI not finding module**: Verify the installer package is published to NuGet
213+
214+
### Verification Steps
215+
216+
1. Build the installer project: `dotnet build`
217+
2. Check embedded resources: Verify `.abpmdl` and `.abppkg` files are embedded
218+
3. Test CLI installation: `abp add-module YourModule`
219+
4. Verify dependencies: Check that module dependencies are added correctly
220+
221+
This installer system enables ABP's sophisticated module architecture, allowing for automated installation with proper dependency resolution and project type matching.
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,34 @@
1-
using Volo.Abp.AspNetCore.MultiTenancy;
1+
using System.Linq;
2+
using Microsoft.Extensions.DependencyInjection;
3+
using Microsoft.Extensions.Logging;
4+
using Microsoft.Extensions.Options;
5+
using Volo.Abp.AspNetCore.MultiTenancy;
6+
using Volo.Abp.MultiTenancy;
27

38
namespace Microsoft.AspNetCore.Builder;
49

510
public static class AbpAspNetCoreMultiTenancyApplicationBuilderExtensions
611
{
12+
private const string AuthenticationMiddlewareSetKey = "__AuthenticationMiddlewareSet";
13+
714
public static IApplicationBuilder UseMultiTenancy(this IApplicationBuilder app)
815
{
9-
return app
10-
.UseMiddleware<MultiTenancyMiddleware>();
16+
var multiTenancyOptions = app.ApplicationServices.GetRequiredService<IOptions<AbpTenantResolveOptions>>();
17+
var hasCurrentUserTenantResolveContributor = multiTenancyOptions.Value.TenantResolvers.Any(r => r is CurrentUserTenantResolveContributor);
18+
if (hasCurrentUserTenantResolveContributor)
19+
{
20+
var authenticationMiddlewareSet = app.Properties.TryGetValue(AuthenticationMiddlewareSetKey, out var value) && value is true;
21+
if (!authenticationMiddlewareSet)
22+
{
23+
var logger = app.ApplicationServices.GetService<ILogger<MultiTenancyMiddleware>>();
24+
logger?.LogWarning(
25+
"MultiTenancyMiddleware is being registered before the authentication middleware. " +
26+
"This may lead to incorrect tenant resolution if the resolution depends on the authenticated user. " +
27+
"Ensure app.UseAuthentication() is called before app.UseMultiTenancy()."
28+
);
29+
}
30+
}
31+
32+
return app.UseMiddleware<MultiTenancyMiddleware>();
1133
}
1234
}

framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/AbpBackgroundWorkersModule.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using System.Threading.Tasks;
1+
using System.Threading;
2+
using System.Threading.Tasks;
23
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Hosting;
35
using Microsoft.Extensions.Options;
46
using Volo.Abp.Modularity;
57
using Volo.Abp.Threading;
@@ -16,9 +18,11 @@ public async override Task OnApplicationInitializationAsync(ApplicationInitializ
1618
var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value;
1719
if (options.IsEnabled)
1820
{
21+
var hostApplicationLifetime = context.ServiceProvider.GetService<IHostApplicationLifetime>();
22+
var cancellationToken = hostApplicationLifetime?.ApplicationStopping ?? CancellationToken.None;
1923
await context.ServiceProvider
2024
.GetRequiredService<IBackgroundWorkerManager>()
21-
.StartAsync();
25+
.StartAsync(cancellationToken);
2226
}
2327
}
2428

@@ -27,9 +31,11 @@ public async override Task OnApplicationShutdownAsync(ApplicationShutdownContext
2731
var options = context.ServiceProvider.GetRequiredService<IOptions<AbpBackgroundWorkerOptions>>().Value;
2832
if (options.IsEnabled)
2933
{
34+
var hostApplicationLifetime = context.ServiceProvider.GetService<IHostApplicationLifetime>();
35+
var cancellationToken = hostApplicationLifetime?.ApplicationStopping ?? CancellationToken.None;
3036
await context.ServiceProvider
3137
.GetRequiredService<IBackgroundWorkerManager>()
32-
.StopAsync();
38+
.StopAsync(cancellationToken);
3339
}
3440
}
3541

framework/src/Volo.Abp.BackgroundWorkers/Volo/Abp/BackgroundWorkers/BackgroundWorkersApplicationInitializationContextExtensions.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using System.Threading.Tasks;
44
using JetBrains.Annotations;
55
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Hosting;
67

78
namespace Volo.Abp.BackgroundWorkers;
89

@@ -28,6 +29,15 @@ public async static Task<ApplicationInitializationContext> AddBackgroundWorkerAs
2829
throw new AbpException($"Given type ({workerType.AssemblyQualifiedName}) must implement the {typeof(IBackgroundWorker).AssemblyQualifiedName} interface, but it doesn't!");
2930
}
3031

32+
if (cancellationToken == default)
33+
{
34+
var hostApplicationLifetime = context.ServiceProvider.GetService<IHostApplicationLifetime>();
35+
if (hostApplicationLifetime != null)
36+
{
37+
cancellationToken = hostApplicationLifetime.ApplicationStopping;
38+
}
39+
}
40+
3141
await context.ServiceProvider
3242
.GetRequiredService<IBackgroundWorkerManager>()
3343
.AddAsync((IBackgroundWorker)context.ServiceProvider.GetRequiredService(workerType), cancellationToken);

framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Auth/AuthService.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public async Task<LoginInfo> GetLoginInfoAsync()
4747
return null;
4848
}
4949

50-
var url = $"{CliUrls.WwwAbpIo}api/license/login-info";
50+
var url = $"{CliUrls.AccountAbpIo}api/license/login-info";
5151

5252
var client = CliHttpClientFactory.CreateClient();
5353

@@ -130,7 +130,7 @@ public async Task LogoutAsync()
130130

131131
public async Task<bool> CheckMultipleOrganizationsAsync(string username)
132132
{
133-
var url = $"{CliUrls.WwwAbpIo}api/license/check-multiple-organizations?username={username}";
133+
var url = $"{CliUrls.AccountAbpIo}api/license/check-multiple-organizations?username={username}";
134134

135135
var client = CliHttpClientFactory.CreateClient();
136136

framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/CliConsts.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ public static class CliConsts
1212

1313
public static string GithubHttpClientName = "GithubHttpClient";
1414

15-
public static string LogoutUrl = CliUrls.WwwAbpIo + "api/license/logout";
15+
public static string LogoutUrl = CliUrls.AccountAbpIo + "api/license/logout";
1616

1717
public static string LicenseCodePlaceHolder = @"<LICENSE_CODE/>";
1818

framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/Licensing/AbpIoApiKeyService.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public async Task<DeveloperApiKeyResult> GetApiKeyOrNullAsync(bool invalidateCac
5151
return _apiKeyResult;
5252
}
5353

54-
var url = $"{CliUrls.WwwAbpIo}api/license/api-key";
54+
var url = $"{CliUrls.AccountAbpIo}api/license/api-key";
5555
var client = _cliHttpClientFactory.CreateClient();
5656

5757
using (var response = await client.GetHttpResponseMessageWithRetryAsync(url, CancellationTokenProvider.Token, _logger))

framework/src/Volo.Abp.Cli.Core/Volo/Abp/Cli/ProjectBuilding/TemplateInfoProvider.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ private async Task<bool> CheckProLicenseAsync()
8888

8989
try
9090
{
91-
var url = $"{CliUrls.WwwAbpIo}api/license/check-user";
91+
var url = $"{CliUrls.AccountAbpIo}api/license/check-user";
9292
var client = _cliHttpClientFactory.CreateClient();
9393

9494
using (var response = await client.GetHttpResponseMessageWithRetryAsync(url, CancellationTokenProvider.Token, Logger))

0 commit comments

Comments
 (0)