2015-12-03 30 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; } 
} 
相關問題