从Razor视图提取HTML Helpers:.NET Core MVC对接旧翻译库问题
优化旧翻译表查询性能的实用方案
嘿,针对你在.NET Core 2.0 MVC应用中对接旧翻译表的性能问题(旧应用每次翻译都单独查数据库,效率太低了),结合数据库不可修改的限制,我整理了几个落地性强的优化方案,都是处理遗留系统时亲测有效的:
1. 预加载所有翻译到内存缓存
翻译数据通常属于低频变更的静态数据,最直接的优化就是启动时一次性加载所有翻译数据到内存,后续所有翻译请求直接从内存读取,彻底避免数据库调用。
实现思路:
- 用线程安全的
ConcurrentDictionary存储翻译映射,键用$"{languageId}_{translationId}"的组合,值为翻译文本。 - 在应用启动阶段(比如
Startup.cs的ConfigureServices里,或者用IHostedService异步加载)执行一次批量查询,把所有翻译数据填充到字典中。 - 为应对翻译数据更新,可添加定时刷新机制(比如每隔几小时重新加载),或者提供手动刷新的后台接口(如果需要即时更新)。
代码示例:
public class TranslationCache { private static ConcurrentDictionary<string, string> _translations = new ConcurrentDictionary<string, string>(); private readonly YourDbContext _dbContext; public TranslationCache(YourDbContext dbContext) { _dbContext = dbContext; LoadTranslations(); } private void LoadTranslations() { var allTranslations = _dbContext.Translations.ToList(); foreach (var trans in allTranslations) { var key = $"{trans.LanguageId}_{trans.TranslationId}"; _translations.TryAdd(key, trans.Text); } } public string GetTranslation(int languageId, int translationId) { var key = $"{languageId}_{translationId}"; _translations.TryGetValue(key, out var text); return text ?? $"[Missing: {translationId}]"; } // 可选:手动刷新缓存 public void RefreshCache() { _translations.Clear(); LoadTranslations(); } }
在Startup.cs里注册为单例:
services.AddSingleton<TranslationCache>();
2. 批量查询+请求级缓存
如果翻译数据量特别大(比如十万级以上),预加载到内存会占用过多资源,这时候可以采用批量查询+请求级缓存的方式:
实现思路:
- 在服务层或视图助手类中,先收集当前请求需要的所有
translationId和对应的languageId。 - 一次性向数据库发起批量查询,获取所有需要的翻译数据。
- 把查询结果缓存到当前请求的
HttpContext.Items中,同一请求内的后续翻译请求直接从这里读取。
代码示例:
public class TranslationService { private readonly YourDbContext _dbContext; private readonly IHttpContextAccessor _httpContextAccessor; public TranslationService(YourDbContext dbContext, IHttpContextAccessor httpContextAccessor) { _dbContext = dbContext; _httpContextAccessor = httpContextAccessor; } public string GetTranslation(int languageId, int translationId) { var cacheKey = $"translations_{languageId}"; if (!_httpContextAccessor.HttpContext.Items.TryGetValue(cacheKey, out var cacheObj)) { // 这里可替换为当前请求收集到的translationId列表,减少不必要的查询 var translations = _dbContext.Translations .Where(t => t.LanguageId == languageId) .ToDictionary(t => t.TranslationId, t => t.Text); _httpContextAccessor.HttpContext.Items[cacheKey] = translations; cacheObj = translations; } var translationDict = (Dictionary<int, string>)cacheObj; return translationDict.TryGetValue(translationId, out var text) ? text : $"[Missing: {translationId}]"; } }
3. 适配.NET Core本地化框架
如果想让翻译逻辑更贴合.NET Core MVC的生态,可以把旧翻译表适配到IStringLocalizer接口中,这样就能直接使用MVC的本地化标签,同时内部优化查询逻辑。
实现思路:
- 自定义
OldDbStringLocalizer类,实现IStringLocalizer接口。 - 在
GetString方法内部,复用预加载缓存或批量查询的方式获取翻译。 - 注册自定义的本地化提供者,替换默认的资源文件本地化。
核心代码示例:
public class OldDbStringLocalizer : IStringLocalizer { private readonly TranslationCache _translationCache; private readonly int _currentLanguageId; public OldDbStringLocalizer(TranslationCache translationCache, IHttpContextAccessor httpContextAccessor) { _translationCache = translationCache; // 从请求上下文获取当前语言ID(示例从Cookie读取,可替换为路由/Header等方式) _currentLanguageId = int.Parse(httpContextAccessor.HttpContext.Request.Cookies["LanguageId"] ?? "1"); } public LocalizedString this[string name] { get { var translationId = int.TryParse(name, out var id) ? id : 0; var text = _translationCache.GetTranslation(_currentLanguageId, translationId); return new LocalizedString(name, text, text == $"[Missing: {translationId}]"); } } // 实现其他接口方法(如GetAllStrings等)... }
在Startup.cs中注册:
services.AddLocalization(options => options.ResourcesPath = "Resources"); services.AddSingleton<IStringLocalizer, OldDbStringLocalizer>();
之后在视图中就能直接使用:
<p>@Localizer["456"]</p>
内容的提问来源于stack exchange,提问作者Arjen L
相关产品推荐
相关产品推荐

