C# System.IO.FileNotFoundException при попытке загрузки ресурсов (.Net Framework 4.8)

У меня есть проект (он начинался как унаследованный код), над которым я когда-то работал. Недавно мне нужно было опубликовать последнюю версию, чтобы ее можно было использовать на отдельном компьютере. Короче говоря, используя издателя в один клик через визуальные студии, я продолжал получать исключение System.IO.FileNotFoundException. Я использовал отладчик VS, чтобы отследить местонахождение ошибки. После присоединения обработчика AssemblyResolve я обнаружил, что проблема связана с этой строкой кода:

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

Путь кода, чтобы добраться сюда, выглядит следующим образом. Main() запускает frmMain (частичный класс MainForm, представляющий форму окна). Затем эта функция вызывает метод InitalizeComponent(). Одна из первых нескольких строк кода, когда componentResourceManager настраивается с помощью строки:

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

Затем выполняется нормальная настройка конструктора оконных форм, загрузка и создание экземпляров всех компонентов графического интерфейса, пока не дойдет до строки 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 для ресурсов, к которым я пытаюсь получить доступ:

Добавляется ли imlProcesses с помощью конструктора форм (при условии, что здесь Visual Studio) или вы добавляете его в коде? Возможно, нам понадобится больше кода, чтобы помочь. Вы смотрели на просмотр событий? Как мы можем воссоздать проблему? Если вы правы в отношении файла resx, вы можете создать небольшое приложение формы Windows, которое минимально издевается над вашим текущим приложением, и удалить файл resx, чтобы воссоздать проблему.

thewallrus 05.04.2023 21:48

Я не уверен, что imlProcesses добавляется через конструктор форм (да, я использую визуальные студии). Этот раздел кода был устаревшим, поэтому я не слишком уверен. Однако файла MainFrom.Designer.cs нет, поэтому я предполагаю, что он не был создан с помощью конструктора форм.

Dave K 05.04.2023 21:55

Что касается просмотра событий, я не пробовал это, но это хорошая идея, я пойду проверю. Для воссоздания я попытался снова получить эту ошибку, используя мое последнее сохранение системы управления версиями, но пока безуспешно. Мне нравится ваша идея создать меньший макет приложения, чтобы попытаться воссоздать его, мне нужно будет попробовать это. Спасибо за ваш вклад!

Dave K 05.04.2023 22:03
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
3
96
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я нашел решение, если кому-то интересно. Оказывается, это известная ошибка в C# .Net Framework 4.8, и исправление было выпущено в ядре .Net 5. Однако у меня был неудачный случай, когда мне пришлось придерживаться версии 4.8.

См. следующие github с описанием ошибки:

Краткое описание ошибки (в моем ограниченном понимании): Предполагается, что С# ищет ресурсы, которые они создают, в локальных сборках (может быть, сателлит, не совсем уверен). В любом случае, по какой-то причине он может сначала начать поиск не в том месте. Внутри 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);
        }
    }

Идея в том, что если возникает ошибка не нахождения нужной сборки, подгрузить ресурсы вручную. Простое решение, которое заняло слишком много времени, чтобы понять. Я люблю программировать :)

Другие вопросы по теме