Razorlight: 'object' does not contain a definition for 'Name'

Created on 7 Mar 2018  路  16Comments  路  Source: toddams/RazorLight

I'm trying to convert an old project with RazorEngine to .netcore and RazorLight but with the old working template and code I get always this error: 'object' does not contain a definition for 'Name'

SomeMethod("\r\n<h1>Hello @Model.Name, welcome to RazorEngine!</h1>", new { Name = "pippo" });

.....

public string SomeMethod(string templateText, object model)
{
    var engine = new RazorLightEngineBuilder().UseMemoryCachingProvider().Build();
    Task<string> messageTask = Task.Run(async () => await engine.CompileRenderAsync("TemplateKey", templateText, model));
    var message = messageTask.Result;
    return message;
}

full exception:

"System.AggregateException: One or more errors occurred. ('object' does not contain a definition for 'Name') ---> Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Name'
   at CallSite.Target(Closure , CallSite , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at RazorLight.CompiledTemplates.GeneratedTemplate.<ExecuteAsync>d__0.MoveNext() in testtemplate:line 2
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.TemplateRenderer.<RenderPageCoreAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.TemplateRenderer.<RenderPageAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.TemplateRenderer.<RenderAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.RazorLightEngine.<RenderTemplateAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.RazorLightEngine.<RenderTemplateAsync>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.RazorLightEngine.<CompileRenderAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at TestProject.Mailer.Domain.MailTemplate.<>c__DisplayClass17_0.<<WithParameters>b__1>d.MoveNext() in D:\\Projects\\TestProject.Mailer\\TestProject.Mailer\\Domain\\MailTemplate.cs:line 61
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at TestProject.Mailer.Domain.MailTemplate.WithParameters(Object model) in D:\\Projects\\TestProject.Mailer\\TestProject.Mailer\\Domain\\MailTemplate.cs:line 62
   at TestProject.Mailer.CoreConsole.Program.Main(String[] args) in D:\\Projects\\TestProject.Mailer\\TestProject.Mailer.CoreConsole\\Program.cs:line 21
---> (Inner Exception #0) Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'object' does not contain a definition for 'Name'
   at CallSite.Target(Closure , CallSite , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecute1[T0,TRet](CallSite site, T0 arg0)
   at RazorLight.CompiledTemplates.GeneratedTemplate.<ExecuteAsync>d__0.MoveNext() in testtemplate:line 2
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.TemplateRenderer.<RenderPageCoreAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.TemplateRenderer.<RenderPageAsync>d__8.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.TemplateRenderer.<RenderAsync>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.RazorLightEngine.<RenderTemplateAsync>d__17.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.RazorLightEngine.<RenderTemplateAsync>d__16.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at RazorLight.RazorLightEngine.<CompileRenderAsync>d__11.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at TestProject.Mailer.Domain.MailTemplate.<>c__DisplayClass17_0.<<WithParameters>b__1>d.MoveNext() in D:\\Projects\\TestProject.Mailer\\TestProject.Mailer\\Domain\\MailTemplate.cs:line 61<---

Most helpful comment

@MarcoNicolodi if the class ViewModel isn't public it breaks. If it is public then everything in the sample works just fine.

All 16 comments

You are casting anonymous object to system.object. Exception message is self explanatory. Don't generics instead of object in your method. Closing

@toddams that code worked with razorengine... and using generics I have the same kind of exception with list of anonymous objects like this (also if I use posts.ToList();):

var posts = new[]
{
    new
    {
        CreatedDate = DateTime.Now,
        ContributorPic = "Doctor.png",
        CommentText = "Lorem ipsum dolor sit&#39;amet, consectetur adipiscing elit. Aliquam nec bibendum metus, eget malesuada ante. In convallis interdum nisl quis"
    },
    ....
};

var parameters = new
{
    ProjectName = "ProjectName",
    Posts = posts,
    Footer = "Footer"
};

This code also breaks:

var engine = new RazorLightEngineBuilder()
              .UseMemoryCachingProvider()
              .Build();

string template = "Hello, @Model.Name. Welcome to RazorLight repository";
ViewModel model = new ViewModel() { Name = "John Doe" };

string result = await engine.CompileRenderAsync("templateKey", template, model);

@giammin it works if you use template as a file instead of a in memory template string :)

This issue should still be reopened though, since the readme.md sample doesnt work (with typed model), at least in my environment (.netcore 2.1.300 on ubuntu 18.04). It only works with anonymously typed model.

it works if you use template as a file instead of a in memory template string :)

good to know.

this is a clue that this is indeed a bug dispite what @toddams says...

@MarcoNicolodi if the class ViewModel isn't public it breaks. If it is public then everything in the sample works just fine.

Honestly I feel this You're doing it wrong -> closing answer was a bit rude.
We aren't all senior developers knowing everything about C#.
As stated in the .NET documentation:

C#鈥檚 type system is unified such that a value of any type can be treated as an object. Every type in C# directly or indirectly derives from the object class type, and object is the ultimate base class of all types

So it was legitimately that we thought passing a type of object for our anonymous type would work.

So @giammin instead of passing a type object to your method, you should pass a dynamic.

But it doesn't completely solve the problem and, I too, think this issue should be reopened.

Here is what I could experience:

using dynamic instead of object partially solves the problem:

public static async Task<string> MyRazorHelperFunction(string templateKey, string template, dynamic model)
{
    var engine = new RazorLightEngineBuilder()
              .UseMemoryCachingProvider()
              .Build();

    return await engine.CompileRenderAsync(templateKey, template, model);
}

But it works only if this method is located in the same project where the anonymous object has been created

Here, only the first method works, not the second one, even though they're identical

var templateKey = "templateKey";
var template = "Hello, @Model.Name. Welcome to RazorLight repository";
var myAnonymousObject= new { Name = "John Doe" };

var resultFromSameProject = await MyHelperClassInTheSameProject.MyRazorHelperFunction(templateKey, template, myAnonymousObject);
var resultFromAnotherProject = await MyHelperClassInAnotherProject.MyRazorHelperFunction(templateKey, template, myAnonymousObject);

And YES, I did set <PreserveCompilationContext>true</PreserveCompilationContext> in the other project as well.

And for me, @MarcoNicolodi 's workaround still doesn't work if the method is located in a separate project.

Any idea @toddams ?
If this isn't a bug, instead of simply closing, could you please provide us the solution?

Thank you

Note: I tried with a generic type T as well but same result

Alright so I found the solution this morning, we should convert the anonymous object to an ExpandoObject object first (see Jon Skeet's answer)

And turns out, there is already an extension method implemented in RazorLight

That would have been great to know about this in the first place.

It now works using a separate project only if I combine this with a template as file like Marco Nicolodi said.

it works if you use template as a file instead of a in memory template string :)

But I still can't get it working using a string template.
Here, the 1st call works but the second fails:

var model = new { Name = "John Doe" }.ToExpando();
var resultUsingFilesystemProject = await MyHelperClassInAnotherProject.UsingFilesystemProject(templatesFolder, "RazorTemplate.cshtml", model);
string template = "Hello, @Model.SenderName. Welcome to RazorLight repository";
var resultFromAnotherProject = await MyHelperClassInAnotherProject.MyRazorHelperFunction("templateKey", template, model);

I get the exception

Can not resolve a content for the template "{0}" as there is no project set.You can only render a template by passing it's content directly via string using coresponding function overload

But I can't find which overload of CompileRenderAsync I should use.

Any example please? That would be really appreciated.

Thank you

Thanks @jmevel for the answers - which helped me a lot in figuring out a solution.

What worked for me was adding typeof(ExpandoObject)

so for example in the code in above example

var model = new { Name = "John Doe" }.ToExpando();
string template = "Hello, @Model.SenderName. Welcome to RazorLight repository";

var resultFromAnotherProject = await MyHelperClassInAnotherProject.MyRazorHelperFunction("templateKey", template, model, typeof(ExpandoObject));

@jmevel Thanks for mentioning this, but without seeing what your helper functions are doing, its difficult to know what the solution is. It's possible you are running into known issues around sub-template location. I've been meaning to dig into this but I imagine its a lot of work to figure out how ASP.NET Core Tooling does this resolution.

guys just stop bothering with this mess and use Handlebars.Net

it is a lot better: lighter, faster.

I'm sure the maintainers of Handlebars.net will love it when you harass them, too.

That's cute how lots of individuals think that they are doing you a favor by using your library, or that we, as a maintainers, owe them something. Guys, use the tools that works better for you. Expressing your toxic and completely redundant opinion is not mandatory

I spent enormous amount of time investigating how all this Razor internals work, library was rewritten a couple of times as Microsoft did major changes in Razor gears, and all that should have been reflected not to lag behind. @jzabroski did a priceless efforts to support this library since I had less time to continue supporting this library at that tempo, and since we are not getting paid at all and do not have any donations in the first place - just being polite @giammin is not a huge price for the library we opened to the world for everyone to use for free, isn't it?

just being polite

just look at this issue and at your attitude...

That's cute how lots of individuals think that they are doing you a favor by using your library, or that we, as a maintainers, owe them something. Guys, use the tools that works better for you. Expressing your toxic and completely redundant opinion is not mandatory

not at all. i dont think that you owe me nothing or I am not doing you a favor
that is why i decided to lost all of the work i did and move to another library

I would suggest not doxing yourself any further.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dombarnes picture dombarnes  路  7Comments

xxeasterxx picture xxeasterxx  路  5Comments

WaltDaniels picture WaltDaniels  路  6Comments

danwalmsley picture danwalmsley  路  7Comments

kinetiq picture kinetiq  路  3Comments