Rick Strahl's Weblog  

Wind, waves, code and everything in between...
.NET • C# • Markdown • WPF • All Things Web
Contact   •   Articles   •   Products   •   Support   •   Advertise
Sponsored by:
West Wind WebSurge - Rest Client and Http Load Testing for Windows

Getting Images to render properly in the ASP.NET Designer


:P
On this page:

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.

Posted in ASP.NET  

The Voices of Reason


 

Marco von Frieling
November 23, 2007

# re: Getting Images to render properly in the ASP.NET Designer

Hello.

I've written a utility which resolves path to files within the current theme. I need this because I have lots of images depending on values from the database (e. g. open/closed envelope symbols, ...) for which Skin files are not a good solution, because it is too dynamic.

So, I have a syntax like
"~$/myimage.gif"
will be resolved to
"~/App_Themes/Current_Theme/myimage.gif"
. Then I use the HttpVirtualPathUtility to resolve the "~/". What do you think, can I switch from the HttpVirtualPathUtility class to an IUrlResolutionService implementation?

And how can I obtain a service instance from my utility class, which has no direct access to a Page instance? Is there another and maybe better way than introducing a parameter of the Page type?

Thanks,

Marco

PBZ
November 24, 2007

# re: Getting Images to render properly in the ASP.NET Designer

Marco: Sounds pretty cool, how does it work? Can you use that with any control?

Thanks.

Russ Suter
May 06, 2008

# re: Getting Images to render properly in the ASP.NET Designer

I tried this approach and it didn't work for me. I'm very confused and getting desperate. What I pass in to base.ResolveClientUrl() is a string which looks like the following:

"~/images/_selected.png"

What it gives me back is:

"images/_selected.png"

Trying then to pass the resolved URL to Bitmap.FromFile() throws my program into some weird loop for a moment and then I just have a broken image. What am I missing?

Rajeev
November 06, 2008

# re: Getting Images to render properly in the ASP.NET Designer

Thanks a million

West Wind  © Rick Strahl, West Wind Technologies, 2005 - 2024