Why You Can't Use Extension Methods With A WebGrid

5 (9 votes)

An interesting question came up recently on the ASP.NET forums. In it, the questioner was attempting to use my Chop() extension method to limit the number of characters in a WebGrid column but it wouldn't work. At first, I was a little stumped, so I tried it myself and got an error message:

'string' does not contain a definition for 'Chop'

 

Huh? The code looked fine:

        grid.Column(
            columnName : "Description",
            format: @<text>@item.Description.Chop(20)</text>
            )

..and the extension method was placed in a class called Extensions within App_Code, so it should have worked, surely? Then I studied the error message a little more closely, and saw this:

Exception Details: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'string' does not contain a definition for 'Chop'

The exception was being thrown by the RuntimeBinder, not the Compiler.

The argument that the WebGridColumn's Format parameter takes is a delegate: Func<dynamic,object>. What this means is that you have to pass in a dynamic type, and then something is done to it before it is returned as an object. A dynamic expression is resolved at runtime. The compiler doesn't know what it is.

When you try to use an extension method, the Compiler will check the type you are trying to use it on to see if such a method exists. If it doesn't. it will check any base classes that the type derives from to see if they contain a formal method with the right name. If that test fails, the Compiler will busy itself looking at any referenced static class which contains a static method with a first argument (the this part of an extension method) of the same type that the method is invoked on. In the case of the Chop method, that would a string. With dynamic variables, that reference isn't passed as part of the "Payload" to the RuntimeBinder, so it cannot find the extension method in your App_Code folder. And that, in the shell of a nut, is why you cannot use extension methods on a dynamic.

Great, so what can you do? Well, the extension method is still a static method on a class, so you can call it like this:

        grid.Column(
            columnName : "Description",
            format: @<text>@Extensions.Chop(item.Description, 20)</text>
            )

Note that this issue doesn't just affect items from a query which are passed to the format method in a WebGrid - it affects all the results you get from a database query because the Database.Query method returns an IEnumerable<dynamic>. That means that you cannot simply apply an extension method in this context either:

@foreach(var item in data){
    @item.Description.Chop(30)<br />
}

One thing you can do in the above example (outside of a WebGrid) is to convert the dynamic return to a strongly typed one. You can use Jeremy Skinners Strongly Type helper for WebMatrix.Data for this (http://www.jeremyskinner.co.uk/2011/01/24/strongly-typed-data-access-with-webmatrix-data/).

If you have problems trying to use extension methods within the WebGridColumn's format argument, or anywhere else on the dynamic return from a method, hopefully you know what to do now. But this example also goes to show that it pays to read exception messages carefully.

 

Date Posted:
Last Updated:
Posted by:
Total Views to date: 12430

2 Comments

- Alistair

Hi Mike, after hitting my head with Use Extension Methods With A WebGrid, i found this article, i tried your suggestion but i keep getting the error below, any ideas?

CS1738: Named argument specifications must appear after all fixed arguments have been specified

- Amir

Thanks mate!

Recent Comments

Jon 31/03/2016 21:36
In response to Exploring Prefix: A Free ASP.NET Profiling Tool
We had the exact same experience, finding multiple bugs in an application that we thought was pretty...

ranjith 31/03/2016 05:50
In response to A Better Way To Export Gridviews To Excel
Hello Mike. i am exporting from gridview, because i have some images in my gridview. but i am error...

Matt Watson 30/03/2016 22:19
In response to Exploring Prefix: A Free ASP.NET Profiling Tool
Glad you are loving it! Matt from Stackify...

Dmitry 28/03/2016 04:26
In response to Solved - The Microsoft.ACE.OLEDB.12.0 provider is not registered on the local machine
thank you about the VS 32-bit remark...

federico 26/03/2016 11:29
In response to Request.Form Is Empty When Posting To ASPX Page
thanks!....

Micheal 23/03/2016 00:58
In response to ASP.NET MVC 5 with EF 6 - Working With Files
Thanks for the code. its pretty straightforward. worked for me on my first trial. Perfect!...

Francisco 22/03/2016 20:35
In response to ASP.NET MVC 5 with EF 6 - Working With Files
The post is very good, thanks...

Nick Brown 22/03/2016 13:53
In response to Adding A View
Hi, Many thanks for this tutorial, it's helping me get started with MVC. In VB (VS 2013) I get late...

ferry mae 22/03/2016 13:04
In response to Send form content by email in ASP.NET
do i need to change this? message.To.Add(new MailAddress("me@domain.com")); message.CC.Add(new you...

Keith 22/03/2016 12:02
In response to Creating a Connection String and Working with SQL Server LocalDB
As always worst explanation, but this time you rocked with plagiarism too .. huhh.. copied from Rick...