Blazor IStringLocalizer 向服务注入
Posted
技术标签:
【中文标题】Blazor IStringLocalizer 向服务注入【英文标题】:Blazor IStringLocalizer injection to services 【发布时间】:2021-05-15 05:08:41 【问题描述】:我正在使用 IStringLocalizer
方法来本地化我的 Blazor 应用程序,如 here 所述。
在剃须刀页面上注入IStringLocalizer
效果很好。我还需要它来本地化一些服务 - 无论是范围服务还是单例服务。
使用构造函数注入将我的IStringLocalizer
服务注入到服务中。但是,当用户通过 UI 更改语言时,服务(无论是单例还是作用域)保持 initial IStringLocalizer
- 即启动时使用 original 语言的服务应用程序,而不是用户选择的更新语言。
从代码中检索更新的IStringLocalizer
的建议方法是什么?
编辑
为了防止更多细节,这里有一些代码。
首先,我添加一个Resources
文件夹并在其中创建一个默认的LocaleResources.resx
(带有公共修饰符)和一个LocaleResources.fr.resx
文件,其中包含每种语言的键值对。
支持的文化在appsettings.json
文件中定义为
"Cultures":
"en-US": "English",
"fr": "Français (Suisse)",
...
在启动时,我注册了Resources
文件夹和支持的文化:
public void ConfigureServices(IServiceCollection services
...
services.AddLocalization(options => options.ResourcesPath = "Resources");
...
services.AddSingleton<MySingletonService>();
services.AddScoped<MyScopedService>();
// --- helper method to retrieve the Cultures from appsettings.json
protected RequestLocalizationOptions GetLocalizationOptions()
var cultures = Configuration.GetSection("Cultures")
.GetChildren().ToDictionary(x => x.Key, x => x.Value);
var supportedCultures = cultures.Keys.ToArray();
var localizationOptions = new RequestLocalizationOptions()
.AddSupportedCultures(supportedCultures)
.AddSupportedUICultures(supportedCultures);
return localizationOptions;
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
...
app.UseRequestLocalization(GetLocalizationOptions());
...
app.UseEndpoints(endpoints =>
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
);
我在项目的根目录下创建了一个空的LocaleResources.razor
控件(这是用于将单个资源文件注入所有组件的技巧)。
我包含了一个路由控制器来更改语言:
[Route("[controller]/[action]")]
public class CultureController : Controller
public IActionResult SetCulture(string culture, string redirectUri)
if (culture != null)
HttpContext.Response.Cookies.Append(
CookieRequestCultureProvider.DefaultCookieName,
CookieRequestCultureProvider.MakeCookieValue(
new RequestCulture(culture)));
return LocalRedirect(redirectUri);
语言 UI 切换器看起来像这样(我在这里使用 SyncFusion 控件,但实际上它可以是任何查找,这并不重要)
@inject NavigationManager NavigationManager
@inject IConfiguration Configuration
<SfComboBox TValue="string" TItem="Tuple<string, string>" Placeholder="Select language" DataSource="@Cultures"
@bind-Value="selectedCulture" CssClass="lan-switch" Width="80%">
<ComboBoxFieldSettings Text="Item2" Value="Item1"></ComboBoxFieldSettings>
</SfComboBox>
<style>
.lan-switch
margin-left: 5%;
</style>
@code
string _activeCulture = System.Threading.Thread.CurrentThread.CurrentCulture.Name;
private string selectedCulture
get => _activeCulture;
set
_activeCulture = value;
SelectionChanged(value);
List<Tuple<string, string>> Cultures;
protected override void OnInitialized()
var cultures = Configuration.GetSection("Cultures")
.GetChildren().ToDictionary(x => x.Key, x => x.Value);
Cultures = cultures.Select(p => Tuple.Create<string, string>(p.Key, p.Value)).ToList();
protected override void OnAfterRender(bool firstRender)
if (firstRender && selectedCulture != AgendaSettings.SelectedLanguage)
selectedCulture = AgendaSettings.SelectedLanguage;
private void SelectionChanged(string culture)
if (string.IsNullOrWhiteSpace(culture))
return;
AgendaSettings.SelectedLanguage = culture;
var uri = new Uri(NavigationManager.Uri)
.GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
var query = $"?culture=Uri.EscapeDataString(culture)&" +
$"redirectUri=Uri.EscapeDataString(uri)";
NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
最后,到了注入。我将IStringLocalizer
注入页面如下,它在剃须刀控件上运行良好:
@inject IStringLocalizer<LocaleResources> _loc
<h2>@_loc["hello world"]</h2>
以上,当我更改语言时,页面显示相应资源文件中的值。
现在,对于服务:MySingletonService
和 MyScopedService
在启动时注册。他们都有一个像
protected IStringLocalizer<LocaleResources> _loc;
public MySingletonService(IStringLocalizer<LocaleResources> loc)
_loc = loc;
public void someMethod()
Console.WriteLine(_loc["hello world"])
我在计时器上运行someMethod
。奇怪的是,当我打破上述行时,结果似乎摇摆不定:一旦它返回默认语言的值,一旦本地化......!
【问题讨论】:
我认为问题在于语言更改逻辑,而不是 IStringLocalizer。但这很难说,你需要提供更多关于代码到底在做什么的信息。 您没有提供足够的信息(至少对我而言)来了解IStringLocalizer
如何基于用户选择的语言。所选语言是IStringLocalizer
实例的构造函数参数吗?如果是这样,则意味着您的服务可能超出了包含语言更改的范围。但是你真的需要在这里提供一个更具体(而且仍然很简短)的例子。
好的,让我调整一下问题,让它足够清楚!
【参考方案1】:
我的问题的答案是:你的代码是正确的!
我发现原因是我使用了在默认 App 的起始页上启动的 Scoped 服务:
protected async override Task OnAfterRenderAsync(bool firstRender)
if (firstRender)
MyScopedService.StartTimer();
await base.OnAfterRenderAsync(firstRender);
当用户更改语言时,会刷新整个页面并创建范围服务的新实例并启动计时器。由于我的服务没有实现IDisposable
,定时器实际上并没有停止。
这里有两个解决方案:
-
使用单例服务
将服务设为一次性,并确保在服务处理完毕后取消任务。
【讨论】:
以上是关于Blazor IStringLocalizer 向服务注入的主要内容,如果未能解决你的问题,请参考以下文章
如何将IStringLocalizer注入IApplicationModelConvention?
带有 IStringLocalizer 的 RazorPages 不起作用
除了 dbContext 之外,如何向 Blazor 中的服务添加参数?