GetManifestResourceStream повертає NULL


105

Це додаток C # .NET 4.0:

Я вставляю текстовий файл як ресурс, а потім намагаюся відобразити його у діалоговому вікні:

    var assembly = Assembly.GetExecutingAssembly();
    var resourceName = "MyProj.Help.txt";

        using (Stream stream = assembly.GetManifestResourceStream(resourceName))
        {
            using (StreamReader reader = new StreamReader(stream))
            {
                string result = reader.ReadToEnd();
                System.Windows.Forms.MessageBox.Show(result, "MyProj", MessageBoxButtons.OK);
            }
        }

Рішення - MyProjSolution, а виконуваний файл - MyProj.exe. Help.txt - це вбудований ресурс. Однак потік є нульовим. Я спробував MyProjSolution.Help.txt і MyProjSolution.MyProj.Help.txt, але, здається, нічого не працює.


1
Використовуйте ildasm.exe, щоб подивитися назви ресурсів .mresource в маніфесті збірки. Не уникайте потрапляння в цю неприємність, замість цього використовуйте вкладку Project + Properties, Resource. Таким чином, ви можете просто використовувати Properties.Resources.Help у своєму вихідному коді.
Ганс Пасант

Відповіді:


189

Ви можете перевірити, чи ресурси вбудовані правильно, використовуючи

//From the assembly where this code lives!
this.GetType().Assembly.GetManifestResourceNames()

//or from the entry point to the application - there is a difference!
Assembly.GetExecutingAssembly().GetManifestResourceNames()

при налагодженні. Тут буде перераховано всі (повністю кваліфіковані імена) усіх ресурсів, вбудованих у збірку, в яку написано ваш код.

Див. Розділ Assembly.GetManifestResourceNames () на MSDN.

Просто скопіюйте відповідне ім’я та використовуйте це замість того, що ви визначили у змінній "resourceName".

Примітки - ім'я ресурсу чутливе до регістру, і якщо ви неправильно вставили файл ресурсу, він не відображатиметься у списку, поверненому викликом GetManifestResourceNames (). Крім того, переконайтеся, що ви читаєте ресурс з правильної збірки (якщо використовується декілька збірок) - отримати надто просто з ресурсів, що виконуються в даний час, а не з посилальної збірки.

EDIT - .NET Core
Будь ласка, перегляньте цей пост, щоб дізнатися, як вбудувати за допомогою .NET Core.

Отримання інформації про маніфест схоже - просто використовуйте this.GetType().GetTypeInfo().Assembly.GetManifestResourceNames()для отримання маніфесту з збірки, де виконується код.

Я ще не придумав, як зробити еквівалент Assembly.GetExecutingAssembly()в .NET Core! якщо хтось знає - повідомте мене, і я оновлю цю відповідь.


5
Це спрацювало. ProjectName.Resources.Help.txt було вбудованою назвою ресурсу.
Рон

2
Я радий, що допомогли! Якщо ви вважаєте, що ця публікація відповіла на ваше запитання, то не забудьте позначити це як прийняту відповідь.
Джей

1
Так, так у .Net Standard це повинно бути [ProjectName]. [Простір імен]. [Resource]. У мене відсутня назва проекту. Дякую!
Біллі Джейк О'Коннор

У моїй проблемі було використання GetExecutingAssembly () замість GetEntryAssembly (). Ресурс, який я хотів, знаходився у виконаному файлі, але функція для завантаження ресурсу жила в іншому, посилається на проект, у тому самому рішенні.
lettucemode

63

У мене була аналогічна проблема, спочатку перевірте, чи файл включений у ваш проект, потім перейдіть до властивостей і встановіть дію збірки цього файлу на Вбудований ресурс. це працювало для мене.


Це мені допомогло! У мене були раніше додані файли, які дефолтом були вбудовані ресурси, а потім ті, які я додав пізніше, які були встановлені на "None". Visual Studio часом так дратує. Найгірше, що всі файли XML для ресурсів не мають налаштувань для дії збірки. Повинна бути встановлена ​​дія збірки.
John Suit

1
Не забудьте використовувати простір імен за замовчуванням і шлях до ресурсу. напр DefatultNameSpace.Infrastructure.Help.txt. Простір імен за замовчуванням на вашій сторінці властивостей проекту, і Infrastructureце папка, в яку ви знаходитесь
jabu.hlong

Це те, що я хотів ура!
таббі

19

Властивість "Build Action" вбудованого файлу слід встановити як "Embedded Resource", щоб правильно запустити рядок, який наведено нижче:

Stream stream = assembly.GetManifestResourceStream(resourceName)

Клацніть правою кнопкою миші на файл, клацніть на властивості та встановіть властивість "Build Action" як "Вбудований ресурс":

введіть тут опис зображення


Саме це було моїм питанням. Дякую!
Рікі

1
Це була моя проблема. Я додав його за допомогою Resources.resx, і він не працював.
Гелдер Ліма

11

Ось причина мого нульового значення.

http://adrianmejia.com/blog/2011/07/18/cs-getmanifestresourcestream-gotcha/

GetManifestResourceStreamМетод завжди повертається , NULLякщо ресурс «Built дії» властивість не встановлено на «впроваджений ресурс»

Після встановлення цього властивості з усіма необхідними файлами assembly.GetManifestResourceStreamпочинає повертати правильний потік замість NULL.


1
Знову дякую. Це виправлено мою проблему місяць-два тому, тоді я забув про неї, у мене була та сама проблема, і вона виправлена ​​знову.
Багатий

8

Просто попередження.

Я не міг отримати доступ до свого файлу як вбудований ресурс, хоча я вказав, що він є, і хоча він мав це властивість Build Action. Даремно багато часу стукав головою. Я вбудував файл коду csharp з .txt, доданим до його імені (xxx.cs.txt). Чомусь методи GetManifestResourceNames () та GetManifestResourceStream () не побачать файл із .cs у своєму імені.

Я її перейменував просто xxx.txt, і все було добре.

Дивно.


1
На це сьогодні витрачено занадто багато часу! Він буде вбудовувати його, якщо ви використовуєте, Resourceале ні Embedded Resource, що робить його ще більш дивакуватим ... Видалення .cs.з імені змушує його працювати. Арг.
Метт

Проблема не в тому, що .cs. шлях / сегмент у файлах розпізнається як файл C #, а не як CultureInfo.
frontlinebg

2
Здається, що з подвійним розширенням це зовсім не працює.
Даріон Бадлідон

3

У мене була така ж проблема, завдяки Джею я виявив, що це дефіси в імені каталогу.

ProjectName.ResourceFolder.Sub-Directoryстає, ProjectName.ResourceFolder.Sub_Directoryколи ви посилаєтесь на потік ресурсів.


2

У моєму випадку проблема полягала в тому, що код, що шукає ресурс, був у іншому проекті, ніж сам ресурс.

Ви можете отримати доступ лише до ресурсів, що містяться в одному проекті. Я думав, що можу вкласти всі свої ресурси в проект веб-сторінки, але мені потрібні зображення і в поштовому проекті.

Сподіваюся, це допоможе комусь у тій же ситуації, що і я.

Я вважаю дійсно корисним дзвінок Assembly.GetExecutingAssembly().GetManifestResourceNames();.


Це неправда, щонайменше з 2011 року: і через Assembly.LoadFrom (), і тип typeof ви можете отримати доступ до ресурсів, які є в іншому проекті
Marcelo Scofano

1

У випадку, якщо це допомагає комусь іншому, переконайтеся, що Assembly.GetExecutingAssembly()лінія викликається з тієї ж збірки, в яку вбудовані ресурси.


За винятком випадків, коли ви телефонуєте з іншого проекту, і в цьому випадку ви повинні використовувати Assembly.LoadFrom () або typeof, щоб ви могли отримати доступ до ресурсів, які є в іншому проекті ...
Marcelo Scofano

1

Просте і обтічне рішення - мати базовий клас:

public class EmbededResourceReader
{
    protected string LoadString(string fileName)
    {
        return LoadString(fileName, Encoding.UTF8);
    }

    protected string LoadString(string fileName, Encoding encoding)
    {
        var assembly = this.GetType().Assembly;
        var resourceStream = assembly.GetManifestResourceStream($"{this.GetType().Namespace}.{fileName}");
        using (var reader = new StreamReader(resourceStream, encoding))
        {
            return reader.ReadToEnd();
        }
    }
}

Потім, додаючи ресурс, ви створюєте читацький клас C # в тій же папці:

введіть тут опис зображення

де клас читача MyResource.cs дуже простий:

public class MyResource : EmbededResourceReader
{
    public string LoadString() => LoadString($"{nameof(MyResource)}.txt");
}

Отже, у кожного ресурсу буде клас "тінь", який вміє правильно його читати.

Ось як ви читаєте ресурс у своєму коді:

var text = new MyResource().LoadString();

І як запропоновано інші відповіді, не забудьте встановити "Вбудований ресурс" у властивості Build Action файлу ресурсу.

Перевагою цього рівномірного рішення є

  1. менше клопоту з пошуком правильного повного імені ресурсу, особливо якщо розміщено в вкладених папках
  2. у випадку, коли папку перейменовано АБО Простір імен за замовчуванням у налаштуваннях проекту буде змінено, код НЕ порушиться

0
    First Unload the project and click on edit the project file. 

    Inside the project file make sure that the item you are fetching from the assembly is included inside <EmbeddedResource> tag.

    Eg: 

         <ItemGroup>
          <EmbeddedResource Include="Template\ForExampleFile.html" />
         </ItemGroup>


    The files I added into the project were just in Content tag but not in the EmbeddedResource as shown below by default. Hence the stream was returning null.
    <ItemGroup>
        <Content Include="Template\ForExampleFile.html" />
  </ItemGroup>

0

Вам потрібно розвантажити рішення. Потім редагуйте проект. Після цього знайдіть свою папку та змініть так:

<EmbeddedResource Include="yourpath" />

0

Хоча OP отримав GetManifestResourceStream, що повертає NULL з ресурсів тієї ж Асамблеї, деякі відповіді припускають, що коли ресурси знаходяться в іншому проекті чи зборах, їх не можна отримати, і є справедливою причиною повернення GetManifestResourceStream NULL.

Це неправда, принаймні з 2011 року; як я вказував у деяких коментарях десь, Assembly.LoadFrom () або typeof роблять трюк, і в результаті ви можете отримати доступ до ресурсів, які є в іншому проекті.

Я маю тут помірно складний приклад для ілюстрації; це моя тестова установка:

введіть тут опис зображення

Шлях до іншого проекту:

введіть тут опис зображення

Захоплені тут:

 var sharedXMLResource =
                "D:\\My Documents\\Consultório Impressos\\DB Pacientes\\Teste\\TestesVariados\\WinFormFramework\\Read_Embedded_XML_File_CS\\bin\\Debug\\Read_Embedded_XML_File_CS.exe";

І на Form1.cs з WinFormFramework, з яким я вказую

Простір імен.Folder.Resource

щось схоже на те:

StreamReader reader = 
                new StreamReader(Assembly.LoadFrom(sharedXMLResource).GetManifestResourceStream("Read_Embedded_XML_File_CS.SharedResources.ContactList.xml") ?? throw new InvalidOperationException());

І результат відображається в текстовому полі: введіть тут опис зображення

Я витратив кілька годин на те, щоб виправити це; для цього мені довелося дуже багато використовувати в негайному вікні:

Environment.CurrentDirectory
AppDomain.CurrentDomain.BaseDirectory
System.Reflection.Assembly.GetExecutingAssembly().Location
System.Reflection.Assembly.GetAssembly(typeof(WinFormFramework.Program)).Location

Сподіваюся, це комусь допоможе


-2

Можливо, вам потрібно буде вказати шлях до вашого файлу txt у GetManifestResourceStreamпараметрі, або ви можете спробувати вставити файл txt у той самий каталог, що і ваш виконуваний файл. Сподіваюся, що це допомагає!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.