.NET MAUI Blazor调用ASP.NET MVC API切换语言失效求助
问题场景
开发了两个应用:.NET MAUI Blazor移动应用,以及处理服务端逻辑的ASP.NET MVC API。API的LanguageController中实现了ChangeLanguageApi方法,可根据传入的culture参数设置语言Cookie并返回对应语言的响应消息。使用Swagger/Postman测试时能正常返回对应语言消息,但Blazor应用调用该接口时Cookie未生效,返回消息语言始终不变,Android模拟器和Windows端应用均存在此问题,需实现按传入culture显示对应语言消息。
相关代码
API端ChangeLanguageApi方法
[HttpPost] public IActionResult ChangeLanguageApi([FromBody]string culture) { if (culture == null || !_supportedLanguages.Contains(culture)) { return StatusCode(StatusCodes.Status404NotFound, new Response { IsSuccess = false, Message = Common.SomethingWentWrong, }); } Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), new CookieOptions { Expires = DateTimeOffset.UtcNow.AddMonths(6) }); return StatusCode(StatusCodes.Status200OK, new Response { IsSuccess = true, Message = Common.Success, }); }
API端Program.cs配置
builder.Services.Configure<LanguageSettings>(options => builder.Configuration.GetSection("LanguageSettings").Bind(options)); builder.Services.AddLocalization(options => options.ResourcesPath = "Resources"); var mvcBuilder = builder.Services.AddControllersWithViews().AddDataAnnotationsLocalization(options => { var type = typeof(Resources.Common); var assembly = new AssemblyName(type.GetTypeInfo().Assembly.FullName); var factory = builder.Services.BuildServiceProvider().GetService<IStringLocalizerFactory>(); var localizer = factory.Create("Common", assembly.Name); options.DataAnnotationLocalizerProvider = (t, f) => localizer; }); var app = builder.Build(); var languageSettings = builder.Configuration.GetSection("LanguageSettings:SupportedLanguages").Get<List<string>>(); var supportedCultures = new List<CultureInfo>(); languageSettings.ForEach(x => supportedCultures.Add(new CultureInfo(x))); app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("en"), SupportedCultures = supportedCultures, SupportedUICultures = supportedCultures });
Blazor端切换语言代码
public async Task<Response> ChangeLanguage(string language) { var returnResponse = new Response(); using (var client = new HttpClient()) { var url = $"{Settings.BaseUrl}{Apis.ChangeLanguage}"; var serializedStr = JsonConvert.SerializeObject(language); var response = await client.PostAsync(url, new StringContent(serializedStr, Encoding.UTF8, "application/json")); if (response.IsSuccessStatusCode) { string contentStr = await response.Content.ReadAsStringAsync(); returnResponse = JsonConvert.DeserializeObject<Response>(contentStr); } } return returnResponse; }
问题分析
- HttpClient无自动Cookie管理:Blazor中默认的
HttpClient不会自动存储Cookie,也不会在后续请求中携带Cookie,而Swagger/Postman会自动处理Cookie生命周期,导致测试正常但Blazor调用无效。 - 当前请求未应用新语言:API设置Cookie后,当前请求的本地化上下文已初始化,返回的消息仍使用旧文化设置;同时因为Blazor未携带Cookie,后续请求也无法读取新的语言配置。
- 中间件顺序问题:若
UseRequestLocalization中间件位置靠后,会导致请求未先处理本地化逻辑,Cookie无法生效。
解决方案
1. Blazor端手动管理Cookie
使用CookieContainer存储API返回的Cookie,并持久化到应用本地存储,后续请求携带该Cookie:
public async Task<Response> ChangeLanguage(string language) { var returnResponse = new Response(); var cookieContainer = new CookieContainer(); using (var handler = new HttpClientHandler { CookieContainer = cookieContainer }) using (var client = new HttpClient(handler)) { var apiUri = new Uri($"{Settings.BaseUrl}{Apis.ChangeLanguage}"); var serializedStr = JsonConvert.SerializeObject(language); var response = await client.PostAsync(apiUri, new StringContent(serializedStr, Encoding.UTF8, "application/json")); // 持久化Cookie到MAUI Preferences var cookies = cookieContainer.GetCookies(apiUri); foreach (Cookie cookie in cookies) { Preferences.Set(cookie.Name, cookie.Value); } if (response.IsSuccessStatusCode) { string contentStr = await response.Content.ReadAsStringAsync(); returnResponse = JsonConvert.DeserializeObject<Response>(contentStr); } } return returnResponse; }
2. 全局HttpClient携带Cookie
注册全局HttpClient时自动添加存储的Cookie:
// 在MAUI Blazor的Program.cs中配置 builder.Services.AddScoped(sp => { var handler = new HttpClientHandler(); var client = new HttpClient(handler) { BaseAddress = new Uri(Settings.BaseUrl) }; // 读取本地存储的语言Cookie并添加到请求 var langCookie = Preferences.Get(CookieRequestCultureProvider.DefaultCookieName, string.Empty); if (!string.IsNullOrEmpty(langCookie)) { handler.CookieContainer.Add(new Uri(Settings.BaseUrl), new Cookie(CookieRequestCultureProvider.DefaultCookieName, langCookie)); } return client; });
3. 让API立即返回对应语言消息
在ChangeLanguageApi中手动设置当前线程文化,确保本次响应直接使用新语言:
[HttpPost] public IActionResult ChangeLanguageApi([FromBody]string culture) { if (culture == null || !_supportedLanguages.Contains(culture)) { return StatusCode(StatusCodes.Status404NotFound, new Response { IsSuccess = false, Message = Common.SomethingWentWrong }); } // 手动切换当前线程文化 var targetCulture = new CultureInfo(culture); Thread.CurrentThread.CurrentCulture = targetCulture; Thread.CurrentThread.CurrentUICulture = targetCulture; Response.Cookies.Append(CookieRequestCultureProvider.DefaultCookieName, CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)), new CookieOptions { Expires = DateTimeOffset.UtcNow.AddMonths(6), HttpOnly = false }); // 允许客户端读取 return StatusCode(StatusCodes.Status200OK, new Response { IsSuccess = true, Message = Common.Success }); }
4. 调整API中间件顺序
确保UseRequestLocalization在路由、授权中间件之前执行:
var app = builder.Build(); // 先处理本地化 var languageSettings = builder.Configuration.GetSection("LanguageSettings:SupportedLanguages").Get<List<string>>(); var supportedCultures = new List<CultureInfo>(); languageSettings.ForEach(x => supportedCultures.Add(new CultureInfo(x))); app.UseRequestLocalization(new RequestLocalizationOptions { DefaultRequestCulture = new RequestCulture("en"), SupportedCultures = supportedCultures, SupportedUICultures = supportedCultures }); // 再执行其他中间件 app.UseRouting(); app.UseAuthorization(); app.MapControllers(); app.Run();
内容的提问来源于stack exchange,提问作者Wosełko
相关产品推荐
相关产品推荐

