.NET Core MVC多租户场景下自定义客户文本与本地化方案咨询
替代实现方案
方案1:自定义ResourceManager
重写默认ResourceManager,读取资源时优先从客户定制文件获取,失败则回退到默认资源文件。
实现步骤:
- 创建自定义ResourceManager类:
public class CustomResourceManager : ResourceManager { private readonly ResourceManager _defaultResourceManager; private readonly ResourceManager _customerResourceManager; public CustomResourceManager(Type defaultResourceType, Type customerResourceType) : base(defaultResourceType) { _defaultResourceManager = new ResourceManager(defaultResourceType); _customerResourceManager = new ResourceManager(customerResourceType); } public override string GetString(string name) { return GetString(name, Thread.CurrentThread.CurrentUICulture); } public override string GetString(string name, CultureInfo culture) { // 优先读取客户资源 var customerValue = _customerResourceManager.GetString(name, culture); if (!string.IsNullOrEmpty(customerValue)) { return customerValue; } // 回退到默认资源 return _defaultResourceManager.GetString(name, culture); } }
- 在业务代码中使用:
// 初始化:默认资源为HelpText,客户定制资源为HelpText.Cust1 var resourceManager = new CustomResourceManager(typeof(HelpText), typeof(HelpText.Cust1)); var targetText = resourceManager.GetString("TargetKey");
方案2:自定义IStringLocalizerProvider(推荐)
如果项目使用IStringLocalizer框架,自定义提供者实现回退逻辑,更贴合.NET本地化体系。
实现步骤:
- 实现FallbackStringLocalizer:
public class FallbackStringLocalizer : IStringLocalizer { private readonly IStringLocalizer _customerLocalizer; private readonly IStringLocalizer _defaultLocalizer; public FallbackStringLocalizer(IStringLocalizer customerLocalizer, IStringLocalizer defaultLocalizer) { _customerLocalizer = customerLocalizer; _defaultLocalizer = defaultLocalizer; } public LocalizedString this[string name] { get { var customerString = _customerLocalizer[name]; return customerString.ResourceNotFound ? _defaultLocalizer[name] : customerString; } } public LocalizedString this[string name, params object[] arguments] { get { var customerString = _customerLocalizer[name, arguments]; return customerString.ResourceNotFound ? _defaultLocalizer[name, arguments] : customerString; } } public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) { // 合并客户与默认资源,客户资源优先去重 var customerStrings = _customerLocalizer.GetAllStrings(includeParentCultures); var defaultStrings = _defaultLocalizer.GetAllStrings(includeParentCultures); return customerStrings.Concat(defaultStrings.Where(s => !customerStrings.Any(c => c.Name == s.Name))); } public IStringLocalizer WithCulture(CultureInfo culture) { return new FallbackStringLocalizer(_customerLocalizer.WithCulture(culture), _defaultLocalizer.WithCulture(culture)); } }
- 实现自定义LocalizerProvider:
public class FallbackStringLocalizerProvider : IStringLocalizerProvider { private readonly IStringLocalizerFactory _factory; private readonly string _customerPrefix; public FallbackStringLocalizerProvider(IStringLocalizerFactory factory, string customerPrefix) { _factory = factory; _customerPrefix = customerPrefix; } public IStringLocalizer Create(Type resourceSource) { var defaultLocalizer = _factory.Create(resourceSource); var customerResourceType = Type.GetType($"{resourceSource.FullName}.{_customerPrefix}, {resourceSource.Assembly.GetName().Name}"); var customerLocalizer = customerResourceType != null ? _factory.Create(customerResourceType) : defaultLocalizer; return new FallbackStringLocalizer(customerLocalizer, defaultLocalizer); } public IStringLocalizer Create(string baseName, string location) { var defaultLocalizer = _factory.Create(baseName, location); var customerBaseName = $"{baseName}.{_customerPrefix}"; var customerLocalizer = _factory.Create(customerBaseName, location); return new FallbackStringLocalizer(customerLocalizer, defaultLocalizer); } }
- 在Startup.cs中注册服务:
public void ConfigureServices(IServiceCollection services) { services.AddLocalization(options => options.ResourcesPath = "Resources"); services.AddSingleton<IStringLocalizerProvider>(sp => { var factory = sp.GetRequiredService<IStringLocalizerFactory>(); // 传入客户标识Cust1,可根据请求上下文动态获取(如从路由/请求头) return new FallbackStringLocalizerProvider(factory, "Cust1"); }); services.AddControllersWithViews(); }
- 注入使用:
public class HomeController : Controller { private readonly IStringLocalizer<HelpText> _localizer; public HomeController(IStringLocalizer<HelpText> localizer) { _localizer = localizer; } public IActionResult Index() { ViewBag.TargetText = _localizer["TargetKey"]; return View(); } }
方案3:手动封装资源读取服务
小型项目可直接编写服务类,手动处理回退逻辑:
public class ResourceService { public string GetResourceValue(string key, string customerId, CultureInfo culture) { // 尝试读取客户资源 var customerResType = Type.GetType($"YourNamespace.Resources.HelpText.{customerId}, YourAssemblyName"); if (customerResType != null) { var customerValue = new ResourceManager(customerResType).GetString(key, culture); if (!string.IsNullOrEmpty(customerValue)) { return customerValue; } } // 回退到默认资源 return new ResourceManager(typeof(HelpText)).GetString(key, culture); } }
在控制器中实例化或注入该服务,直接调用方法获取资源值即可。
内容的提问来源于stack exchange,提问作者HelpMe
相关产品推荐
相关产品推荐

