Friday, January 23, 2009

More Embedded Resource fun

If you're new to embedded resources please read this entry first: http://springboardpillow.blogspot.com/2009/01/embedded-resources-and-having-fun-with.html

Now we'll use the same image, from my previous blog entry, from within the project we created earlier. For this we will need a...

Custom Web Control

To make this, either use the default ServerControl1.cs, or right click the control project and select: Add -> New Item -> Web -> ASP.NET Server Control. By default this should give us:

WebCustomControl1.cs

To get in the habit, first...

Compile the Control Project

Select: Build -> Rebuild [project name]

This will recompile the custom web control project, including the new (empty) control and place it's DLL into the web project. This is because we previously referenced the control project from the web project. Now, we are going to...

Add a reference to the Embedded Resource to the Custom Control

In the new custom control, find the RenderContents(...) method and replace it's content with:

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

You should be able to see that this is essentially just manually writing out the same code as was in the previous web page, however this time we are inside the custom control and so the reference to it can essentially be 'this.GetType()'.

Now, rebuild the custom control project as before (Build -> Rebuild [project name]) and the updated DLL will be copied to the web project. All we need to do is...

Drop the Custom Control onto a Web Page

So, create a new ASPX in the web project and open it's design view. If the custom web control project compiled correctly, you should have a new toolbox group called '[project name] Components'.

Grab the custom control from within the toolbox group and drop it onto the designer. Save everything and run the page.

You should now have the same output as in the previous blog entry!

Easy, eh?

Two things to Note are...

That dropping the custom control on your web page add a Register directive to the top (just as any ASP.NET toolbox control does)

And that you will have a <span> tag surrounding your <img> tag. To remove this, simply override RenderBeginTag and RenderEndTag, like so:

public override void RenderBeginTag(HtmlTextWriter writer)
{
// removed one line of default code!
}
public override void RenderEndTag(HtmlTextWriter writer)
{
// removed one line of default code!
}

Listing the Known Embedded Resource

If you want to place a stop point in your code and list the embedded resource files that are available to you, paste the following line just before your stop point:

object a = GetType().Assembly.GetManifestResourceNames();

Upon stopping here, the 'a' object will be a list of embedded resources.

As Before...

The entire demo solution can be found here.

Resources:

http://support.microsoft.com/kb/910442
http://www.codeproject.com/KB/aspnet/MyWebResourceProj.aspx
http://aspnet.4guysfromrolla.com/articles/080906-1.aspx
http://aspalliance.com/726
http://msdn.microsoft.com/en-us/library/yhzc935f.aspx

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.

Resources:

http://support.microsoft.com/kb/910442
http://www.codeproject.com/KB/aspnet/MyWebResourceProj.aspx
http://aspnet.4guysfromrolla.com/articles/080906-1.aspx
http://aspalliance.com/726
http://msdn.microsoft.com/en-us/library/yhzc935f.aspx