Helper for DropDownLists with extension method Is the following helper idiomatic ASP.NET MVC? All the built-in DropDownListFor helpers only accept IEnumerable&lt;SelectListItem&gt;. If the Model doesn't have this list, but an IEnumerable&lt;SomeEntity&gt;, avoiding this conversion in the Razor template seems to require some more of its helpers.

namespace CompanyName.ProjectName.PresentationLayer.Helpers
{
    // ...documentation omitted...
    public static MvcHtmlString DropDownListFor&lt;TModel, TElem&gt;(
        this HtmlHelper&lt;TModel&gt; htmlHelper,
        Expression&lt;Func&lt;TModel, string&gt;&gt; expression,
        IEnumerable&lt;TElem&gt; elements,
        Func&lt;TElem, string&gt; valueFunc,
        Func&lt;TElem, string&gt; textFunc
    )
    {
        ModelMetadata metadata =
            ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData);

        IEnumerable&lt;SelectListItem&gt; items =
            elements.Select(elem =&gt; new SelectListItem()
            {
                Value = valueFunc(elem),
                Text = textFunc(elem),
                Selected = elem.Equals(metadata.Model)
            });

        return htmlHelper.DropDownListFor&lt;TModel, string&gt;(expression, items);
    }
}
The native MVC solution is to pass your collection into the SelectList class.

@Html.DropDownListFor(m =&gt; m.Item, new SelectList(Model.MyList, "ValueProperty", "TextProperty"))


This would make your helper method unnecessary.

However, the downside to the native approach is that there is no compile-time safety on the Text/Value properties, so you may still want to have a helper method similar to what you've written for this added benefit.



The DropDownListFor methods handle which item is selected for you, so you don't need to concern yourself with populating the Selected property for your SelectListItems.

Your extension method is not idiomatic to DropDownListFor&lt;TModel, TProperty&gt; because you're not using a generic type for the given property. You would at least want to keep TProperty as a generic type, and add a third generic type to your extension method for the collection type. This would change your method signature to DropDownListFor&lt;TModel, TProperty, TElem&gt; and your second parameter to Expression&lt;Func&lt;TModel, TProperty&gt;&gt; expression.

However, your approach has one major design issue: you lose out on all the overloads that exist for DropDownListFor. While you could reimplement all of them, it would be tackling the wrong problem.

You essentially want an elegant way to create a SelectList, so that's what your extension method should do. A Linq extension that works similarly to the ToDictionary extension method would look like the following:

public static IEnumerable&lt;SelectListItem&gt; ToSelectList&lt;T&gt;(this IEnumerable&lt;T&gt; source, Func&lt;T, string&gt; valueFunc, Func&lt;T, string&gt; textFunc)
{
    return source.Select(x =&gt; new SelectListItem
    {
        Value = valueFunc(x),
        Text = textFunc(x)
    });
}


Then you can use the native MVC DropDownListFor on any collection easily:

@Html.DropDownListFor(m =&gt; m.Item, Model.MyList.ToSelectList(x =&gt; x.ValueProperty, x =&gt; x.TextProperty))
@Html.DropDownListFor(m =&gt; m.Item, Model.MyList.ToSelectList(x =&gt; x.ValueProperty, x =&gt; x.TextProperty), "Choose...", new { @class = "form-control dropdown" })