TemplateCompilationException thrown when using anonymous types with version 2.0

Jan 20, 2011 at 3:56 PM

I am trying to use an anonymous type as my model and with the latest 2.0 version and this test fails. Any Ideas?

        [TestMethod]
        public void Template_engine_supports_anonymous_models2()
        {
            string template ="<p>Hello @Model.Name</p><p>Time is: @Model.Time</p>";
            var model = new {Name = "World", Time = DateTime.Now};
            try
            {
                string result = RazorEngine.Razor.Parse(template, model);
                Assert.IsTrue(result.Contains("Hello World"));
            }
            catch (TemplateCompilationException compilationException)
            {
                foreach (var error in compilationException.Errors)
                {
                    Debug.WriteLine(error.ErrorText);
                }
                throw;
            }
        }

 

The error collection contains this:

Predefined type 'Microsoft.CSharp.RuntimeBinder.Binder' is not defined or imported
One or more types required to compile a dynamic expression cannot be found. Are you missing references to Microsoft.CSharp.dll and System.Core.dll?
One or more types required to compile a dynamic expression cannot be found. Are you missing references to Microsoft.CSharp.dll and System.Core.dll?
One or more types required to compile a dynamic expression cannot be found. Are you missing references to Microsoft.CSharp.dll and System.Core.dll?
One or more types required to compile a dynamic expression cannot be found. Are you missing references to Microsoft.CSharp.dll and System.Core.dll?

Coordinator
Jan 21, 2011 at 9:20 AM

That seems really odd, the Microsoft.CSharp reference issue normally occurs because the compiled assembly doesn't reference that assembly. We got round this by initialising a type from that assembly which forced it to be included in the assembly manifest.  It only seemed to crop up through unit tests, I only tested the fixed issue using NUnit. 

Could you send me a copy of your test project along with the assemblies and I'll have a look through and see if there is something I'm still missing? (matt [at] fidelitydesign (dot) net).

Jan 21, 2011 at 2:25 PM

I'm having the same problem with version 1.2 I get off of NuGet. Works fine when I run it as a console app, but gives me the Microsoft.CSharp.RuntimeBinder.Binder error when I run it in a nunit test. I can send you a copy of my solution if you like.

Coordinator
Jan 21, 2011 at 2:40 PM

Please do, I'll have a look at it over the weekend.


Jan 21, 2011 at 3:29 PM

I was able to get the test to pass by adding this line at the beginning of the test

bool loaded = typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly != null;

I guess this does the work of loading the Microsoft.CSharp assembly into the test AppDomain or something? Weird stuff

Coordinator
Jan 21, 2011 at 3:35 PM

That *shouln't* be required really.  The RazorEngine compiler service loads all the assemblies from the current AppDomain, which includes RazorEngine and any other assemblies referenced by it, including Microsoft.CSharp.

Jan 21, 2011 at 4:35 PM

That worked for me too.

Coordinator
Jan 21, 2011 at 9:00 PM

I believe the fix I put in place before still doesn't work.  The unused variable that references the Microsoft.CSharp assembly is omitted in the compiled assembly (as seen through reflector). To get round this, the v2.1 release will include an internal stub type that inherits from a Microsoft.CSharp type.  This inheritance enforces that the Microsoft.CSharp assembly is referenced and the type cannot be omitted. Check back for the release of v2.1

Feb 4, 2011 at 8:28 PM

I'm having this same issue on v2.1.

Feb 4, 2011 at 8:35 PM

Same here... I downloaded it through NuGet today.

Coordinator
Feb 4, 2011 at 9:02 PM

Can you send me a sample project recreating the issue? Send it to matt (at) fidelitydesign (dot) net

Feb 4, 2011 at 11:42 PM

Sent. I'm using xUnit. Are you, lordeagle?

Feb 5, 2011 at 12:14 AM

I sent one too. I'm using the VS Unit Tests.

Feb 5, 2011 at 1:58 AM
Edited Feb 5, 2011 at 4:43 PM

I'm having the same issue still with 2.1 as well. It seems like its not enough to have a type in your assembly that references System.CSharp because the CLR doesn't load it unless code is executed that needs it. Looking at the content of the Output window, it appears that this assembly has never been loaded.

Coordinator
Feb 6, 2011 at 12:34 PM

Curiously, I don't seem to have this issue using the NUnit unit test runner, but mstest and xunit seem to fail.  I haven't checked in the change, but you could do:

protected CompilerServiceBase(RazorCodeLanguage codeLanguage, MarkupParser markupParser)
{
    if (codeLanguage == null)
        throw new ArgumentNullException("codeLanguage");

    CodeLanguage = codeLanguage;
    MarkupParser = markupParser ?? new HtmlMarkupParser();

    // Once again... "eugh"...
    string dummy = new MicrosoftCSharpReferenceStub().ToString();
}

in Core\RazorEngine\Compilation\CompilerServiceBase.cs

I want to have another review before I check the change in as final.

 

 

Feb 7, 2011 at 1:25 AM

That fix works for me using xUnit.

Josh

Apr 20, 2011 at 3:11 AM

I'm having the same issue when using RazorEngine inside a windows service. I had to use jkll's hack to force loading the assembly. Any fix for this upcoming?

Coordinator
Apr 20, 2011 at 8:35 AM

Hi,

We're hoping to roll out a fix through v2.2, but unfortunately I've been so swamped with work I haven't progressed as far as I would have liked with it. Watch this space.

May 6, 2011 at 9:14 AM

It seems that the Microsoft.CSharp.dll is delay-loaded when dynamic is actually used (not declared, but used effectively in the code). When debugging from VS2010 (and probably NUnit is forcing to load it by default?) this assembly is loaded automatically by default.

For example, if you are instantiating and using a dynamic object (through the dynamic keyword) before parsing a template, the assembly Microsoft.CSharp.dll should be loaded when compiling templates.

Forcing RazorEngine to load Microsoft.CSharp.dll, by using jkll's workaround "bool loaded = typeof(Microsoft.CSharp.RuntimeBinder.Binder).Assembly != null;" is fixing this.