Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I turn an anonymous object into key/value pairs or HTML attributes?

In my MVC application, I have a helper class designed to render a group of related buttons. I'm trying to pass in the buttons' HTML attributes as an anonymous object:

new { @class="myClass1 myClass2" }

The helper emits HTML as an MvcHtmlString, which I'm currently building like this:

        foreach (var b in _buttons)
        {
            sb.AppendFormat("<button type='submit' name='{0}' {1}>{2}</button>",
                b.Value,
                b.HtmlAttributes,
                b.Text);
        }

My problem is that the above code produces invalid HTML:

<button type='submit' name='Foo' { class = myClass1 myClass2 }>Bar</button>

Unfortunately, since it's passed to the helper as an object, I don't have type information to work with. I could ToString the object and parse the result, but that seems pretty silly. How can I programmatically convert an anonymous object into key="value" style HTML attributes? Is there an existing utility for this?

like image 795
Justin Morgan Avatar asked Feb 29 '12 17:02

Justin Morgan


2 Answers

You should use the TagBuilder class, which builds HTML tags for you.

You can then write

builder.MergeAttributes(HtmlHelper.AnonymousObjectToHtmlAttributes(HtmlAttributes));
like image 170
SLaks Avatar answered Nov 13 '22 22:11

SLaks


As it turns out, there's a static method for this on the HtmlHelper class:

HtmlHelper.AnonymousObjectToHtmlAttributes(b.HtmlAttributes)

This solved my issue:

    foreach (var b in _buttons)
    {
        var dict = HtmlHelper.AnonymousObjectToHtmlAttributes(b.HtmlAttributes);

        var attr = dict.Keys.Zip(
            dict.Values, 
            (k, v) => string.Format("{0}='{1}'", k, v));

        sb.AppendFormat("<button type='submit' name='{0}' {1}>{2}</button>",
            b.Value,
            string.Join(" ", attr),
            b.Text);
    }

I also tried it with a TagBuilder and got about the same amount of code.


Edit: As Slaks pointed out, doing it this way is a potential XSS vulnerability. There was no risk in my specific use case, but TagBuilder seems like the best practice.

like image 30
Justin Morgan Avatar answered Nov 13 '22 23:11

Justin Morgan