I'm embarrassed to say that I didn't quite know how to get controls to render image urls properly in the designer. The situation is as follows: You create a custom server control and you have an image property and you allow the use of the ~/images/someimage.gif syntax to specify the image path. I use this sort of thing frequently and have many controls that use custom image urls. For example, I have an error/notification control that has ErrorImageUrl and InfoImageUrl properties, a calendar that has a ButtonImageUrl etc.
So the obvious thing and what I've been using is Control.ResolveUrl() and it works great at runtime for specifying related links.But if you try to get this control to render in the designer as well you'll quickly find that ResolveUrl() doesn't work properly at design time because there's no explicit ApplicationPath available at design time. So the designer can't properly render the Image Url which results in a broken image in the designer.
There's a really easy solution however - use Control.ResolveClientUrl() which creates a relative URL rather than a fully rooted base URL as ResolveUrl() does. Say I'm in an app like /WebLog and I have an image path like ~/images/Warning.gif defined, the rendered image URL will look like this for each of the methods:
ResolveUrl:
/WebLog/Images/warning.gif <!--- fully rooted
ResolveClientUrl:
images/warning.gif or if in a subpath: ../images/warning.gif <!-- relative paths
ResolveClientUrl() creates a relative URL rather than a fully rooted URL which works because at design time there's no application root path to inject. A relative path works just fine with the designer's default rendering. The designer is smart enough to figure out the base path and the relative path for pages/controls in the current project and consolidates the two properly creating an appropriate relative path that works both at runtime and design time. Problem solved.
FWIW, I took a look to see what ResolveClientUrl does at design time and it uses IUrlResolutionService to handle the task at design time (from Reflector):
IUrlResolutionService service = (IUrlResolutionService)this.Page.Site.GetService(typeof(IUrlResolutionService));
if (service != null)
{
return service.ResolveClientUrl(relativeUrl);
}
Beyond that, ResolveUrl() relies on the Request.ApplicationPath to create its base path and then adds the Control.TemplateSourceDirectory on top of it to figure out path information. ResolveClientUrl() uses Control.TemplateSourceDirectory and co-relates that to the base path of the application.
I've always been using ResolveUrl() but now that I'm looking at this more closely it seems that using relative paths - especially for images - is a much better call since it works both at runtime and design time. Relative paths are shorter for one thing saving a few bytes in the Response too. Also checking into System.Web it looks like Microsoft too is using ResolveClientUrl for things like ImageUrls on an image control, so this is obviously something that I've missed for the duration - duh! Offhand I can't think of any reason why I wouldn't want to use ResolveClientUrl.
Other Posts you might also like