2015-12-03 42 views
14

当我在没有EditHistory成员的情况下呈现我的模板时,它可以工作。然而,当我添加额外的成员,在我的应用程序中,我得到一个异常Could not load file or assembly 'Models, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or one of its dependencies. The system cannot find the file specified.模型是包含ContentModel,EditHistory和UserDetail的项目。孤立的RazorEngine无法将模型传递到不同的AppDomain

public class ContentModel 
{ 
    public string Html { get; set; } 
    public string Title { get; set; } 
    public EditHistory History { get; set; } 
} 

public class EditHistory 
{ 
    public IReadOnlyCollection<UserDetail> Authors { get; set; } 
} 

public class UserDetail 
{ 
    public string Name { get; set; } 
    public string EmailAddress { get; set; } 
} 

我在RazorDynamicObject包裹ContentModel这样: Razor.Run("default.cshtml", typeof(ContentModel), RazorDynamicObject.Create(cm));

如上所述,它的工作原理而不EditHistory存在,但失败时它是。

沙箱设置逐字按照它是如何做的https://antaris.github.io/RazorEngine/Isolation.html

我如何得到它与复杂的自定义类型的工作?

在ASP.NET下运行。

编辑 我创建了我正面临的问题的最小再现。它在https://github.com/knightmeister/RazorEngineIssue。如果包恢复失败,请手动install-package razorengine

+2

如果更换'公共EditHistory历史发生了什么{获取;集;}'和'公共IReadOnlyCollection 历史{get; set;}'并且也使用简单类型'public IReadOnlyCollection History {get; set;}'?只读集合是否会成为问题?如果你使用“IList”或“IEnumerable”呢?相同的结果? – Tommy

+2

任何机会,你可以把一个简单的VS项目放在一起,重现这个问题并在某处发布(例如GitHub)? –

+2

@CaioProiete - 好主意。我有一种感觉,并不是很多人会熟悉这个特定的模块。我不是,但很好奇追查究竟是什么导致失败(嵌套复杂类型,只读集合等) – Tommy

回答

4

首先;我永远无法让你的GitHub代码运行。以下是基于我自己的复制代码。

我认为你要无法加载文件或程序集 -exceptions因为当你设置了沙箱的AppDomain你设置:

adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase; 

这不会在ASP.NET工作因为程序集位于bin子文件夹中。要解决这个问题,只需做到这一点:

adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase 
          + "\\bin"; 

但是,ASP.NET将默认shadow copy assemblies。因此,只是进行此更改可能会导致另一个异常:

ArgumentException:对象类型无法转换为目标类型。

这是因为在默认应用程序域和沙箱中加载的程序集之间存在混淆。默认应用程序域中的那些位于临时卷影副本位置,沙盒中的那些位于Web应用程序根目录的bin文件夹中。

解决这个问题的最简单的方法是将<system.web>下面的这行的你的web.config禁用阴影复制:

<hostingEnvironment shadowCopyBinAssemblies="false"/> 

此外,我认为跳过使用RazorDynamicObject会更好,更容易,并用[Serializable]来标记模型。事实上,我从来没有得到RazorDynamicObject正常工作。

这个答案的其余部分总结了我做什么得出这样的结论


我认为,这是由于RazorEngine错误或限制。 (我不太知道这个了,这很可能是那个影子复制和RazorDynamicObject不能一起工作)

我已经花了几个小时试图找出如何得到这个工作,但我总是以RazorEngine抛出的安全异常结束。

但是,有一种可能的解决方法:RazorDynamicObject并将您的模型类标记为可序列化。

[Serializable] 
public class ContentModel 
{ 
    public string Html { get; set; } 
    public string Title { get; set; } 
    public EditHistory History { get; set; } 
} 

[Serializable] 
public class EditHistory 
{ 
    public IReadOnlyCollection<UserDetail> Authors { get; set; } 
} 

[Serializable] 
public class UserDetail 
{ 
    public string Name { get; set; } 
    public string EmailAddress { get; set; } 
} 

,做:

Razor.Run("default.cshtml", typeof(ContentModel), cm); // no RazorDynamicObject 

我不能让你的摄制代码的运行,所以我创建了自己的基于您的代码:

  1. 创建新的控制台应用程序(Visual Studio)

  2. 在包管理器控制台,运行:install-package razorengine

  3. 复制代码从您的摄制:

  4. [Serializable]标记模型。

  5. 删除RazorDynamicObject

  6. 为了确保我们真的可以使从作者列表中的用户信息,改变测试模板:

    string template = "@Model.History.Authors[0].EmailAddress"; 
    
  7. 此外,为了使该模板的工作,改变Authors in EditHistory from IReadOnlyCollection<> to IReadOnlyList<>

我创建了GIST,生成代码:
https://gist.github.com/mwikstrom/983c8f61eb10ff1e915a

这对我有用。正如它应该那样打印[email protected]


ASP。NET会默认影射副本程序集,这会导致沙盒问题。

要获得ASP.NET的这种工作,你就必须做到以下几点变化:

  1. 禁用ASP.NET阴影复制加入<system.web>下,按照Web.config文件:

    <hostingEnvironment shadowCopyBinAssemblies="false"/> 
    
  2. \bin附加到沙箱的应用程序基路径。因此,在createRazorSandbox(...)做:

    adSetup.ApplicationBase = 
        AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\bin"; 
    

我测试了这一点,它工作得很好。我的测试项目很简单:

  • 一个空的ASP.NET Web应用程序(使用Visual Studio创建的),用install-package razorengine

  • 在Web.config中<hostingEnvironment shadowCopyBinAssemblies="false"/>

  • 以下Global.asax.cs

https://gist.github.com/mwikstrom/ea2b90fd0d306ba3498c


这里有列出的其他替代品(除了禁用阴影复制):

https://github.com/Antaris/RazorEngine/issues/224

+0

嗨,谢谢你的努力。在发布之前,我尝试过这样做,并且我刚刚尝试了在GitHub上发布的示例(请参阅OP) - 是否能够运行? – Sam

+0

@Sam:请参阅我最近的编辑,其中显示了我所做的工作。 –

+0

感谢您的帮助,但这在ASP.NET下无效。它需要在ASP.NET下运行。 – Sam

1

我大多穿上”使用复杂的类型,但一般规则通常是只有原始数据类型才能传输好(我自己的规则,因为否则值往往会丢失)。然而,当我看到一些旧的源代码时,我注意到我确实使用了许多复杂的类型,但是我将它们填充到Controller中(例如,在Public ActionResult Index()中)。一些阅读后,我想,如果你使用类似这样的东西(未经测试,MSDN source2nd source)它可能工作:

[MetadataType(typeof(EditHistory))] 
public partial class ContentModel 
{ 
    public string Html { get; set; } 
    public string Title { get; set; } 
    public EditHistory History { get; set; } 
} 

[MetadataType(typeof(UserDetail))] 
public partial class EditHistory 
{ 
    public IReadOnlyCollection<UserDetail> Authors { get; set; } 
} 

public class UserDetail 
{ 
    public string Name { get; set; } 
    public string EmailAddress { get; set; } 
}