Extension methods cannot be dynamically dispatched

2019-01-14 05:37发布

问题:

I want to have DropDownListFor in MVC

@foreach (var item in Model)
{
    @Html.DropDownListFor(modelItem => item.TitleIds, new SelectList(ViewBag.TitleNames as System.Collections.IEnumerable, "TitleId", "Title.TitleText"), "No: " + ViewBag.MagNo, new { id = "TitleIds" })   
}

in Controller

public ActionResult ArticleList(int id)
{
    ArticleWriter_ViewModel viewModel = new ArticleWriter_ViewModel();
    Func<IQueryable<NumberTitle>, IOrderedQueryable<NumberTitle>> orderByFunc = null;
    Expression<Func<NumberTitle, bool>> filterExpr = null;
    if (id > 0)
    {
        filterExpr = p => p.MagazineId.Equals(id);
    }
    var wholeTitles = unitOfWork.NumberTitleRepository.Get(filterExpr,  orderByFunc, "Magazine,Title").ToList();          

    ViewBag.MagNo = wholeTitles[0].Magazine.MagNo.ToString();
    ViewBag.MagId = wholeTitles[0].Magazine.Id;
    ViewBag.TitleNames = wholeTitles;

    return View("../Panel/Magazine/ArticleList", "_BasicLayout", viewModel);
}

but I get this error

'System.Web.Mvc.HtmlHelper<System.Collections.Generic.IEnumerable<Cinemavaadabiat.ViewModel.ArticleWriter_ViewModel>>' has no applicable method named 'DropDownListFor' but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax.

I can't understand the error, what should I check for it?

回答1:

You are using dynamic types in extension methods, which is not supported.

Cast the dynamic types to actual types, and it will work.

From what I see now, I'd say:

(string) ViewBag.MagNo

Which would result in

@foreach (var item in Model)
{
    @Html.DropDownListFor(modelItem => item.TitleIds, 
       new SelectList(ViewBag.TitleNames as System.Collections.IEnumerable, 
       "TitleId", "Title.TitleText"), 
       "No: " + (string) ViewBag.MagNo, 
       new { id = "TitleIds" })   
}


回答2:

My fix for this problem was to add:

    @model MyModel

At the top of the partial control. I had forgotten it.



回答3:

To expand on the subject of MVC extension methods (which is how I ran across this question), I like to use Dapper's connection.Query() syntax which will return results as an IEnumerable<dynamic>.

It is also possible to use dynamic objects by:

  • Calling the static method directly, per Jon Skeet's answer:

    @model IEnumerable<dynamic>
    
    @PartialExtensions.Partial(Html, "~/link/to/_partialView.cshtml", Model)
    
  • Wrapping it in a class.

    public class DynamicQueryResult
    {
        public dynamic QueryResults {get; set;}
    }
    

    Then in your MVC View:

    @model Namespace.DynamicQueryResult
    
    @Html.Partial("~/link/to/_partialView.cshtml", Model)