7

I wanted to create a method in my Base controller that would take a list and return it as a SelectList. I wrote a method, and the site compiles, but I get this message:

Cannot call action method 'System.Collections.Generic.IEnumerable1[System.Web.Mvc.SelectListItem] GetSelectList[T](System.Collections.Generic.IEnumerable1[T], System.String, System.String, System.String, System.Object)' on controller 'PublicationSystem.Controllers.BaseController' because the action method is a generic method.
Parameter name: methodInfo

I'm wondering what I did wrong. Here's the code:

public partial class BaseController : Controller
{
    public IEnumerable<SelectListItem> GetSelectList<T>
    (
        IEnumerable<T> itemList, 
        string textField,
        string valueField,
        string defaultPrompt = "", 
        object defaultValue = null)
    {
        IEnumerable<SelectListItem> returnList = null;

        if (!string.IsNullOrEmpty(defaultPrompt))
        {
            returnList = Enumerable.Repeat(
                new SelectListItem { Value = (string)defaultValue, Text = defaultPrompt },
                count: 1);
        }

        var textProp = typeof (T).GetProperty(textField);
        var valueProp = typeof (T).GetProperty(valueField);

        returnList = returnList.Concat
            (itemList
                .Select(x =>
                    new SelectListItem
                    {
                        Value = Convert.ToString(valueProp.GetValue(x)),
                        Text = Convert.ToString(textProp.GetValue(x)),
                    }).Distinct().ToList());

        return returnList.ToList();
    }
}

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
        routes.LowercaseUrls = true;
        routes.MapMvcAttributeRoutes(); // Errors here
        //..
    }
}
M Kenyon II
  • 3,894
  • 4
  • 40
  • 86

2 Answers2

22

Your method is public in controller class. Asp.Net will see this method as an action method.

You can't use generic methods for action. Check this.

If you want to use this method on derived classes(your controllers). Make your method protected.

Community
  • 1
  • 1
Erkan Demirel
  • 4,232
  • 1
  • 22
  • 42
  • 2
    'Asp.Net will see this method as an action method.' was the key point, thank you. That sheds a new light on how the inherited controller works and what should and shouldn't be there. – M Kenyon II Mar 04 '16 at 20:46
  • @MKenyonII If it helped you can mark as an answer to guide other people. – Erkan Demirel Mar 06 '16 at 17:18
0

I removed this method. I turned it into an Extension method for IEnumerable<T>. Here's what I'm doing now:

public static class EnumerableExtensions
{
    public static IEnumerable<SelectListItem> AsSelectList<T>
    (
        this IEnumerable<T> dataList,
        string textField,
        string valueField,
        string defaultPrompt = "",
        object defaultValue = null)
    {
        IEnumerable<SelectListItem> returnList = new List<SelectListItem>();

        if (!string.IsNullOrEmpty(defaultPrompt))
        {
            returnList = Enumerable.Repeat(
                new SelectListItem { Value = (string)defaultValue, Text = defaultPrompt },
                count: 1);
        }

        var textProp = typeof(T).GetProperty(textField);
        var valueProp = typeof(T).GetProperty(valueField);

        returnList = returnList.Concat
            (dataList
                .Select(x =>
                    new SelectListItem
                    {
                        Value = Convert.ToString(valueProp.GetValue(x)),//x["valueField"],
                        Text = Convert.ToString(textProp.GetValue(x)),//x.["textField"]
                    }).Distinct().ToList());

        return returnList;
    }
}
M Kenyon II
  • 3,894
  • 4
  • 40
  • 86