{"id":2584,"date":"2023-02-04T21:49:28","date_gmt":"2023-02-05T02:49:28","guid":{"rendered":"https:\/\/badecho.com\/?p=2584"},"modified":"2023-02-20T20:37:58","modified_gmt":"2023-02-21T01:37:58","slug":"embedded-raw-media","status":"publish","type":"post","link":"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/","title":{"rendered":".NET 7 Embedded Raw Media Using ResourceCreator"},"content":{"rendered":"\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full is-resized\"><img loading=\"lazy\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia.png\" alt=\".NET 7 Embedded Raw Media Using ResourceCreator\" class=\"wp-image-2585\" width=\"856\" height=\"448\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia.png 856w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia-300x157.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia-768x402.png 768w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia-480x251.png 480w\" sizes=\"(max-width: 856px) 100vw, 856px\" \/><\/figure><\/div>\n\n\n\n<p>Except for the most basic applications, we often need to bundle one or more <em>resources<\/em> with our programs or libraries. By resources, we are referring to data such as strings, images, and even sound or video media content.<\/p>\n\n\n\n<p>These resources are typically attached to a compiled execution image; they are embedded in the binary, if you will. Including these resources in your .NET project&#8217;s output is normally a very simple affair. This is because, for the most part, <em>Visual Studio<\/em>&#8216;s managed resources editor does the job with no incident. <\/p>\n\n\n\n<p>That job being: the visual creation of a <code>.resx<\/code> file, which allows for the attachment to the executable of resources that are either linked at compile time or embedded in the resources file.<\/p>\n\n\n\n<p><strong>Unfortunately, embedding media content in a resources file results in runtime errors.<\/strong><\/p>\n\n\n\n<p>This article seeks to demonstrate some outstanding bugs with <em>Visual Studio<\/em>&#8216;s resource editor, and how I got around them with a little <code>dotnet<\/code> tool I made.<\/p>\n\n\n\n<h2>Link or Die: How Embedding Fails<\/h2>\n\n\n\n<p>It always gives me a sense of relief (and disbelief) when, after finding a significant bug and developing a workaround for it, said bug still exists over a year later when I get around to writing an article on it.<\/p>\n\n\n\n<p>When adding resources to our .resx file via&nbsp;<em>Visual Studio<\/em>&#8216;s managed resources editor, by default, each resource is configured to be linked at compile time.<\/p>\n\n\n\n<p>Let&#8217;s say we want our application to play an audio file. Using the managed resources editor, we&#8217;ll see that adding a particular .wav file to our resources file will also add it to our project so that it&#8217;s linked at compile time.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" width=\"249\" height=\"176\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/ProjectContainingLinkedResource.png\" alt=\"Shows how a resource linked at compile time occupies a place in our project's structure.\" class=\"wp-image-2592\"\/><figcaption>Our new audio resource: &#8220;MurderedVincentLaugh.wav&#8221;.<\/figcaption><\/figure><\/div>\n\n\n\n<p>The strangely named audio file shown above is something I used in my <a href=\"https:\/\/badecho.com\/index.php\/2022\/02\/14\/vision\/\" target=\"_blank\" rel=\"noreferrer noopener\"><em>Vision<\/em> application<\/a>. Let&#8217;s just leave it at that.<\/p>\n\n\n\n<p>If we peer inside the <code>Resources.resx<\/code> file, we&#8217;ll see a reference to our audio file via a relative path.<\/p>\n\n\n\n<h6>Entry for Audio File in Resources.resx<\/h6>\n\n\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;data name=&quot;MurderedVincentLaugh&quot; type=&quot;System.Resources.ResXFileRef, System.Windows.Forms&quot;&gt;\n  &lt;value&gt;\n\t  ..\\Resources\\MurderedVincentLaugh.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089\n  &lt;\/value&gt;\n&lt;\/data&gt;\n<\/pre>\n\n\n<h3>Get Out of My Project! Let\u2019s Directly Embed It<\/h3>\n\n\n\n<p>You may have one or more reasons for not wanting a bunch of loose resource assets present in your project&#8217;s structure. Luckily for you, we can open up the .resx file via the managed resources editor, click on the resource, and then adjust its manner of persistence via the Properties window.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" width=\"519\" height=\"643\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/ResourcePersistence.png\" alt=\"Shows how we can change how a resource is persisted to our resources file.\" class=\"wp-image-2590\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/ResourcePersistence.png 519w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/ResourcePersistence-242x300.png 242w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/ResourcePersistence-480x595.png 480w\" sizes=\"(max-width: 519px) 100vw, 519px\" \/><figcaption>Some types of resources allow for direct embedding into a resources file, configurable via the Properties window.<\/figcaption><\/figure><\/div>\n\n\n\n<p>By selecting the option to embed the resource in our <code>.resx<\/code> file, the resource no longer needs to be part of our project, as it now exists in the resources file.<\/p>\n\n\n\n<h6>Partial Entry for Embedded Audio File in Resources.resx<\/h6>\n\n\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;data name=&quot;MurderedVincentLaugh&quot; mimetype=&quot;application\/x-microsoft.net.object.binary.base64&quot;&gt;\n  &lt;value&gt;\n      AAEAAAD\/\/\/\/\/AQAAAAAAAAAEAQAAABZTeXN0ZW0uSU8uTWVtb3J5U3RyZWFtCgAAAAdfYnVmZmVyB19v\n      cmlnaW4JX3Bvc2l0aW9uB19sZW5ndGgJX2NhcGFjaXR5C19leHBhbmRhYmxlCV93cml0YWJsZQpfZXhw\n      b3NhYmxlB19pc09wZW4dTWFyc2hhbEJ5UmVmT2JqZWN0K19faWRlbnRpdHkHAAAAAAAAAAACAggICAgB\n      AQEBCQIAAAAAAAAAAAAAACBTHwAgUx8AAAEAAQoPAgAAACBTHwACUklGRhhTHwBXQVZFZm10IBAAAAAB\n      AAIAgLsAAADuAgAEABAATElTVBoAAABJTkZPSVNGVA4AAABMYXZmNTguMjkuMTAwAGRhdGEgPR8AAAAA\n      AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\n      &lt;!--And on and on and on...--&gt;\n  &lt;\/value&gt;\n&lt;\/data&gt;\n<\/pre>\n\n\n<p>Neat. Functionally, the resource asset behaves the same in our code whether it is linked at compile time or embedded in the <code>.resx<\/code> file ahead of time. Namely, accessing <code>Resources.MurderedVincentLaugh<\/code> will return an <code><a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.io.unmanagedmemorystream?view=net-7.0\" target=\"_blank\" rel=\"noreferrer noopener\">UnmanagedMemoryStream<\/a><\/code>, with which we can feed the audio data through some playback mechanism.<\/p>\n\n\n\n<h3>But It Won\u2019t Work!<\/h3>\n\n\n\n<p>It would&#8217;ve worked just fine if we left our resource configured to be linked at compile time, but changing it to be directly embedded in the <code>.resx<\/code> file will result in an exception thrown when accessing the resource.<\/p>\n\n\n\n<div class=\"wp-block-image\"><figure class=\"aligncenter size-full\"><img loading=\"lazy\" width=\"660\" height=\"226\" src=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddedRuntimeException.png\" alt=\"System.Runtime.Serialization.SerializationException: 'Type 'System.IO.MemoryStream' in Assembly 'System.Private.CoreLib, Version=7.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' is not marked as serializable.'\n\" class=\"wp-image-2598\" srcset=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddedRuntimeException.png 660w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddedRuntimeException-300x103.png 300w, https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddedRuntimeException-480x164.png 480w\" sizes=\"(max-width: 660px) 100vw, 660px\" \/><figcaption>Ouch. Something isn&#8217;t getting baked into our executable image correctly.<\/figcaption><\/figure><\/div>\n\n\n\n<p>Functionally identical to using a resource that was linked at compile time; unfortunately, choosing to embed the resource directly in the <code>.resx<\/code> file has left us with a dud.<\/p>\n\n\n\n<h3>Why Doesn&#8217;t It Work?<\/h3>\n\n\n\n<p>Knowing the exact cause isn&#8217;t all that important here. Clearly, there is a bug happening with <em>Visual Studio<\/em>&#8216;s managed resources editor when embedding a resource into a <code>.resx<\/code> file &#8212; a bug that persists even with .NET 7 and the newest version of <em>Visual Studio 2022<\/em>.<\/p>\n\n\n\n<p>For some reason, perhaps due to how the managed resources editor baked in the resource, it&#8217;s actually trying to directly deserialize the resource as a <code>MemoryStream<\/code>. You normally deserialize data <em>into<\/em> a <code>Stream<\/code>,  not <em>as<\/em> a <code>Stream<\/code>.<\/p>\n\n\n\n<p>We&#8217;re going to say &#8220;goodbye&#8221; to the managed resource editor and take matters into our own hands in order to embed this resource into our assembly.<\/p>\n\n\n\n<h2>Embedding Resources With ResourceCreator<\/h2>\n\n\n\n<p>It would be much simpler if we could embed the raw byte data of our media into our assembly. At runtime, we would then take the bytes and pipe that data through a <code>Stream<\/code>.<\/p>\n\n\n\n<p>We don&#8217;t (to my knowledge) have that level of control when working with <code>.resx<\/code> files, so let&#8217;s skip them altogether and jump straight to working with <code>.resources<\/code> files, which are what <code>.resx<\/code> files compile into anyway.<\/p>\n\n\n\n<p>To generate a <code>.resources<\/code> file, you&#8217;ll have to write some code &#8212; or, you could make use of a <code>dotnet<\/code> tool I created.<\/p>\n\n\n\n<h6>Installing ResourceCreator<\/h6>\n\n\n\n<pre class=\"wp-block-code\"><code>dotnet tool install BadEcho.ResourceCreator --global<\/code><\/pre>\n\n\n\n<p>Whether or not you want it installed globally is up to you, of course. The tool is published on NuGet, so the above command should simply work.<\/p>\n\n\n\n<p>The tool can be invoked with the command <code>resource-creator<\/code>:<\/p>\n\n\n\n<pre class=\"wp-block-code has-small-font-size\"><code>C:\\src\\resources&gt;resource-creator --help\nDescription:\n  Create a .resources file from a directory containing files we wish to bundle as resources for a program.\n\nUsage:\n  resource-creator &lt;RESOURCES_PATH&gt; &#91;options]\n\nArguments:\n  &lt;RESOURCES_PATH&gt;  The path to the directory containing the resources.\n\nOptions:\n  -o, --output &lt;OUTPUT_PATH&gt;     The path to the output resources file. &#91;default: out.resources]\n  -f, --filter &lt;SEARCH_PATTERN&gt;  A filter comprising one or more search patterns matched against the names of \n                                 files to be included in the output resources file. Each pattern can contain a \n                                 combination valid literal and wildcard characters, with each pattern separated \n                                 by a comma. &#91;default:*.*]\n  --version                      Show version information\n  -?, -h, --help                 Show help and usage information<\/code><\/pre>\n\n\n\n<p>Hopefully the usage is self-explanatory. We simply take all the media resources we want to embed, throw them into a directory, and then run our tool. Something like the following:<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>resource-creator C:\\src\\resources -o Sounds.resources<\/code><\/pre>\n\n\n\n<p>This will generate a <code>Sounds.resources<\/code> file which we can then attach to our project, with its <strong>Build Action<\/strong> set to <strong>Embedded resource<\/strong>.<\/p>\n\n\n\n<h3>Creating the Accessor Class<\/h3>\n\n\n\n<p>We got our baked-in resources attached to the project. We now need a nice way of accessing them.<\/p>\n\n\n\n<p>What I do is create a class with the same name as the <code>.resources<\/code> file; so, in this case: <code>Sounds.cs<\/code>.<\/p>\n\n\n\n<p>In this class, we want to initialize a <code>ResourceManager<\/code> for our .resources file, provide a property that returns the audio resource in question, and finally include a general helper method that we&#8217;ll be calling into for this and any other resource we have bundled into the particular <code>.resources<\/code> file.<\/p>\n\n\n\n<h6>Sounds.cs<\/h6>\n\n\n<pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\npublic static class Sounds\n{\n    private static readonly ResourceManager _Manager = new(\n        &quot;BadEcho.Embedding.Stuff.Properties.Sounds&quot;,\n        typeof(Sounds).Assembly);\n\n    \/\/\/ &lt;summary&gt;\n    \/\/\/ Gets a stream for the rather pleasant sound effect of Vincent Price laughing at us for\n    \/\/\/ being murdered.\n    \/\/\/ &lt;\/summary&gt;\n    public static Stream MurderedVincentLaugh\n        =&gt; GetStream(nameof(MurderedVincentLaugh));\n\n    private static Stream GetStream(string name)\n    {\n        UnmanagedMemoryStream? stream = _Manager.GetStream(name, CultureInfo.InvariantCulture);\n\n        if (stream == null)\n            throw new BadImageFormatException(Strings.SoundMissingResource.InvariantFormat(name));\n\n        return stream;\n    }\n}\n<\/pre>\n\n\n<p>Adding another sound file is as simple as adding another property (after generating a new <code>.resources<\/code> file).<\/p>\n\n\n\n<p>Voil\u00e0! We have working fully-embedded media resources. Enjoy.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Except for the most basic applications, we often need to bundle one or more resources with our programs or libraries. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[10],"tags":[41,42,77],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v14.9 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\r\n<title>.NET 7 Embedded Raw Media Using ResourceCreator - omni&#039;s hackpad<\/title>\r\n<meta name=\"description\" content=\"An overview of using the BadEcho.ResourceCreator dotnet tool to easily embed raw media files into your .NET 7 assemblies.\" \/>\r\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\r\n<link rel=\"canonical\" href=\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/\" \/>\r\n<meta property=\"og:locale\" content=\"en_US\" \/>\r\n<meta property=\"og:type\" content=\"article\" \/>\r\n<meta property=\"og:title\" content=\".NET 7 Embedded Raw Media Using ResourceCreator - omni&#039;s hackpad\" \/>\r\n<meta property=\"og:description\" content=\"An overview of using the BadEcho.ResourceCreator dotnet tool to easily embed raw media files into your .NET 7 assemblies.\" \/>\r\n<meta property=\"og:url\" content=\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/\" \/>\r\n<meta property=\"og:site_name\" content=\"omni&#039;s hackpad\" \/>\r\n<meta property=\"article:published_time\" content=\"2023-02-05T02:49:28+00:00\" \/>\r\n<meta property=\"article:modified_time\" content=\"2023-02-21T01:37:58+00:00\" \/>\r\n<meta property=\"og:image\" content=\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia.png\" \/>\r\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\r\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebSite\",\"@id\":\"https:\/\/badecho.com\/#website\",\"url\":\"https:\/\/badecho.com\/\",\"name\":\"omni&#039;s hackpad\",\"description\":\"Game Code Disassembly. Omnified Modification. Madness.\",\"publisher\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":\"https:\/\/badecho.com\/?s={search_term_string}\",\"query-input\":\"required name=search_term_string\"}],\"inLanguage\":\"en-US\"},{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#primaryimage\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/badecho.com\/wp-content\/uploads\/2023\/02\/EmbeddingMedia.png\",\"width\":856,\"height\":448,\"caption\":\".NET 7 Embedded Raw Media Using ResourceCreator\"},{\"@type\":\"WebPage\",\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#webpage\",\"url\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/\",\"name\":\".NET 7 Embedded Raw Media Using ResourceCreator - omni&#039;s hackpad\",\"isPartOf\":{\"@id\":\"https:\/\/badecho.com\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#primaryimage\"},\"datePublished\":\"2023-02-05T02:49:28+00:00\",\"dateModified\":\"2023-02-21T01:37:58+00:00\",\"description\":\"An overview of using the BadEcho.ResourceCreator dotnet tool to easily embed raw media files into your .NET 7 assemblies.\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/\"]}]},{\"@type\":\"Article\",\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#article\",\"isPartOf\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#webpage\"},\"author\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"headline\":\".NET 7 Embedded Raw Media Using ResourceCreator\",\"datePublished\":\"2023-02-05T02:49:28+00:00\",\"dateModified\":\"2023-02-21T01:37:58+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#webpage\"},\"commentCount\":0,\"publisher\":{\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\"},\"image\":{\"@id\":\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#primaryimage\"},\"keywords\":\".NET,C#,dotnet\",\"articleSection\":\"General Dev\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\/\/badecho.com\/index.php\/2023\/02\/04\/embedded-raw-media\/#respond\"]}]},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\/\/badecho.com\/#\/schema\/person\/3de67496328be7ae6e1f52faf582e9d2\",\"name\":\"Matt Weber\",\"image\":{\"@type\":\"ImageObject\",\"@id\":\"https:\/\/badecho.com\/#personlogo\",\"inLanguage\":\"en-US\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/7e345ac2708b3a41c7bd70a4a0440d41?s=96&d=mm&r=g\",\"caption\":\"Matt Weber\"},\"logo\":{\"@id\":\"https:\/\/badecho.com\/#personlogo\"}}]}<\/script>\r\n<!-- \/ Yoast SEO plugin. -->","_links":{"self":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/2584"}],"collection":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/comments?post=2584"}],"version-history":[{"count":23,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/2584\/revisions"}],"predecessor-version":[{"id":2656,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/posts\/2584\/revisions\/2656"}],"wp:attachment":[{"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/media?parent=2584"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/categories?post=2584"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/badecho.com\/index.php\/wp-json\/wp\/v2\/tags?post=2584"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}