C#读取程序集外的.resx资源文件会抛出MissingManifestResourceException异常。

7
我正在处理一个项目,它包括Asp.Net Web应用程序和Windows服务应用程序。这两个可以使用我创建的共享项目来包含资源文件。我想把资源文件放在程序集外面,这样当我想要更改它们时,就可以在不编译整个解决方案的情况下进行编辑。我搜索了一种方法,并在这里找到了一个:ASP.NET Resourcemanager读取本地.resx
它在Web应用程序上完美运行,但过了一段时间后,我发现Windows服务应用程序无法读取这些资源,我得到了:
System.Resources.MissingManifestResourceException: Could not find any resources appropriate for the specified culture (or the neutral culture) on disk.
baseName: abc  locationInfo: <null>  fileName: abc.resx
   at System.Resources.FileBasedResourceGroveler.GrovelForResourceSet(CultureInfo culture, Dictionary`2 localResourceSets, Boolean tryParents, Boolean createIfNotExists, StackCrawlMark& stackMark)
   at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo requestedCulture, Boolean createIfNotExists, Boolean tryParents, StackCrawlMark& stackMark)
   at System.Resources.ResourceManager.InternalGetResourceSet(CultureInfo culture, Boolean createIfNotExists, Boolean tryParents)
   at System.Resources.ResourceManager.GetObject(String name, CultureInfo culture, Boolean wrapUnmanagedMemStream)
   at System.Resources.ResourceManager.GetObject(String name, CultureInfo culture)
   at yyyy.yyyyyy.yyyyyyy.GetGlobalResourceObject(String classKey, String resourceKey, Boolean getCommon)
   at xxx.xxx.xxx.Entities.xxxxxxxx.get_LocalizedName()
   at yyyyy.Adapters.ArchiverDtoAdapter.CreateArchiverInjectionsDto(InjectionProcedure procedure, INamingService namingService)
   at yyyyy.Adapters.ArchiverDtoAdapter.ConvertInjectionProcedureDto(InjectionProcedure procedure, INamingService namingService)
   at yyyy.Factories.ArchiverDtoFactory.<>c__DisplayClass1.<CreateInjectionProcedureSendRequestDto>b__0(IUnitOfWork unitOfWork)
   at Core.Data.NHibernate.Factory.UnitOfWorkFactoryBase.Create(Action`1 action, IUnitOfWork unitOfWork)
   at Core.Data.NHibernate.Factory.UnitOfWorkFactory.Create(Action`1 action)

我不理解问题的原因,因为一个项目运行正常,而另一个却不行。另一个奇怪的行为是,当我在我的电脑上启动服务并进行调试以查看发生了什么时,它就可以工作。

更新:这是我所使用的代码参考。

public class ResxResourceManager : ResourceManager
    {
        public ResxResourceManager(string baseName, string resourceDir)
        {
            ObjectFactory.ResolveDependencies(this);

            Type[] paramTypes = new Type[] { typeof(string), typeof(string), typeof(Type) };
            object[] paramValues = new object[] { baseName, resourceDir, typeof(ResXResourceSet) };

            Type baseType = GetType().BaseType;

            ConstructorInfo ci = baseType.GetConstructor(
                BindingFlags.Instance | BindingFlags.NonPublic,
                null, paramTypes, null);

            ci.Invoke(this, paramValues);
        }

        protected override string GetResourceFileName(CultureInfo culture)
        {
            string resourceFileName = base.GetResourceFileName(culture);
            return resourceFileName.Replace(".resources", ".resx");
        }
    }

读取清单资源是使用 Assembly 的一个方法完成的:您需要一个包含该资源的程序集实例:请展示您的代码,以便我们可以看到您正在使用哪个程序集。 - Richard
嗨,Richard,问题出现的原因是我不想使用汇编来存储资源。我按照我在问题中提供的链接建议创建了“ResxResourceManager”。我检查了参数是否有误,但区域设置、目录和文件名都正确给出了。 - ertanergun
看这段代码:它在调用自己的基类构造函数时使用了反射 on itself。最好情况下,这将是脆弱的代码(在引用的 A 更新到 .NET 的四年中可能已经破坏了此代码)。为什么不直接调用该构造函数呢?同时,也值得在一个小而专注的原型中使其工作(例如没有 NHibernate 或 UI)。 - Richard
使用默认构造函数,我们需要将资源嵌入到程序集中,以便用户(最终用户)无法在不重新编译所有程序集并对其进行签名的情况下更改任何特定内容。为了避免这种情况,我们希望在外部范围内使用资源。心中的问题是,如果它不能正常工作,则在其他项目或调试模式中也不应该工作。 - ertanergun
抱歉,你误解了,我建议使用 …:base(baseName, resourceDir, typeof(ResXResourceSet)) 而不是反射(因此不在同一对象上调用两个不同的 ResourceManager 构造函数) 。整个反射的使用似乎是在绕过 ResourceManager 的三个参数构造函数不公开:我只能假设它在早期版本的 .NET 中不存在,并且代码没有更新(MSDN 仅回溯到 .NET 2:那时它是公开的)。 - Richard
我尝试了你建议的方法,但是没有接受(baseName, resourceDir, typeof(ResXResourceSet))的基本构造函数。但是过了一会儿,我发现问题完全不同。问题出在我提供的路径字符串上。该路径来自程序集路径,并且由于编码而包含20%(空格)。当我提供本地路径时,该方法运行得非常顺畅。感谢您的时间和帮助。 - ertanergun
1个回答

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接