Drew's Blog

The Joys of Technology Explored

Web Controls and External Resources

This has come up on the DOTNET-WEB mailing list a couple times lately and I figured I should make an entry about it to help people out in the future. I was actually surprised that this wasn't covered in Fritz's book.

Unlike Windows control resources where it usually makes the most sense to package your icons, format strings, images, etc. into an assembly, Web controls have to deal with emitting URLs to their resources so that the browser can go fetch them. The ASP.NET people at Microsoft realized this and provided support for it within the System.Web.UI.Control class.

The problem:

You're about to write a control that needs to emit HTML that has an img element in it. How do you generate the value for the src attribute such that if the control is hosted on a web page located at the URL /foo.aspx or the URL /someApplication/bar.aspx the control still emits the proper URL?

The solution:

Luckily the ASP.NET developers at Microsoft were smart enough to catch this potential problem and they supplied the Control class with the TemplateSourceDirectory property and the ResolveUrl method.

Using these properties it is possible to solve the external resource problem in an elegant fashion that requires the same xcopy deployment as your control might. First, you can override the TemplateSourceDirectory property to return the following type of URL for your control: ~/Company/Controls/SomeControl. The ~ is a special indicator that tells ResolveUrl to prefix the rest of the supplied URL with the current HttpContext's HttpRequest::ApplicationPath value.

Example 1

If the control is hosted on a page /foo.aspx, then / is your ApplicationPath and a call to ResolveUrl for ~/Company/Controls/SomeControl would simply resolve to /Company/Controls/SomeControl.

Example 2

If the control is hosted on a page /someApplication/bar.aspx, where /someApplication is explicitly configured under IIS as a standalone appication, your ApplicationPath is now /someApplication and a call to ResolveUrl for ~/Company/Controls/SomeControl would resolve to /someApplication/Company/Controls/SomeControl.

Now, you might be tempted to forgo using the ~ in your TemplateSourceDirectory URL and instead make the control's resources global for the entire server on which it's installed. By all means this can be done by forcing the control's resources to be installed at the root site and returning a URL like /Company/Controls/SomeControl (note there's no ~ prefix). The major problem with this is versioning as sub applications might need to use different versions of the control and then you would be forced to come up with a versioning scheme for your control's URLs (i.e. /Company/Controls/SomeControl/v[Major].[Minor].[Build].[Revision]). This would also defeat the whole xcopy deployment scenario because now you can't just pick up a whole directory and move it somewhere to deploy the application. Instead you have to worry about moving the control's resources into an entirely different directory. As a final deterrent to using this method, consider the web farm scenario where the person that might be using your control doesn't have any control over the machine and can't get resources into the root application.

On a final note, in the above example scenario I used an img element's src attribute as a example where a URL might need to be resolved, but obviously this goes for any external resource (i.e. stylesheets, scripts, etc.). Also, since the System.Web.UI.Page class ultimately derives from Control, it also supports these features. When might this be useful? Well, consider the scenario where all pages in an application may derive from a custom base Page subclass which might render some portion of the HTML itself, this can be just as useful since the base Page subclass has no idea what the URL of it's subclasses may end up being.

Posted: Jun 03 2003, 02:34 PM by drub0y | with 11 comment(s)
Filed under:

Comments

Robert McLaws said:

I package my resources in my control, and then use a single aspx page and some server-side processing to stream them out. This includes graphics images and javascript files. Then I don't ever have to know where the files reside, I just make them put an ASPX page in the root. DbCombo.net actually does the exact same thing.
# June 3, 2003 4:27 PM

Drew Marsh said:

That certainly works, however that puts a lot of HTTP work into the hands of that APSX resource dispenser. For example, does it handle caching (i.e. etags/last modified)? Seems like you could be paying a lot of overhead overhead to hand over a static file. Then again, this has the benifit of protecting your resources against tampering. As usual, all trade offs to consider. :)
# June 3, 2003 4:40 PM

Kevin Dente said:

Here's a related question - something I've been struggling with. If I want to write a web control that generates a custom image on the fly (say generating a graph or chart, for example) and displays it, what's the best way to go about it? The control rendering can spit out an IMG tag, but of course the image data can't be rendered in-line with the html. You can set the src of the image to some URL that generates the image. But is there a way for the control itself to render that image? I haven't come up with a good solution yet (short of having some separate web page do the image rendering).
# June 3, 2003 6:07 PM

Drew Marsh said:

Kevin,

I would do this in two parts. First, write an HttpHandler that takes a query string with the parameters required to generate the image. The HttpHandler simply generates the image and returns the bytes. Second, your control simply emits URLs with the proper query string params pointed at the configured HttpHandler's URL.

The installation of your control becomes a little more complex because the HttpHandler needs to be registered in the application's web.config, but I think this is the best way to do it.
# June 4, 2003 12:41 PM

Kevin Dente said:

Hmm, an HttpHandler, eh? I'll take a look at that. Thanks.
# June 4, 2003 6:49 PM

Clue said:

The only problem with using ResolveUrl is the lack of design-time support. A path like "~/Company/Controls/SomeControl" can't be resolved at design time so images are not displayed by VS.NET.
# June 8, 2003 6:44 AM

jknm jmm said:

jknm jmm
# November 15, 2003 5:02 AM

nakedcelebsi said:

photographs of  <a href=sciencenewsarticles.org/.../> naked clips</a> fre naked pictures .

# December 14, 2011 1:47 AM

allnakedcelebritiesx said:

# January 16, 2012 1:09 AM

nakedbabesv said:

naložba v delnice <a href=http://www.publikumsi.info>publikum.si</a>

# January 16, 2012 3:26 AM

nakedcelebss said:

avto.net <a href=http://www.ilirikadzu.info>ilirika dzu</a>

# February 5, 2012 11:11 AM
Leave a Comment

(required) 

(required) 

(optional)

(required)