PPC-Coder
PPC-Coder

Reputation: 3632

TemplateCompilationError with RazorEngine and Layouts

I've been trying to use RazorEngine in a little project of mine but can't get past this error when I try to use template layouts.

Unable to compile template. 'object' does not contain a definition for 'Description' and no extension method 'Description' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

My Setup: I have a template layout like this:

<html>
<head>
    <title>@Model.Description</title>
</head>
<body>
    @RenderBody()
</body>
</html>

And then a page template that looks like this:

@{
    _Layout = "Layout.cshtml";
}
<h1>@Model.Description</h1>

Here is a test Main function I'm using to try and figure this out:

    static void Main(string[] args)
    {
        // Configuration for RazorEngine
        var config = new TemplateServiceConfiguration
        {
            EncodedStringFactory = new RawStringFactory(),

            Resolver = new DelegateTemplateResolver(name =>
            {
                var file = name;
                var content = File.ReadAllText("Templates/" + file);
                return content;
            })
        };

        // Try to render output using Razor
        using (var service = new TemplateService(config))
        {
            string template = File.ReadAllText("Templates/Default.cshtml");

            dynamic model = new ExpandoObject();
            model.Description = "This is a test";
            string result = service.Parse(template, model);
            Console.WriteLine(result);
            if (Debugger.IsAttached)
            {
                Console.ReadLine();
            }

        }
    }

Any idea what I'm missing?

Update: It works if I replace the dynamic model object with a POCO with a Description property. I also tried the typed version of Parse with

dynamic

, ExpandoObject, and IDictionary<string, object> but they all have the same error.

Update: I found this project on Github that seems to make it work somehow: https://github.com/mikoskinen/graze/blob/master/src/core/Graze.cs#L174

Upvotes: 10

Views: 3428

Answers (5)

Fish
Fish

Reputation: 11

try to use like this :

service.AddTemplate("layout", "<h1>@RenderBody()</h1>");
service.AddTemplate("template", @"@{Layout = ""layout"";}my template");
service.Compile("template");

Upvotes: 0

Fish
Fish

Reputation: 11

Razor vs. MVC vs. WebPages vs. RazorEngine There is often a confusion about where Razor sits in this set of technologies. Essentially Razor is the parsing framework that does the work to take your text template and convert it into a compilable class. In terms of MVC and WebPages, they both utilise this parsing engine to convert text templates (view/page files) into executable classes (views/pages). Often we are asked questions such as "Where is @Html, @Url", etc. These are not features provided by Razor itself, but implementation details of the MVC and WebPages frameworks.

Upvotes: 1

ministrymason
ministrymason

Reputation: 1793

Create the model as you do above

In your Index template set the ViewBag.Description to the Model.Description

@{
    _Layout = "Layout.cshtml";
    ViewBag.Description = Model.Description;
}

<div>Hello John </div>

In the layout page use the viewbag instead of the model

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
    <head>
        <title>@ViewBag.Description</title>
    </head>
    <body>
        <div id="content">
            @RenderBody()
        </div> 
        @if (IsSectionDefined("Footer"))
        { 
            <div id="footer">
                @RenderSection("Footer")
            </div>
        }
    </body>
</html>

I don't know why the dynamic model cant be used in the layout page. This is how i use it in my project

Upvotes: 2

Gleb Starazhenka
Gleb Starazhenka

Reputation: 43

You can't pass an anonymous type into a dynamically-typed view because the anonymous types are compiled as internal. Since the CSHTML view is compiled into a separate assembly, it can't access the anonymous type's properties.

Upvotes: 4

Plymouth223
Plymouth223

Reputation: 1925

I would think it to be more appropriate to use the template service's Parse overload that takes a ViewBag and use the ViewBag in your view rather than a model.

Edit:

public virtual string Parse(string razorTemplate, object model, DynamicViewBag viewBag, string cacheName)

Upvotes: 4

Related Questions