Embedding assets in a .NET Assembly

James Walker
James Walker
Published in
3 min readMay 26, 2017

I’ve recently been asked how we go about embedding static assets in some Redspa’s core libraries. This is essentially compiling assets into a shared .NET Framework assembly that needs to be used across a number of different projects.

I haven’t, as yet played with this on .NET Core, so this solution is very much for the .NET Framework and is also a few years old, so there may be better ways to do it!

Setting your assets to be embedded

The first thing that you need to do is to create a Visual Studio project that will hold all your assets. This could be the same assembly where you have other shared elements, such as common Controller actions and/or Views that you’ve compiled using RazorGenerator.

The first thing to do is to set the resources you want to be shared to be embedded within the project. The simplest way to do this is to mark the Build Action as an Embedded Resource within Visual Studio:

Setting Assets to Embedded from the Properties Pane

However, this will become really tedious if you need to embed a whole load of resources, so it’s actually much easier to tell Visual Studio that you want to embed all the resources in a specific folder on compile:

If you’ve got a lot of embedded resources, it can be a pain to mark every single item as embedded. The alternative is to edit your .csproj file directly and add the following in the BeforeBuild section:

<Target Name="BeforeBuild">
<ItemGroup>
<EmbeddedResource Include="**\*.gif;**\*.jpg;**\*.css;**\*.js;**\*.png" />
</ItemGroup>
</Target>

Accessing the embedded resources

Once the resources are embedded in your assembly, you can add a method within the assembly to access the resources and stream them to the browser.

In this instance, I’m going to create an ASP.NET Controller Action to perform the streaming and use reflection to access the embedded resources:

public class ResourceController : Controller
{

public ActionResult Index(string resourceName)
{
} }

So far, so simple. The idea here is that the controller action will be called with the resource name passed through as a property.

Next, we need to find the embedded file in the assembly. When files are embedded in an assembly, they are stored with a reference of the assembly namespace and then the filename with the file path converted to dot notation. It’s also worth noting that any filenames are case sensitive.

For example, if the file is in the assembly with a default namespace of:

Test.EmbeddedResources

and a relative file path of

Content\Assets\file.png

Then the embedded resource would be:

Test.EmbeddedResources.Content.Assets.file.png

We’re ideally wanting our embedded resources to be able to be called as if they’re ‘real’ file URLs, so we’d expect the resourceName parameter to our controller action to have forward slashes.

The first thing therefore is to convert any forward slashes to full stops — as this is how they get mapped when embedded and then add on our assembly namespace:

resourceName = resourceName.Replace("/", ".");
resourceName = "Test.EmbeddedResources." + resourceName;

Now, we can use this reference to the resource to query the assembly using reflection:

var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);

This returns a stream reference to the embedded resource that we can just return as the result of our action:

return File(resourceStream, contentType);

The contentType variable is a string with the Mime type of the file that’s being returned. I’ve got a helper function that works this out for a standard set of files that I’m most likely to use.

Wrapping it all up, our action now looks like this:

public class ResourceController : Controller
{
public ActionResult Index(string resourceName)
{
resourceName = resourceName.Replace("/", ".");
resourceName = "Redspa.MVCLibrary." + resourceName;
var contentType = GetContentType(resourceName);
var resourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourceName);

return File(resourceStream, contentType);
}
}

Routing

Finally, we now need to make sure our routing is all setup.

Within the library project, we need to add a route to point to our controller action. So, in our RouteConfig.cs we add:

routes.MapRoute(
name: "ResourceController",
url: "common/resource/{*resourceName}",
defaults: new { controller = "Resource", action = "Index" }

We now add a web.config setting to the system.webServer section of main web application that we need to access the shared resource. This allows us to use pick up the URLs with extensions on them and pass them through to the .NET pipeline.

<handlers>
<add name="Embed-Integrated-1.0" path="common/resource/*.*" verb="GET" type="System.Web.Handlers.TransferRequestHandler" preCondition="integratedMode,runtimeVersionv4.0" />
</handlers>

You should now be able to reference your stored assets using a standard URL

<img src="/common/resource/Content/Assets/file.png" />

--

--

James Walker
James Walker

Enterprise Architect, Tech Evangelist and Founder & MD of Tunbridge Wells-based Digital Agency Redspa