Blazor WebAssembly已注册服务仍提示‘无注册服务’问题排查
问题场景
我有一个采用WebAssembly渲染模式的Blazor应用。客户端Demo页面代码如下:
@page "/demo" @page "/{lang}/demo" @inject IDemoService DemoService @inject ICsvImportService CsvImportService @inject ILanguageService LanguageService ... @code { [Parameter] public required string Lang { get; set; } protected override void OnParametersSet() { text = LanguageService.GetLocalizedStrings("AppName.Client.Localization.Strings.Demo.csv", Lang ?? Constants.SupportedLanguages[0]); } ... }
服务在客户端Program.cs中的注册方式:
string apiUrl = "https://localhost:7254"; // TODO move to appsettings.json string apiVersion = "/api/v1"; builder.Services.AddRefitClient<IDemoService>() .ConfigureHttpClient(c => c.BaseAddress = new Uri($"{apiUrl}{apiVersion}")); builder.Services.AddScoped<IEmbeddedCsvService, EmbeddedCsvService>(); builder.Services.AddScoped<ILanguageService, LanguageService>(); builder.Services.AddScoped<ICsvImportService, CsvImportService>();
偶发出现以下错误(比如手动修改URL语言代码时):
InvalidOperationException: Cannot provide a value for property 'DemoService' on type 'AppName.Client.Features.Calculation.Demo.Page.Demo'. There is no registered service of type 'AppName.Client.Features.Calculation.Demo.Service.IDemoService'.
奇怪的是页面加载后调用API时服务又能正常工作,后续发现即使不修改语言版本、非Refit相关服务也会出现此问题。
解决方法
1. 修复路由参数的必填约束与默认值
Lang参数标记为required,但访问/demo路由时无参数传入,会导致组件初始化阶段参数绑定异常,间接引发服务注入问题。修改参数定义:
[Parameter] public string Lang { get; set; } = Constants.SupportedLanguages[0];
同时简化OnParametersSet逻辑:
protected override void OnParametersSet() { text = LanguageService.GetLocalizedStrings("AppName.Client.Localization.Strings.Demo.csv", Lang); }
2. 调整服务注册顺序
将Refit客户端注册放在自定义Scoped服务之前,避免边缘场景下的依赖解析时机问题:
// 优先注册Refit客户端 builder.Services.AddRefitClient<IDemoService>() .ConfigureHttpClient(c => c.BaseAddress = new Uri($"{apiUrl}{apiVersion}")); // 再注册其他自定义服务 builder.Services.AddScoped<IEmbeddedCsvService, EmbeddedCsvService>(); builder.Services.AddScoped<ILanguageService, LanguageService>(); builder.Services.AddScoped<ICsvImportService, CsvImportService>();
3. 改用构造函数注入替代属性注入
属性注入在Blazor组件初始化的某些阶段可能存在解析延迟,构造函数注入能确保服务在组件实例化时就被正确解析:
@page "/demo" @page "/{lang}/demo" @code { private readonly IDemoService _demoService; private readonly ICsvImportService _csvImportService; private readonly ILanguageService _languageService; private string text; [Parameter] public string Lang { get; set; } = Constants.SupportedLanguages[0]; // 构造函数注入所有依赖服务 public Demo(IDemoService demoService, ICsvImportService csvImportService, ILanguageService languageService) { _demoService = demoService; _csvImportService = csvImportService; _languageService = languageService; } protected override void OnParametersSet() { text = _languageService.GetLocalizedStrings("AppName.Client.Localization.Strings.Demo.csv", Lang); } ... }
4. 禁用页面的预渲染(若启用)
如果应用开启了预渲染(如Static Web Apps预渲染或服务器端预渲染),客户端服务在预渲染阶段无法被解析,会触发异常。给页面添加属性禁用预渲染:
@attribute [RenderModeWebAssembly]
5. 清理缓存并重新构建
Blazor WebAssembly的缓存可能导致旧代码未更新,执行以下操作:
- 强制刷新浏览器(Ctrl+Shift+R)
- 删除客户端项目的
bin和obj目录,重新构建项目
内容的提问来源于stack exchange,提问作者ZdenekF

