升级到Razor 2/RE 3.2后,RazorEngine扩展方法失败,并出现RuntimeBinderException [英] RazorEngine extension method fails with RuntimeBinderException after upgrade to Razor 2/ RE 3.2

查看:79
本文介绍了升级到Razor 2/RE 3.2后,RazorEngine扩展方法失败,并出现RuntimeBinderException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 RazorEngine 项目,该项目在升级到Razor 2.0和RazorEngine 3.2.0之后失败了

在以前的基于Razor 1.0的RazorEngine(3.0.8)版本中,此方法运行良好.

我有一个类(MyClass)的实例(myInstance)和扩展方法:

namespace MyCompany.Extensions 
{
    public static class MyClassExtensions
    {
        public static string ExtensionMethod(this MyClass thing) 
        {
            // do stuff
        }
    }
}

我想在RazorEngine视图中调用它(简化示例,这些方法有很多,并且都以相同的方式失败):

@using MyCompany.Extensions
@using MyCompany
@{
    var myInstance = new MyClass(Model, ...);
}

Some text @myInstance.ExtensionMethod() some more text

这在RazorEngine编译的文本文件中:

string parsedResult = RE::Razor.Parse(fileContent, myModel, "testfile.txt");

问题是此行(以前可以正常工作)抛出RuntimeBinderException:

'MyCompany.MyClass'不包含'ExtensionMethod'的定义

请注意,如果我将文本文件更改为:

Some text @MyClassExtensions.ExtensionMethod(myInstance) some more text

它工作正常,所以我认为它必须找到扩展方法的名称空间.

我的第一个想法是,它必须将传递的模型视为dynamic(因此从它派生的任何内容也视为dynamic),但是它知道RuntimeBinderException中的预期类型.作为运行时的例外,我认为在编译模板时一定无法识别扩展方法,但是为什么会改变呢?

我不确定3.0.8和3.2.0之间有什么变化,或者为什么会被破坏.我需要添加一些东西,以便在编译模板时找到扩展方法吗?

解决方案

这是 RazorEngine中的错误: Razor.Compile可以在TemplateBase<dynamic>上运行(因此Model以及从其派生的所有内容也都是dynamic),这意味着没有扩展方法需要经过编译器魔术"才能将其转换为静态调用.然后Razor.RunModel作为正确的类型传递,但是扩展方法的语法称为实例方法.

可能很快会对此进行修复(该错误仅存在了几天,这是一个小案例),但是与此同时,我有一个解决方法:在Razor模板中明确键入Model

@using MyCompany.Extensions
@using MyCompany
@{
    ExpectedModelClass strongTypeModel = Model as ExpectedModelClass;
    MyClass myInstance = new MyClass(strongTypeModel , ...);
}

Some text @myInstance.ExtensionMethod() some more text

这现在可行,因为即使在编译时Model仍然是dynamic,也不再传播到myInstance了.

这并不理想,我现在使用的任何地方Model都必须是strongTypeModel,但这是一个更简单的替代方法.

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.

这篇关于升级到Razor 2/RE 3.2后,RazorEngine扩展方法失败,并出现RuntimeBinderException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆