Custom html helpers: Create helper with "using" statement support

Viewed 9890

I'm writing my first asp.net mvc application and I have a question about custom Html helpers:

For making a form, you can use:

<% using (Html.BeginForm()) {%>
   *stuff here*
<% } %>

I would like to do something similar with a custom HTML helper. In other words, I want to change:

Html.BeginTr();
Html.Td(day.Description);
Html.EndTr();

into:

using Html.BeginTr(){
    Html.Td(day.Description);
}

Is this possible?

3 Answers

Here is a possible reusable implementation in c# :

class DisposableHelper : IDisposable
{
    private Action end;

    // When the object is created, write "begin" function
    public DisposableHelper(Action begin, Action end)
    {
        this.end = end;
        begin();
    }

    // When the object is disposed (end of using block), write "end" function
    public void Dispose()
    {
        end();
    }
}

public static class DisposableExtensions
{
    public static IDisposable DisposableTr(this HtmlHelper htmlHelper)
    {
        return new DisposableHelper(
            () => htmlHelper.BeginTr(),
            () => htmlHelper.EndTr()
        );
    }
}

In this case, BeginTr and EndTr directly write in the response stream. If you use extension methods that return a string, you'll have to output them using :

htmlHelper.ViewContext.HttpContext.Response.Write(s)

If you look at the source for the ASP.NET MVC (available on Codeplex), you'll see the implementation of the BeginForm eventually calls down to the following code:

static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes)
{
    TagBuilder builder = new TagBuilder("form");
    builder.MergeAttributes<string, object>(htmlAttributes);
    builder.MergeAttribute("action", formAction);
    builder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);
    htmlHelper.ViewContext.HttpContext.Response.Write(builder.ToString(TagRenderMode.StartTag));

    return new MvcForm(htmlHelper.ViewContext.HttpContext.Response);
}

The MvcForm class implements IDisposable, in it's dispose method is writes the </form> to the response.

So, what you'd need to do is write the tags you want out in the helper method and return an object that implements IDisposable...in it's dispose method close the tag off.

Related