Friday, January 23, 2009

Embedded Resources and having fun with them

Ok, so, having gotten back from 2 months round the world and almost 3 months not coding at all, I'm feeling rusty. Opening Visual Studio came as quite a shock, simply because "All Those Buttons Can't Possibly Do What I Remember!!!"

Anyway, back in the saddle (I hope) and getting some new code under my belt: This time in the form of...

Embedded Resources

What are those? Well, when you drop, say, a GridView control or something, anything from the toolbox onto your page and it already has, lets say, stylesheets, images, javascript etc, that you think would be better provided as separate files... they probably are. How? Well, when building the code as separate files the non-C# files are placed into an...

ASP.NET Server Control project

This project then needs to be referenced by the web project, so that it's DLL is placed in the website's \bin directory, thus placing any (correctly compiling) custom web controls [because that's what this project type is for] into the toolbox (when ASPX/ASCX 's are in design mode.)

So, lets...

Create a Custom Web Control with images and stylesheets in a DLL

So, open Visual Studio and create a new solution (File -> New -> Project -> Visual C#|Basic -> ASP.NET Web Application) This will give us a website as well.

Now, to this solution, add an ASP.NET Server Control project (File -> Add -> New Project -> Visual C#|Basic -> Web -> ASP.NET Server Control) This gives us a project we can create custom web controls in. This is also the project where the embedded files will be placed.

Ok, so the quickstart to adding and using an embedded resource is...

Add an Embedded Resource and call GetWebResourceUrl

First we need something to use. So lets add an image to the control project - not the web project!

In order to make the image embedded select it in the solution explorer and in the properties panel change it's Build Action to Embedded Resource.

Now make the image usable by expanding the control project's Properties item (in the solution explorer) and edit the AssemblyInfo.cs. Add the following lines to the using declarations at the top:

using System.Web.UI;

And the following to them bottom:

[assembly: WebResource("EmbeddedCtrls.cartman.jpg","image/jpg")]

Where the format is:

[assembly: WebResource("[assembly name].[directory names].[filename]","[filetype]")]

For an image called "cartman.jpg" stored in the root directory of the control project.

Bear in mind that the first part is the assembly name (select the project in solution explorer and click properties) and not the namespace. Also, that rather than being a typical absolute path, the path separators are '.' and not '/'.

We now have a project with an image which can be referenced as an embedded resource, both by code within the control project and any project which references it's DLL's, eg: the web project we created at the start.

Important: One major stumbling block I found was that if the above line of code, in the AssemblyInfo.cs, does not get recognised by Visual Studio, it means something has gone when creating the project. Just delete it and create a new "ASP.NET Control Project". It should appear as so:

[assembly: WebResource("EmbeddedCtrls.cartman.jpg","image/gif")]

Or something close to that, assuming you haven't adjusted your editor styling.

Now, to actually use this image somewhere, we need to...

Add a reference to the Control Project and Compile It.

So, in the web project, right click the References and add the control project as a reference. Then, select the control project in the solution explorer and click Build -> Build [project name]

This will compile the control project and copy it's DLL into the web project's \bin directory. Nearly there. Finally, we need to use it by...

Adding a reference in a web page

Either add an ASPX or open the default one. Paste the following line into the <div></div> statement in the HTML of the page:

<img src='<%= Page.ClientScript.GetWebResourceUrl(typeof(EmbeddedCtrls.ServerControl1),"EmbeddedCtrls.cartman.jpg") %>' />

And run the web page. If everything goes to plan, you should have a page with a single img tag which displays your embedded image.

If WebResource.axd is not found, check the highlighting of the assembly: webresource statement as described above. Also, check that the image file Build Action is set to Embedded Resource, in the properties panel. If the image simply fails to appear, just go through and check that you are providing the correct file name, assembly name, etc.

If you get a web resource exception, it's because you are not registering the embedded resources correctly. If you get a webresource.axd?d=... URL but it shows nothing, it's because the image file is not being referenced in your code properly. The GetWebResourceUrl call and the AssemblyInfo.cs entries must match.

Failing the above, ensure that each time you change the contents of the control project that you rebuild the project and refresh the web page. Simply recompiling the web project will not do it (unless you've configured your solution especially - this is not the default in VS.)

Wasn't that fun? You can download the complete solution here. That is also the same download for the next blog entry, where I will deal with referencing the image from within the control project.