Embedded Web Resources

If, as an ASP.NET developer, you haven't used embedded resources, you're missing out big.

How many times have you had to deploy or maintain a site, only to have one or more of your images going missing, javascripts being modified by rogue web admins, or wrestling with the ASPNET securities monster?

If the answer's more than one, or even if it's zero, you need to think about embedding your site's resources at some point. The basic idea is that you embed your sites resources (ie, javascript, images, EULAs or whatever you have) into a seperate class library. When a resource is then requested by the user, the web server then pulls the requested resource out of the dll rather than the filesystem.

The nice part is it's pretty simple to do. There are really just 2 main parts - get the resources into the dll, get the resouces out of the dll.

Firstly you need to create a new class library that's referenced by your web project. Be sure to give it a default namespace, something like <Company>.<Project>.Resources is a good start.

Add to it your resources

Resources Project

Next, select all your resources, go to their property page (F4), and set their build action to "Embedded Resource". This means that when you go to compile your DLL, your "Embedded resource" files will be stored inside it.

The next step is an easy one to forget. Although the resources have been embedded, you need to mark them to be accessable as a web resource. To do this you need to open up your Properties\AssemblyInfo.cs and add the following line for each one of your resources:

[assembly: WebResource("Company.Project.Resources.Images.Login.background.gif", "image/gif")]

The file reference is made up of Namespace.Folder(s).filename.ext

Compile your project to produce the dll. I highly recommend Lutz Roeder's .NET Reflector - a functional and free dll browser, essential to any .NET dev's toolkit. You can use this to see

  1. if your files are being embedded in the dll, and
  2. what their manifest names are

To get the resources out of the dll, you need to use the method call:

Page.ClientScript.GetWebResourceUrl(typeof(Language), "Company.Project.Resources.Images.Login.background.gif");

For simplicity sake in my site, I've created a public static class to do this stuff for me, and also take out the repetitiveness of having to supply the same namespace all the time:

public static class Global

{

    public static string GetResource(Page currentPage, string resourceName)

    {

        string resNamespace = typeof(Language).Namespace;

        return currentPage.ClientScript.GetWebResourceUrl(typeof(Language), resNamespace + "." + resourceName);

    }

}

In the above examples, Language is simply a class that i've compiled into the Resources dll. It's necessary so that reflections can locate the assembly that contains your resources. This method will return a string that looks something like this:

WebResource.axd?d=rLxM_e-hNRgcxNZLXGjctTk29lCIdmt5WI7DIzX8eu0chQcXvXKMdywK0qPrNmD7OWHAxEdM_Bgznu_OY1JLU413x9VqlXs-NmZ294HGH8E1&t=633300286780182866

So for instance to display the background image, in your HTML you'd use:

<img src="<%=Global.GetResource(Page, "Images.Login.background.gif") %>" alt="Login Background" />

And there you have it, your images should then be read through your dll and viewable through your web browser. You can do the same with your javascripts, or really any other static file. You can then deploy websites which don't have a whole heap of images that can go missing. But a word of warning - because you're embedding all these things into a single dll, it gets fully loaded into memory. Making it too big will impact the performance of your website.

For this reason, here's a quick list of DOs and DONTs:

DO

  • Embed frequently used resources
  • Embed javascripts etc that you don't want sneaky web admins to modify
  • Files that tend to remain static throughout the life of your server

DONT

  • Embed big media (ie: video, audio, swf's, streaming data)
  • Embed files which are rarely accessed
  • Embed files which need to be writable

posted @ Thursday, November 08, 2007 8:02 AM

Print

Comments on this entry:

# re: Embedded Web Resources

Left by Carl Taylor at 3/3/2008 12:00 AM
Gravatar
Can anyone tell me why Microsoft doesn't:

1. Support Page.ClientScript.GetWebResourceUrl(...) for Web Applications like it does for controls and other control libraries.
2. When you mark a resource as embedded, why doesn't Microsoft automatically prompt the developer to see whether the WebResource attribute should be automatically added to AssemblyInfo.cs?

Instead what we have is numerous cries for help on the web sand having to artifically create another dll to access embedded image URLs.

Page.ClientScript.GetWebResourceUrl(...) should be supported for Web Applications.

Is there a good reason why this isn't done that I am not seeing?

# re: Embedded Web Resources

Left by Eric at 7/18/2008 11:13 AM
Gravatar
Good article. I followed everything except the part about "Language is simply a class that i've compiled into the Resources dll" . What does that class do and can you explain more about why it's needed?

# re: Embedded Web Resources

Left by Mirta at 11/5/2008 2:56 AM
Gravatar
Hi:

I have a great doubt about on how do I to show an image contained in an external dll?

I've just created a external dll (resources.dll) that contains 16000 images as resources. I've included this in my current web project by copying it the bin folder.

By running this:
Assembly dll = Assembly.LoadWithPartialName("resources");
string [] resources = dll.GetManifestResourceNames();
dgPages.DataSource = resources;
dgPages.DataBind();
I got a table listing my images names. So far so good!

But, how do I to show one of these in a img tag?
<asp:Image ID="imgTest" runat="Server" />
something like this doesn't work:
imgTest.ImageUrl = resources[1];

Any help well be so appreciated!

Regards

# re: Embedded Web Resources

Left by Andrew at 11/6/2008 9:38 AM
Gravatar
Carl:

I guess that .NET doesn't automatically flag assembly resources as WebResources to allow the developer to make the decision.
Re Page.ClientScript.GetWebResourcesUrl() - this method's available for web apps, otherwise I'm not quite understanding your question

Eric:

There are a number of ways to retrieve an assembly. The method I'm using is to specify one of the classes within that assembly, in this case "Language".

Mirta:

You can't use resources[i], as this will just give you back the unique ID of the resource you're trying to retrieve as a string (eg: "namespace.image.gif")

What you need to do is to resolve this to a URL. .NET uses http handlers and WebResource.axd to allow you to access resources from your assembly.

To do this, you need to use Page.ClientScript.GetWebResourceUrl(typeof(ANameOfAClassInYourAssembly), resources[i]);

this will resolve to a url that looks like: WebResource.axd?d=rLxM_e-hNRgcxNZLXGjctTk29lCIdmt5WI7DIzX8eu0chQcXvXKMdywK0qPrNmD7OWHAxEdM_Bgznu_OY1JLU413x9VqlXs-NmZ294HGH8E1&t=633300286780182866

Your comment:



 (will not be displayed)


 
 
 
Please add 8 and 5 and type the answer here:
 

Live Comment Preview:

 
«November»
SunMonTueWedThuFriSat
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456