Hi,
To save you the time of preparing a full demo project, could you instead email us your Blazorise product token directly? We'll plug it into a fresh Blazor Web App + Tiered solution on our side and see if the footer still shows up there. That should quickly tell us whether the issue is with the token itself or with something specific to your project setup.
Please send it to: liming.ma@volosoft.com
If there is any problem, we will contact Blazorise technical support directly.
Thanks
Hi,
Thanks for the correction — you're right. The Split License has applied since ImageSharp v3.0.0; the v4 .lic enforcement just makes it visible at build time. I shouldn't have written "free on 3.x" without that qualifier.
Where ImageSharp comes from on our side today:
SixLabors.ImageSharp from 2.1.6 to 3.0.2 in ABP 8.0, pinned at 3.1.11 on dev. We don't plan to move to v4 while the paid-license model stays as it is.abp/ codebase and all project templates do not reference ImageSharp directly. The transitive reference in a Pro solution comes from Volo.Abp.Account.Pro.Public.Application, which today depends on AbpImagingImageSharpModule to compress user avatars via IImageCompressor.Agreed — patching ABP source on every build isn't a workflow we should expect from customers, especially when source access is there for fast zero-day responses.
Plan for ABP 10.4:
Volo.Abp.Account.Pro.Public.Application from any specific imaging implementation — it will depend only on Volo.Abp.Imaging.Abstractions. The default implementation will be picked at the application level, so swapping it out won't require touching ABP source.ImageCompressorContributor implementation to Volo.Abp.Imaging.SkiaSharp (today that package only ships a resizer).Magick.NET-Q16-AnyCPU past the currently reported NuGet vulnerability warnings, assuming an upstream fixed version is available.Before 10.4 ships, the simplest workaround: ABP already ships a Magick.NET-based implementation in Volo.Abp.Imaging.MagickNet (Apache 2.0), which provides both compressor and resizer contributors. Reference that package in your own *.Application module, depend on AbpImagingMagickNetModule, and explicitly remove the ImageSharp contributors from the DI container. Just adding DependsOn(AbpImagingMagickNetModule) isn't enough on its own — both contributors would coexist in the container, and ABP's IImageCompressor iterates the registered contributors and uses the first one that supports the input mime type, so ImageSharp would still run at runtime. After RemoveAll, only the Magick.NET contributors remain and ABP's conventional registration picks them up automatically — no custom code needed.
MyCompanyName.MyProjectName.Application.csproj:
<PackageReference Include="Volo.Abp.Imaging.MagickNet" Version="x.y.z" />
MyProjectNameApplicationModule.cs:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Volo.Abp.Imaging;
using Volo.Abp.Modularity;
[DependsOn(typeof(AbpImagingMagickNetModule))]
// ... your existing DependsOn list
public class MyProjectNameApplicationModule : AbpModule
{
public override void ConfigureServices(ServiceConfigurationContext context)
{
context.Services.RemoveAll(d =>
d.ServiceType == typeof(IImageCompressorContributor) &&
d.ImplementationType == typeof(ImageSharpImageCompressorContributor));
context.Services.RemoveAll(d =>
d.ServiceType == typeof(IImageResizerContributor) &&
d.ImplementationType == typeof(ImageSharpImageResizerContributor));
}
}
After that, IImageCompressor and IImageResizer use the Magick.NET contributors at runtime for these interfaces. You can pin the underlying Magick.NET-Q16-AnyCPU to whichever version you've audited.
One thing to be aware of for license compliance: this RemoveAll only stops ABP imaging services from invoking ImageSharp at runtime. Because Volo.Abp.Account.Pro.Public.Application still has DependsOn(typeof(AbpImagingImageSharpModule)) in 10.3, both Volo.Abp.Imaging.ImageSharp.dll and SixLabors.ImageSharp.dll will still be restored and copied to your build output as transitive dependencies. The transitive package reference itself will go away in 10.4 once we decouple the Account module from a specific imaging implementation. Whether the runtime-only avoidance is enough for your compliance position is a call you'll need to make against the Six Labors Split License terms.
If neither ImageSharp nor Magick.NET works for you, IImageCompressor / IImageResizer (and their IImageCompressorContributor / IImageResizerContributor) are plain DI abstractions — you can register your own implementation backed by any library you trust (NetVips, libvips wrappers, your own code, etc.) in your own module. Outside the current Account.Pro module dependency in 10.3, the imaging services are abstractions you swap at the application level; the Volo.Abp.Imaging.* packages are just convenience implementations on top of those abstractions.
Thanks
Hi,
The blazor-webapp + tiered template already has placeholders for ProductToken in both Module files. Please make sure the token is set exactly in those two places:
MethodInsight.Blazor project → MethodInsightBlazorModule.cs → ConfigureBlazorise():context.Services
.AddBlazorise(options =>
{
options.ProductToken = "your-token-here";
})
.AddBootstrap5Providers()
.AddFontAwesomeIcons();
MethodInsight.Blazor.Client project → MethodInsightBlazorClientModule.cs → ConfigureBlazorise() (same shape).A few things to share / try so we can pinpoint the issue:
Could you paste the actual ConfigureBlazorise method from both Module files? We want to confirm the change went into the existing template placeholder and not, for example, an extra AddBlazorise(...) call in Program.cs or OnApplicationInitialization.
WASM build / cache is the most common cause when the Client side looks unchanged:
bin/ and obj/ in both MethodInsight.Blazor and MethodInsight.Blazor.Client projects.Log in at https://blazorise.com/account/user/manage/license with the same email as your abp.io developer account and confirm your active ABP license is listed there. If it isn't shown on the Blazorise side, the token won't be recognized and the free footer stays.
When did you generate the token? The sync between abp.io and Blazorise isn't always instant — if it was generated very recently, give it some time (or regenerate after the sync completes) and try again.
Double-check the token string for stray leading/trailing whitespace or smart quotes from copy-paste.
Thanks
Hi,
Quick clarification on the current state: ABP pins SixLabors.ImageSharp to 3.1.11 in Directory.Packages.props. Per the SixLabors announcement, the sixlabors.lic requirement only applies to ImageSharp 4.0.0+, so building ABP itself does not need a license file. The error you're seeing is almost certainly because your own solution is overriding the package to 4.x.
About our plan: if SixLabors keeps the paid-license model on v4+, we won't upgrade SixLabors.ImageSharp to a paid version. We'll either stay on 3.x or move to a free, open-source alternative.
You don't need to wait for us though — ABP already abstracts image manipulation behind IImageResizer / IImageCompressor, and ships three independent implementations. You can switch any time:
| Package | Underlying library | License |
|---|---|---|
| Volo.Abp.Imaging.ImageSharp | SixLabors.ImageSharp 3.x | Six Labors Split License (free on 3.x) |
| Volo.Abp.Imaging.MagickNet | Magick.NET | Apache 2.0 |
| Volo.Abp.Imaging.SkiaSharp | SkiaSharp | MIT |
Just swap the ImageSharp package and module dependency for the Magick.NET or SkiaSharp one — your business code keeps using the same IImageResizer / IImageCompressor abstractions, no code changes needed.
Docs: https://abp.io/docs/latest/framework/infrastructure/image-manipulation
Thanks
Great 👍
Hi,
回到本地复现一下你这次的现象——我把 Customer 加成"非分表实体"放进同一个 AppDbContext(和 SpcAutoAnalyse 等价的 sharded 实体并存),manager 内部用默认的 autoSave: false 调 IRepository.InsertAsync(customer),模块里同样开 AbpMultiTenancyOptions.IsEnabled = true 和 Inbox/Outbox:
| 实体 | 是否注册分表路由 | InsertAsync 参数 | 结果 |
|---|---|---|---|
| Order(分表) | ✅ OrderMonthRoute | autoSave: true | INSERT 到 Orders_yyyyMM ✅ |
| Customer(非分表) | ❌ | autoSave: false(默认) | UoW Complete 时批量 INSERT 到 Customers ✅ |
SQL 输出:
INSERT INTO `Orders_202512` (`Id`, `Code`, `CreationTime`, `CreatorId`, `TenantId`) VALUES (...)
INSERT INTO `Orders_202601` (...) VALUES (...)
INSERT INTO `Orders_202605` (...) VALUES (...)
INSERT INTO `Customers` (`Id`, `CreationTime`, `CreatorId`, `Name`, `TenantId`) VALUES (...), (...)
这个最小 stack 比你实际项目少了不少东西(AuditLogging / Identity / Saas / 自定义 PermissionChecker / 自定义 ExceptionFilter / 你自己的 RedisMessageProcessor 等模块都没复刻),所以只能说明在等价的核心 stack 下非分表实体能正常写入,不能直接断定你那边的问题不是 ShardingCore 引起的。需要看真实日志才能继续定位,麻烦你做两步:
看 EF Core SQL 日志。把日志级别开到 Information:
"Logging": {
"LogLevel": {
"Microsoft.EntityFrameworkCore.Database.Command": "Information",
"Microsoft.EntityFrameworkCore": "Information"
}
}
然后调一次 SPCHandAnalysis 的 swagger create,把这次调用过程的所有日志贴上来。关注 3 件事:
INSERT INTO tblSPCHandAnalyses ... 这条 SQLDbUpdateExceptionBegin Uow、Complete Uow、Rollback Uow)顺便把 SPCHandAnalysisManager.CreateAsync(...) 最后一行的 InsertAsync 也加上 autoSave: true 再跑一次:
return await _sPCHandAnalysisRepository.InsertAsync(sPCHandAnalysis, true);
这样 SaveChanges 时机被提前到 manager 里,SQL 日志和异常更直观。
把 1 的完整日志贴上来后再继续定位。
Thanks
Hi thanhvl1,
Excellent debugging — that nails it down to the Cookie header.
To confirm exactly what's happening on the server side, could you share the full AuthServer Debug log for one reproduction of the /api/account/user-sharing call?
To enable Debug-level logs, please follow this guide: https://abp.io/support/questions/8622/How-to-enable-Debug-logs-for-troubleshoot-problems
Then restart AuthServer, sign in, switch to a tenant, open the Switch Tenant modal once, and attach the complete log (please don't trim it).
Thanks!
Hi thanhvl1,
Great comparison — Angular vs Postman returning different responses with the same token strongly points to Angular sending something extra in the request that's changing the server's behavior.
Could you share two things?
The full Request Headers of the Angular call to /api/account/user-sharing from DevTools Network — please include all headers (not just Authorization), especially any Cookie, Origin, Referer, or __tenant-style headers. A screenshot of the fully expanded Request Headers section works.
How are the Angular app and AuthServer exposed on AKS? Same domain (e.g. app.example.com and app.example.com/authserver) or different domains (e.g. app.example.com and authserver.example.com)? If they share a domain, the browser may be sending the AuthServer's session cookie automatically along with the Bearer token, which could change how the server authenticates the request.
Once we see the headers and the deployment layout, we can pinpoint and fix it.
Thanks!
Hi,
你的项目我下载下来看了,根因已经定位到,能 100% 在本地复现。
SpcServiceDbContext.cs 第 218-221 行,GetShardingExecutor 写错了一个字符:
private IShardingDbContextExecutor _executor;
public IShardingDbContextExecutor GetShardingExecutor()
{
return _executor ?? this.CreateShardingDbContextExecutor(); // ← bug: ?? 不会赋值
}
应该改成 ??=(空合并赋值):
public IShardingDbContextExecutor GetShardingExecutor()
{
return _executor ??= this.CreateShardingDbContextExecutor();
}
只改这一行,新增数据就能正常落到 tblSpcAutoAnalyses_yyyyMM 分表了。
?? 会导致 INSERT 静默丢失?? 是空合并:_executor ?? expr 只是返回值,不会把 expr 赋给 _executor,所以每次 GetShardingExecutor() 都 new 一个全新的 ShardingDbContextExecutor 实例。
ABP UoW 调 SaveChangesAsync 时走的是 ShardingCore 替换的 ShardingStateManager.SaveChangesAsync → 它每次都从 dbContext.GetShardingExecutor() 拿 executor 来分发实体到分表 DbContext。新 new 出来的 executor 没有任何已分发的实体/分表 DbContext 缓存,路由结果是"空",于是一条 INSERT 也不发,最终 ABP UoW 看到的是"0 行受影响、操作成功",HTTP 返回 200,但 DB 里什么都没写入。
我把你 DbContext 关键的几个特性都搬到本地最小项目里做了对照验证:DbContext 实现 IHasEventInbox + IHasEventOutbox,模块里 Configure<AbpMultiTenancyOptions>(opts => opts.IsEnabled = true) 开多租户,Configure<AbpDistributedEventBusOptions> 把 Inbox/Outbox 都挂到 DbContext,实体继承 CreationAuditedEntity<Guid> + IMultiTenant,应用服务走 OrderManager.CreateAsync → IRepository.InsertAsync(autoSave: true) 链路,和你完全一致。
?? 版(复刻你的写法):
OK: ABP + ShardingCore + MySQL initialized successfully.
Query returned 0 rows:
Orders_202512: []
Orders_202601: []
...
改成 ??= 后:
INSERT INTO `Orders_202512` (`Id`, `Code`, `CreationTime`, `CreatorId`, `TenantId`) VALUES (...)
INSERT INTO `Orders_202601` (`Id`, `Code`, `CreationTime`, `CreatorId`, `TenantId`) VALUES (...)
INSERT INTO `Orders_202605` (`Id`, `Code`, `CreationTime`, `CreatorId`, `TenantId`) VALUES (...)
Query returned 3 rows:
Orders_202512: [D-2512]
Orders_202601: [J-2601]
Orders_202605: [M-2605]
现象和你完全一致:?? 静默 0 行写入、??= 正常路由到月份分表。
注意你项目里还有一个基类文件 ShardingAbpDbContext.cs(line 28-30)写的是正确的 ??=,但 SpcServiceDbContext 没继承这个基类,而是直接继承 AbpDbContext<> 然后重新写了一遍 GetShardingExecutor——这次复制粘贴时把 ??= 抄成了 ??。
这个我没有现成可工作的方案验证。两套机制冲突在于:
IConnectionStringResolver 按当前 tenant 解析 connection string(每个 tenant 可以是不同的物理库);IVirtualDataSource 自己维护 dataSourceName → connection string 的字典,启动时通过 AddDefaultDataSource("ds0", connStr) 静态注册。如果你的多租户场景是"所有 tenant 共享一个物理库 + 按 tenant 分表",那其实不用动 IVirtualDataSource,让 ABP 的 connStr 统一指向同一个库即可,分表后缀走 ShardingCore 的路由就行。
如果是"每个 tenant 一个物理库 + 库内再按月分表",那需要在 tenant 切换时动态注入新的 dataSource 到 IVirtualDataSource,并实现 IVirtualDataSourceRoute 把 tenantId 路由到 dataSourceName。这块 ShardingCore 自己有 AddPhysicDataSource 之类的 API,但要和 ABP 的 CurrentTenant.Change(...) 流程配合,我没在本地验证过,遇到具体问题再单独看。
建议你先把第一个 ?? 的 bug 改了,确认插入和查询都没问题之后再处理多租户的设计。
Thanks