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 on TemplateBase<dynamic>
(so Model
and everything derived from it is dynamic
too) and that means that no extension methods undergo the 'compiler-magic' to convert them to the static calls. Then Razor.Run
passes the Model
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 template
@using MyCompany.Extensions
@using MyCompany
@{
ExpectedModelClass strongTypeModel = Model as ExpectedModelClass;
MyClass myInstance = new MyClass(strongTypeModel , ...);
}
Some text @myInstance.ExtensionMethod() some more text
This now works, because even though Model
is still dynamic
at compile-time that doesn't spread to myInstance
any more.
It's not ideal, and everywhere I used Model
now has to be strongTypeModel
, but that's a much simpler substitution.
来源:https://stackoverflow.com/questions/14561695/razorengine-extension-method-fails-with-runtimebinderexception-after-upgrade-to