ASP.NET Image Control With Fallback URL
What happens when the URL that your image is pointing to does not exist or cannot be reached? Well, all browsers I know of resort to displaying something like:
Sometimes, however, we may be able to anticipate that a given image won’t be accessible and instead choose to serve something else. For that, we can rely on the DOM onerror event; in the case of img tags, this event is raised when the target image cannot be displayed. In that situation, we have the opportunity to change its src property to point to a valid, alternative, location.
One control that we use to display images in ASP.NET is the venerable Image. What if we could change this control so that it supports an alternative URL, in case its target image cannot be loaded? It turns out, it is very easy to achieve this! Let’s start with some code:
1: <asp:Image runat="server" ImageUrl="NonexistentImage.png" FallbackUrl="AlternativeImage.png" />
As you can see, I added an extra FallbackUrl attribute to the control’s declaration. Image won’t mind, because it implements IAttributeAccessor, which, in case you don’t know, allows for having extra attributes, that is, attributes that cannot be mapped to actual properties.
There are two ways to proceed:
-
Having a control adapter inject some JavaScript onerror handler for all Image with an attribute FallbackUrl (mind you, I talked about control adapters before);
-
Having a control derived from Image that does the JavaScript injection.
This time, I’ll go for option 2. Let’s implement one such control:
1: public class ImageWithFallback : Image
2: {
3: [DefaultValue("")]
4: [Description("An alternative URL in case the image cannot be loaded")]
5: public String FallbackUrl
6: {
7: get;
8: set;
9: }
10:
11: protected override void OnLoad(EventArgs e)
12: {
13: if (String.IsNullOrWhiteSpace(this.FallbackUrl) == false)
14: {
15: this.Attributes["onerror"] = String.Format("this.src = '{0}'", this.ResolveUrl(this.FallbackUrl));
16: }
17:
18: base.OnLoad(e);
19: }
20: }
OK, now I have this control, but I have hundreds of already existing declarations of Image. There’s no way I can replace them all… Enter tag mappings!
Tag mappings, as its name implies, allow mapping one tag to another, that is, effectively replacing all instances of a control declared on markup for another control. This other control must be a class that inherits from the declared one. This is the case in my example. Here’s the way to go:
1: <pages>
2: <tagMapping>
3: <add tagType="System.Web.UI.WebControls.Image" mappedTagType="MyNamespace.ImageWithFallback, MyAssembly"/>
4: </tagMapping>
5: </pages>
And that’s it! All Image controls on your site, provided you add them a valid FallbackUrl property, will display an alternative image if the target image cannot be found! Easy, don’t you think?