ASP.NET MVC Core如何支持从多个资源路径读取本地化资源?
解决ASP.NET Core MVC同时读取多位置本地化资源的问题
这个问题我之前在做模块化ASP.NET Core项目的时候碰到过,本质是默认的本地化配置只能盯着一个资源路径/程序集找,没法同时覆盖MVC项目的视图资源和独立DLL里的服务资源。下面给你两种可行的解决方案,你可以根据自己的项目情况选:
方案一:自定义本地化工厂(通用型,支持多个资源程序集)
这种方法会扩展默认的本地化逻辑,让它在找不到资源时自动去你指定的额外程序集里搜索,同时保留MVC项目Resources目录的读取能力。
步骤1:确保DLL里的资源是嵌入资源
右键应用服务DLL里的资源文件 → 属性 → 把生成操作设置为「嵌入的资源」,这样资源会被打包进DLL,本地化系统才能读取到。
步骤2:实现自定义本地化工厂
创建一个继承自ResourceManagerStringLocalizerFactory的类,添加对额外程序集的支持:
public class MultiAssemblyResourceManagerStringLocalizerFactory : ResourceManagerStringLocalizerFactory { private readonly IEnumerable<Assembly> _additionalAssemblies; public MultiAssemblyResourceManagerStringLocalizerFactory( IOptions<LocalizationOptions> localizationOptions, ILoggerFactory loggerFactory, IEnumerable<Assembly> additionalAssemblies) : base(localizationOptions, loggerFactory) { _additionalAssemblies = additionalAssemblies; } protected override ResourceManager CreateResourceManager(string baseName, Assembly assembly) { // 先尝试从当前程序集(MVC项目)找资源 var resourceManager = base.CreateResourceManager(baseName, assembly); if (resourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, false) != null) { return resourceManager; } // 当前程序集找不到,遍历额外程序集查找 foreach (var additionalAssembly in _additionalAssemblies) { try { resourceManager = base.CreateResourceManager(baseName, additionalAssembly); if (resourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, false) != null) { return resourceManager; } } catch { // 忽略找不到的情况,继续尝试下一个程序集 } } return resourceManager; } }
步骤3:在Startup中替换默认工厂
保留ResourcesPath的配置,同时注册自定义工厂并传入应用服务的程序集:
public void ConfigureServices(IServiceCollection services) { // 保留这个配置,让MVC能读取自身Resources目录下的视图资源 services.AddLocalization(options => options.ResourcesPath = "Resources"); // 获取应用服务DLL的程序集(替换成你实际的类名) var appServicesAssembly = typeof(YourAppServiceNamespace.SomeServiceClass).Assembly; // 替换默认的本地化工厂为自定义实现 services.AddSingleton<IStringLocalizerFactory>(sp => { var localizationOptions = sp.GetRequiredService<IOptions<LocalizationOptions>>(); var loggerFactory = sp.GetRequiredService<ILoggerFactory>(); return new MultiAssemblyResourceManagerStringLocalizerFactory( localizationOptions, loggerFactory, new[] { appServicesAssembly }); }); // 其他服务注册... services.AddControllersWithViews(); }
这样配置后,无论是MVC视图里的本地化,还是应用服务中注入IStringLocalizer<T>,都能自动找到对应的资源了。
方案二:单独注册服务专用的本地化器(轻量型)
如果你的项目只需要支持一个额外的应用服务DLL,也可以直接给它注册一个专用的本地化器,不用修改全局工厂:
步骤1:同样确保DLL资源是嵌入资源
和方案一的第一步一样,把应用服务的资源文件设置为嵌入资源。
步骤2:在Startup中注册专用本地化器
public void ConfigureServices(IServiceCollection services) { services.AddLocalization(options => options.ResourcesPath = "Resources"); // 获取应用服务程序集 var appServicesAssembly = typeof(YourAppServiceNamespace.SomeServiceClass).Assembly; // 注册针对应用服务资源的本地化器 services.AddSingleton<IStringLocalizer<AppServicesResourceMarker>>(sp => { var factory = sp.GetRequiredService<IStringLocalizerFactory>(); // 这里的"AppServicesResources"是你DLL里资源文件的基名(比如AppServicesResources.en.resx) return factory.Create("AppServicesResources", appServicesAssembly.FullName); }); services.AddControllersWithViews(); }
注:AppServicesResourceMarker可以是你应用服务DLL里的一个空类,用来标记这个本地化器的用途;或者直接用你资源对应的类名。
步骤3:在应用服务中注入专用本地化器
public class YourAppService { private readonly IStringLocalizer<AppServicesResourceMarker> _localizer; public YourAppService(IStringLocalizer<AppServicesResourceMarker> localizer) { _localizer = localizer; } public string GetErrorMessage() { // 直接读取DLL里的本地化资源 return _localizer["resource_key"]; } }
这种方法更轻量,不需要修改全局的本地化逻辑,适合资源来源比较单一的场景。
额外注意事项
- 资源文件命名要符合ASP.NET Core的规范:MVC视图资源要放在
Resources/Views/{Controller}/{View}.resx;DLL里的资源如果和类同命名空间,要放在对应目录下(比如YourAppService.Resources.Errors.ErrorMessages.en.resx对应YourAppService.Errors.ErrorMessages类)。 - 测试时要确保当前线程的UICulture设置正确,可以通过
RequestCultureProvider或者手动设置CultureInfo.CurrentUICulture来验证。
内容的提问来源于stack exchange,提问作者Simple Code
相关产品推荐
相关产品推荐

