The MVC platform: creating a new HTML helper
Yesterday I’ve presented the main properties and methods of the TagBuilder class. Today, we’re going to reuse those ideas and build an extension method that renders an image inside an anchor (unfortunately, the image helper methods are defined in the futures assembly and the current release of the anchors won’t let you pass HTML for its content). Before going on, I’d like to say two things:
- This isn’t going to be a complete example. What I mean by this is that I’m going to pick up a general form of helper and implement only that form (so, you won’t have all those overloads you generally end up having with the official methods);
- If I had to implement this scenario in the real world, I’d probably go with “straight HTML” and I’d use the Url helper methods for getting the correct urls.
Having said this, I still believe that building a simple example like this is good and might help you get a better grasp of the code used by the helpers. The idea is to have something like this:
<%=
Html.ActionLinkWithImage(
"~/Content/add.png", //relative image url
"About", //controller action
"Home", //controller
null , //route values
null, //link html attributes
new { style = "border: none"} //image html attributes
)
%>
As I said,I’m picking only one form (based on the anonymous object syntax) and I’m using it through out this example. You should be able to extend this sample with more overloads that give you more options and reduce the code you need to write if you’re note interested in setting all these parameters. Let’s see how easy it is to build this helper. Here’s the code:
public static class ImageWithAnchorHelper {
public static string ActionLinkWithImage( this HtmlHelper htmlHelper,
String relativeImageUrl,
String actionName,
String controllerName,
Object routeValues,
Object linkHtmlAttributes,
Object imageHtmlAttributes ) {
var url = GetUrlForLink( htmlHelper,
actionName,
controllerName,
routeValues,
null,
null,
null );
var tagBuilder = BuildTagForLink(
htmlHelper,
GetImageHtml( htmlHelper, relativeImageUrl, imageHtmlAttributes ),
linkHtmlAttributes, url );
return tagBuilder.ToString( TagRenderMode.Normal );
}
private static TagBuilder BuildTagForLink( HtmlHelper htmlHelper,
String imageHtml,
Object linkHtmlAttributes,
String url ) {
var tagBuilder = new TagBuilder( "a" ) {
InnerHtml = imageHtml
};
tagBuilder.MergeAttributes( new RouteValueDictionary( linkHtmlAttributes ) );
tagBuilder.MergeAttribute( "href", url );
return tagBuilder;
}
private static String GetIma
geHtml( HtmlHelper helper,
String relativeImageUrl,
Object imageHtmlAttributes ) {
var imageUrl = new UrlHelper( helper.ViewContext.RequestContext ).Content( relativeImageUrl );
var imageTag = new TagBuilder( "img" );
imageTag.MergeAttribute( "src", imageUrl, true );
imageTag.MergeAttributes( new RouteValueDictionary( imageHtmlAttributes ), true );
return imageTag.ToString( TagRenderMode.SelfClosing );
}
private static String GetUrlForLink( HtmlHelper html,
String actionName,
String controllerName,
Object routeValues,
String protocol,
String hostName,
String fragment ) {
var urlHelper = new UrlHelper( html.ViewContext.RequestContext );
var url = urlHelper.Action( actionName,
controllerName,
new RouteValueDictionary(routeValues),
protocol,
hostName );
if( !String.IsNullOrEmpty( fragment ) ) {
url += String.Concat (“#”, fragment);
}
return url;
}
}
As you can see, the ActionLinkWithImage method extends the HtmlHelper class and is the only public entry point of these helpers (all the other methods are private). The method starts by getting the url for the current action. If you look at the code used by the helpers, you’ll see that they use the GenerateUrl method for getting the current url. Unfortunately, the method is internal and so we can’t use it without resorting to reflection. On the other hand, we can use the UrlHelper class and its Action method. Lets take a closer look at the GetUrlForLink method. As you can see, we start by instantiating a UrlHelper object:
var url = urlHelper.Action( actionName,
controllerName,
new RouteValueDictionary(routeValues),
protocol,
hostName );
In this case, protocol and hostname are always null, but I’ve decided to leave the necessary code for making the adaptation of the GetUrlForLink easy for future helpers. That’s why I’ve also made the method receive a fragment, even though the main helper doesn’t accept it (as an exercise, you can always add more overloads which use those parameters: the private methods support them so it’s only necessary to add more overloads of the ActionLinkWithImage that receives them). A fragment is always in the form of http://…..#fragment. That’s why you’ve got that String.Concat there for joining an eventual fragment with the current url:
if( !String.IsNullOrEmpty( fragment ) ) {
url += String.Concat (“#”, fragment);
}
And that’s it for the GetUrlForLink method. Getting the HTML for the inner image is also easy, as you can see by looking at the GetImageHtml method. We start by creating an UrlHelper object for getting the correct url for the image. The main difference (when compared with the previous snippet) is that, in this case, we’re passing a relative url and so we’re using the Content method:
var imageUrl = new UrlHelper( helper.ViewContext.RequestContext ).Content( relativeImageUrl );
The “hard work” of getting the HTML is done by the TagBuilder class. Notice that I’m simply using the MergeAttribute and MergeAttributes method in order to set the attributes applied to the final IMG tag. The HTML is obtained by calling an overload of the ToString method and passing a value from the TagRenderMode enumeration to generate an image on the form <img … />:
var imageTag = new TagBuilder( "img" );
imageTag.MergeAttribute( "src", imageUrl, true );
imageTag.MergeAttributes( new RouteValueDictionary( imageHtmlAttributes ), true );
return imageTag.ToString( TagRenderMode.SelfCl
osing );
After having the inner HTML and the correct link url, we delegate the remaining work to the BuildTagForLink method:
private static TagBuilder BuildTagForLink( HtmlHelper htmlHelper,
String imageHtml,
Object linkHtmlAttributes,
String url ) {
var tagBuilder = new TagBuilder( "a" ) {
InnerHtml = imageHtml
};
tagBuilder.MergeAttributes( new RouteValueDictionary( linkHtmlAttributes ) );
tagBuilder.MergeAttribute( "href", url );
return tagBuilder;
}
As you can see, most of the work is done (once again) by the TagBuilder class. Since we’re passing HTML for the link’s content, we just pass that value to the InnerHtml property without encoding it (as happens with the current Link extension methods). And that’s all that is needed for having a helper that generates HTML. As I’ve said, this is only demo code. In a real work extension method you’re expected to provide more overloads and perform more validations. I’ll leave those modifications for those that intend to make this a “real world” extension method helper.
Keep tuned for more on the ASP.NET MVC.
can you show the output rendered to the view so we can conceptually see the end result in View Source?
Anonymous said this on June 17, 2009 at 8:39 pm |
??? ??? ??????????? ?????,??????? ?????? +? ????,????? ??????????? ?????????,???? ?????? ??????.
Broonfore said this on June 28, 2009 at 8:57 am |
??? ??? ??????????? ????? mp3,??????????? ????? ???????,??????????? ????? +??? ???????????,??????? ?????? ?????.
Broonfore said this on June 29, 2009 at 1:46 pm |
gRzYRJ yozkqtcfostr, [url=http://uymdkemgtqfu.com/]uymdkemgtqfu[/url], [link=http://iejxmecsyxhe.com/]iejxmecsyxhe[/link], http://dzpqkmeleaok.com/
umemzoa said this on October 24, 2009 at 8:26 am |
yoo. bookmarked ))
Swonloak said this on December 13, 2009 at 1:26 pm |
well.. it”s like I knew!
Amateur Beaver said this on December 21, 2009 at 2:59 pm |
hmm.. love this thoughts ))
Voyeur 19 Torrent said this on December 26, 2009 at 7:56 am |
understanding sports betting lines football bet tips sports betting lines ncaa
sports betting africa uganda bets wimbledon ufc 88 betting odds
free bets offer sportsbook online betting how to bet on sports games most popular sports bets
online bet boxing john morrison sports betting champ ufc 69 betting odds
champions league betting picks sports bet lines melbourne cup online bet sports bet football
sports betting in oregon sports betting nfl lines online poker sports betting
reading baseball betting lines football betting websites sports betting manuals betting odds melbourne cup
sport bet review bet on football sport betting uk
sports bet spread sports betting mathematics live tennis betting soccer betting strategies
teaser sports bet professional football betting odds sports betting in australia
arc de triomphe betting odds live betting football financial betting sports betting odds tennis
sports betting champ rapidshare 888 free bet sports betting in ontario
DyncKayange said this on December 31, 2009 at 7:21 pm |
?? ???????? ? ???????. ?????? ? ??? ???? 747067
Rengenx said this on February 17, 2010 at 3:34 am |
??? ???????: ???????.
???? ?????????? ?? ??? ?????? ? ????? – ???? ????????????? ??? ???????????
???? ?????????? ??? ?????????? – ????? ????????????? ???? ??????????
? ????????? ???? ????? ? ?????? ???????? ????? ???? ? ????????? ? ??????????
????????? ???? ? ???????? ? ?????? – ???? ? ???????? 2007 2009
????? ????????? ?? ???? ????? ??????: ????? ????????? ??? ?????
??? ????????????? ? ??????? ???????? – ??? ????????????? ? ???????????
?????????? ? ????????: ????????????? ???? ?????????? ? ????????
????? ???????????? ??????????? ?????? ????????????
????? ???? ? ?????? ????????? ???????? ????? ??????????
???? ????? ? ?????????? ???? ????? ? ???????
????? ????? ? ??????? ????????? ?? ?????????? ????? ?????
????????? ?????????? ??? ????? ???????: ?????????? ??? ????? 16
?????????? ?????? ????????????? ???? – ????????????? ???? ??? ???????
???????? ???? ????????? ??? ????? ??????: ???? ????????? ??? ?????????? ?????
???????????? ? ????? ????????: ???? ????????????? ? ??????????
???? ?????????? ?? 24lux ru ? ??????? – ?????????? ????? ??????????
???? ????? ? ??????? ?????? – ???? ????? ? ?????????
? ???????????? ??? ????????????? ? ????????: ??? ????? ????????????? ? ???????????? ? ??????
?????? ??????? ????? ?????????????: ?????? ??????? ????? ????????????? ? ??????
PlawlSaw said this on February 28, 2010 at 4:54 am |
ehh. good text ))
Drunk Frat Sex said this on March 4, 2010 at 12:22 am |