First of all; I was never able to get your GitHub-code running. The following is based on my own reproducing code.
I think that you're getting Could not load file or assembly-exceptions because when you setup the sandbox AppDomain you're setting:
adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase;
This won't work in ASP.NET because assemblies are in the bin
subfolder. To fix that, simply do this instead:
adSetup.ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase
+ "\\bin";
However, ASP.NET will by default shadow copy assemblies. Therefore just doing this change will probably cause another exception:
ArgumentException: Object type cannot be converted to target type.
That's because there's a mixup between assemblies loaded in the default app domain and the sandbox. The ones in the default app domain are located in a temporary shadow copy location and the ones in the sandbox are located in the bin-folder of your web application root.
The easiest way to fix this is to disable shadow copying by adding the following line under <system.web>
in your Web.config:
<hostingEnvironment shadowCopyBinAssemblies="false"/>
In addition; I think it's better and easier to skip using RazorDynamicObject
and instead mark your models with [Serializable]
. In fact I never got RazorDynamicObject
working properly.
The rest of this answer summarizes what I did to come to this conclusion
I think that this is due to a bug or limitation in RazorEngine. (I'm not so sure about this anymore, it might very well be that shadow copying and RazorDynamicObject
cannot work together)
I've spent a couple of hours trying to figure out how to get this working but I've always ended up with a security exception being thrown from RazorEngine.
There is, however, a possible workaround: Ditch RazorDynamicObject
and mark your model classes as serializable.
[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; }
}
And do:
Razor.Run("default.cshtml", typeof(ContentModel), cm); // no RazorDynamicObject
I couldn't get your repro code running, so I created my own based on your code:
Create a new Console application (Visual Studio)
In the package manager console, run: install-package razorengine
Copy code from your repro:
Mark models with [Serializable]
.
Remove RazorDynamicObject
To ensure that we really can render user details from the authors list, change the test template to:
string template = "@Model.History.Authors[0].EmailAddress";
Also, to make that template work, change Authors
in EditHistory
from IReadOnlyCollection<>
to IReadOnlyList<>
I created a GIST with the resulting code:
https://gist.github.com/mwikstrom/983c8f61eb10ff1e915a
This works for me. It prints [email protected]
just as it should.
ASP.NET will shadow copy assemblies by default and that will cause additional problems with sandboxing.
To get this working under ASP.NET you'll have to do the following changes:
Disable ASP.NET shadow copying by adding the following under <system.web>
in your Web.config file:
<hostingEnvironment shadowCopyBinAssemblies="false"/>
Append \bin
to the sandbox's application base path. So in createRazorSandbox(...)
do:
adSetup.ApplicationBase =
AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "\\bin";
I have tested this and it works just fine. My test project is simply:
An empty ASP.NET Web Application (created with Visual Studio), with install-package razorengine
<hostingEnvironment shadowCopyBinAssemblies="false"/>
in Web.config.
The following Global.asax.cs
:
https://gist.github.com/mwikstrom/ea2b90fd0d306ba3498c
There are other alternatives (besides disabling shadow copying) listed here:
https://github.com/Antaris/RazorEngine/issues/224
public EditHistory History {get;set;}
withpublic IReadOnlyCollection<UserDetail> History {get;set;}
and also the same test with a simple typepublic IReadOnlyCollection<string> History {get;set;}
? Could the read only collection be the problem? What if you used aIList
orIEnumerable
? Same results? – DocumentType is not resolved for member 'RazorEngine.Templating.IsolatedRazorEngineService+DefaultConfigCreator,RazorEngine, Version=3.7.4.0,
Any thoughts? – Documentinstall-package razorengine
– Arterio