I have a RazorEngine project that fails following an upgrade to Razor 2.0 and RazorEngine 3.2.0
This worked fine in the previous Razor 1.0 based version of RazorEngine (3.0.8).
I have an instance (myInstance
) of a class (MyClass
) and and extension method:
namespace MyCompany.Extensions
{
public static class MyClassExtensions
{
public static string ExtensionMethod(this MyClass thing)
{
// do stuff
}
}
}
I want to call this in a RazorEngine view (simplified example, there are loads of these methods, and all fail the same way):
@using MyCompany.Extensions
@using MyCompany
@{
var myInstance = new MyClass(Model, ...);
}
Some text @myInstance.ExtensionMethod() some more text
This is in a text file that's compiled by RazorEngine:
string parsedResult = RE::Razor.Parse(fileContent, myModel, "testfile.txt");
The problem is that this line (which used to work) throws a RuntimeBinderException
:
'MyCompany.MyClass' does not contain a definition for 'ExtensionMethod'
Note that if I change the text file to:
Some text @MyClassExtensions.ExtensionMethod(myInstance) some more text
It works fine, so I think it must find the extension method's namespace.
My first thought was that it must be considering the passed model as a dynamic
(and hence anything derived from it as dynamic
too), but it knows the expected type in the RuntimeBinderException
. As the exception is run-time I think it must be failing to identify the extension method while the template is compiled, but why would that have changed?
I'm not sure what's changed between 3.0.8 and 3.2.0, or why this is broken. Is there something I need to add so that the extension method can be found while the template is compiled?
This is a bug in RazorEngine: the
Razor.Compile
works onTemplateBase<dynamic>
(soModel
and everything derived from it isdynamic
too) and that means that no extension methods undergo the 'compiler-magic' to convert them to the static calls. ThenRazor.Run
passes theModel
as the correct type, but the extension method syntax is called as an instance method.There will probably be a fix for this soon (the bug's only a few days old and this is a corner case), but in the meantime I have a workaround: explicitly type the
Model
in the Razor templateThis now works, because even though
Model
is stilldynamic
at compile-time that doesn't spread tomyInstance
any more.It's not ideal, and everywhere I used
Model
now has to bestrongTypeModel
, but that's a much simpler substitution.