winforms C# System.IO.FileNotFoundException当尝试加载资源时(.Net Framework 4.8)

jtoj6r0c  于 2023-04-21  发布在  C#
关注(0)|答案(1)|浏览(287)

我有个项目(它开始作为遗留代码),我一直在工作的某个时候。最近我需要发布最新版本,以便它可以在单独的计算机上使用。长话短说,通过Visual Studio使用一键式发布器我一直得到一个System.IO.FileNotFoundException.我使用VS调试器来跟踪错误的位置。在附加assemblyResolve处理程序后,我发现问题来自这行代码:

this.imlProcesses.ImageStream = ((System.Windows.Forms.ImageListStreamer)(resources.GetObject("imlProcesses.ImageStream")));

到达这里的代码路径如下。Main()运行frmMain(MainForm的一个分部类,表示Windows窗体)。然后此函数调用InitalizeComponent()。在最初的几行代码中,componentResourceManager是使用以下行设置的:

System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(frmMain));

然后它继续执行,进行正常的窗口窗体设计器设置,加载和示例化所有GUI组件,直到它到达上面所示的imlProcesses行。它到达这里,这就是它崩溃的地方。
从我的理解,这是资源造成的(.resx)文件未被定位。我去尝试并在发布设置中乱弄,看看是否可以确保MainForm.resx确实被包括在内。在这样做的同时,我去测试应用程序,并在调试模式下运行它(注意到目前为止我唯一改变的是构建设置,没有代码),我现在得到了相同的IO.FileNotFoundException,在相同的位置!所以我恢复了我所做的所有更改,清理,并重建了程序,但我仍然得到错误!
目前导致问题的代码是遗留代码,到目前为止没有问题。我仍然可以拉取我的最后一次版本控制保存,我将resx属性从旧版本匹配到新版本,仍然,没有什么固定的。在这一点上,我觉得失去了一个解决这个问题的办法。即使我只是更新我的最后一个版本控制保存到与我当前项目相同的功能,我仍然遇到无法将项目导出到不同笔记本电脑的问题。
我是C#和.net的新手,任何或所有的想法/建议都非常感谢,因为我已经没有想法了。谢谢!
我尝试过的一些事情:已将.resx属性还原回以前的版本控制保存。
尝试了不同的属性变体。(原始保存将生成操作设置为“嵌入式资源”,并将“复制到输出”设置为“不复制”。这是当前项目在atm下设置的内容)
还有很多,但这都是试验和错误,并不真正确定我经历了什么
------------------------------------------更新---------------------------------------------------
所以我已经追踪到这个问题与winforms的自动生成代码有关。ComponentResourceManager和imlProcess都是自动生成的行。
我使用DotPeek检查项目中包含的资源。在PixyControl-〉Resources-〉EA.PixyControl.frmMain.resources下确实包含了资源(我引用的名称空间是EA.PixyControl)。
我目前的解决方案是用以下代码替换对resources.GetObject的任何引用:

using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("EA.PixyControl.frmMain.resources"))
            {
                using (var resourceReader = new ResourceReader(stream))
                {
                    var resourceDict = resourceReader.Cast<DictionaryEntry>().ToDictionary(entry => entry.Key.ToString(), entry => entry.Value);
                    this.imlProcesses.ImageStream = (System.Windows.Forms.ImageListStreamer)resourceDict["imlProcesses.ImageStream"];
                }
            }

我想找到一个不同的解决方案,因为任何时候我更新窗口窗体,我的代码被删除(因为它是修改自动生成的部分)。
我觉得答案就在我的错误System.IO.FileNotFoundException中:'找不到文件'PixyControl. resources '。
我认为应该在PixyControl.Resources中搜索,而不是PixyControl. resources。
下面是我试图访问的资源的dotPeek细分的屏幕截图:

1yjd4xko

1yjd4xko1#

如果有人好奇的话,我已经找到了解决方案。事实证明,这是C# .Net Framework 4.8中的一个已知错误,并且在.Net Core 5中进行了修复。然而,我不幸地需要坚持使用4.8。
请看下面的github来概述这个bug:

bug的总结(在我有限的理解中):C#应该在本地程序集中查找它们创建的资源(可能是satallite,不太确定)。无论如何,无论什么原因,它可能会首先开始在错误的区域搜索。在内部,这应该由C#处理以转到其他位置,并在那里检查四个资源文件。然而,无论出于什么原因,错误不会被处理,而是被传递回用户。
解决方案:
在我的Main()中,我添加了一个程序集解析事件处理程序:

AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve;

事件处理函数:

private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
    {
        var resourceName = new AssemblyName(args.Name).Name + ".dll";
        var resource = Array.Find(Assembly.GetExecutingAssembly().GetManifestResourceNames(), element => element.EndsWith(resourceName));

        using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resource))
        {
            if (stream == null) return null;
            var assemblyData = new byte[stream.Length];
            stream.Read(assemblyData, 0, assemblyData.Length);
            return Assembly.Load(assemblyData);
        }
    }

这个想法是,如果没有找到正确的程序集发生错误,手动加载资源。简单的解决方案,花了太长的时间才弄清楚。必须热爱编程:)

相关问题