You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NET Core MVC多租户场景下自定义客户文本与本地化方案咨询

替代实现方案

方案1:自定义ResourceManager

重写默认ResourceManager,读取资源时优先从客户定制文件获取,失败则回退到默认资源文件。

实现步骤:

  1. 创建自定义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);
    }
}
  1. 在业务代码中使用:
// 初始化:默认资源为HelpText,客户定制资源为HelpText.Cust1
var resourceManager = new CustomResourceManager(typeof(HelpText), typeof(HelpText.Cust1));
var targetText = resourceManager.GetString("TargetKey");

方案2:自定义IStringLocalizerProvider(推荐)

如果项目使用IStringLocalizer框架,自定义提供者实现回退逻辑,更贴合.NET本地化体系。

实现步骤:

  1. 实现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));
    }
}
  1. 实现自定义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);
    }
}
  1. 在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();
}
  1. 注入使用:
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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 13:05:19