Giter VIP home page Giter VIP logo

razorenginecore's Introduction

RazorEngineCore

.NET6 Razor Template Engine. No legacy code. No breaking changes.

  • .NET 6.0
  • .NET 5.0
  • .NET Standard 2.0
  • .NET Framework 4.7.2
  • Windows / Linux
  • Publish as single file supported
  • Thread safe
  • Template debugging

NuGet NuGet Gitter

Every single star makes maintainer happy! ⭐

NuGet

Install-Package RazorEngineCore

Feature requests

✅ Feel free to create new issues and vote for existing ones!

Articles

Wiki

Extensions

  • wdcossey/RazorEngineCore.Extensions
    • HTML values encoded by default (See issue #65 and @Raw)
    • Template precompiling
    • Direct model usage without RazorEngineTemplateBase
     template.Run(object model = null)
     template.RunAsync(object model = null)
     template.Run<TModel>(TModel model = null)
     template.RunAsync<TModel>(TModel model = null)

💥 HTML Safety

RazorEngineCore is not HTML safe by default.
It can be easily turned on: see #65 and @Raw

Examples

Basic usage

IRazorEngine razorEngine = new RazorEngine();
IRazorEngineCompiledTemplate template = razorEngine.Compile("Hello @Model.Name");

string result = template.Run(new
{
    Name = "Alexander"
});

Console.WriteLine(result);

Strongly typed model

IRazorEngine razorEngine = new RazorEngine();
string templateText = "Hello @Model.Name";

// yeah, heavy definition
IRazorEngineCompiledTemplate<RazorEngineTemplateBase<TestModel>> template = razorEngine.Compile<RazorEngineTemplateBase<TestModel>>(templateText);

string result = template.Run(instance =>
{
    instance.Model = new TestModel()
    {
        Name = "Hello",
        Items = new[] {3, 1, 2}
    };
});

Console.WriteLine(result);

Debugging

Compile template with IncludeDebuggingInfo() option and call EnableDebugging() before running template. If template was compiled with IncludeDebuggingInfo() option, saving and loading will keep original template source code and pdb.

IRazorEngineCompiledTemplate template2 = razorEngine.Compile(templateText, builder =>
{
    builder.IncludeDebuggingInfo();
});

template2.EnableDebugging(); // optional path to output directory

string result = template2.Run(new
{
    Title = "Welcome"
});

Place @{ Breakpoint(); } anywhere in template to stop at.

Save / Load compiled templates

Most expensive task is to compile template, you should not compile template every time you need to run it

IRazorEngine razorEngine = new RazorEngine();
IRazorEngineCompiledTemplate template = razorEngine.Compile("Hello @Model.Name");

// save to file
template.SaveToFile("myTemplate.dll");

//save to stream
MemoryStream memoryStream = new MemoryStream();
template.SaveToStream(memoryStream);
IRazorEngineCompiledTemplate template1 = RazorEngineCompiledTemplate.LoadFromFile("myTemplate.dll");
IRazorEngineCompiledTemplate template2 = RazorEngineCompiledTemplate.LoadFromStream(myStream);
IRazorEngineCompiledTemplate<MyBase> template1 = RazorEngineCompiledTemplate<MyBase>.LoadFromFile<MyBase>("myTemplate.dll");
IRazorEngineCompiledTemplate<MyBase> template2 = RazorEngineCompiledTemplate<MyBase>.LoadFromStream<MyBase>(myStream);

Caching

RazorEngineCore is not responsible for caching. Each team and project has their own caching frameworks and conventions therefore making it impossible to have builtin solution for all possible needs.

If you dont have one, use following static ConcurrentDictionary example as a simplest thread safe solution.

private static ConcurrentDictionary<int, IRazorEngineCompiledTemplate> TemplateCache = new ConcurrentDictionary<int, IRazorEngineCompiledTemplate>();
private string RenderTemplate(string template, object model)
{
    int hashCode = template.GetHashCode();

    IRazorEngineCompiledTemplate compiledTemplate = TemplateCache.GetOrAdd(hashCode, i =>
    {
        RazorEngine razorEngine = new RazorEngine();
        return razorEngine.Compile(Content);
    });

    return compiledTemplate.Run(model);
}

Template functions

ASP.NET Core way of defining template functions:

<area>
    @{ RecursionTest(3); }
</area>

@{
  void RecursionTest(int level)
  {
	if (level <= 0)
	{
		return;
	}

	<div>LEVEL: @level</div>
	@{ RecursionTest(level - 1); }
  }
}

output:

<div>LEVEL: 3</div>
<div>LEVEL: 2</div>
<div>LEVEL: 1</div>

Helpers and custom members

string content = @"Hello @A, @B, @Decorator(123)";

IRazorEngine razorEngine = new RazorEngine();
IRazorEngineCompiledTemplate<CustomTemplate> template = razorEngine.Compile<CustomTemplate>(content);

string result = template.Run(instance =>
{
    instance.A = 10;
    instance.B = "Alex";
});

Console.WriteLine(result);
public class CustomTemplate : RazorEngineTemplateBase
{
    public int A { get; set; }
    public string B { get; set; }

    public string Decorator(object value)
    {
        return "-=" + value + "=-";
    }
}

Referencing assemblies

Keep your templates as simple as possible, if you need to inject "unusual" assemblies most likely you are doing it wrong. Writing @using System.IO in template will not reference System.IO assembly, use builder to manually reference it.

IRazorEngine razorEngine = new RazorEngine();
IRazorEngineCompiledTemplate compiledTemplate = razorEngine.Compile(templateText, builder =>
{
    builder.AddAssemblyReferenceByName("System.Security"); // by name
    builder.AddAssemblyReference(typeof(System.IO.File)); // by type
    builder.AddAssemblyReference(Assembly.Load("source")); // by reference
});

string result = compiledTemplate.Run(new { name = "Hello" });

Credits

This package is inspired by Simon Mourier SO post

Changelog

  • 2024.4.1
  • 2023.11.2
    • Virtual keyword fixed
  • 2023.11.1
  • 2022.8.1
    • Proper namespace handling for nested types and types without namespace #113 (thanks @Kirmiir)
  • 2022.7.6
    • Added the option to genereate pdb alongside the assembly which allows debugging the templates.
  • 2022.1.2
    • #94 publish as single file fix
  • 2022.1.1
    • Make private methods in RazorEngine protected and virtual #PR88 (thanks @wdcossey)
    • Dictionary bug in anonymous model #91 (thanks @jddj007-hydra)
    • Template name fix #PR84 (thanks @Yazwh0)
    • CI for GitHub Actions #PR69 (thanks @304NotModified)
    • Added Source Link #PR67 (thanks @304NotModified)
    • Microsoft.AspNetCore.Razor.Language 3.1.8 -> 6.0.1
    • Microsoft.CodeAnalysis.CSharp 3.7.0 -> 4.0.1
  • 2021.7.1
  • 2021.3.1
    • fixed NET5 publish as single file (thanks @jddj007-hydra)
    • AnonymousTypeWrapper array handling fix
    • System.Collections referenced by default
    • Microsoft.AspNetCore.Razor.Language 3.1.8 -> 5.0.3
    • Microsoft.CodeAnalysis.CSharp 3.7.0 -> 3.8.0
  • 2020.10.1
    • Linux fix for #34
    • Microsoft.AspNetCore.Razor.Language 3.1.5 -> 3.1.8
    • Microsoft.CodeAnalysis.CSharp 3.6.0 -> 3.7.0
  • 2020.9.1
    • .NET 4.7.2 support (thanks @krmr)
  • 2020.6.1
    • Reference assemblies by Metadata (thanks @Merlin04)
    • Expose GeneratedCode in RazorEngineCompilationException
    • Microsoft.AspNetCore.Razor.Language 3.1.4 -> 3.1.5
  • 2020.5.2
    • IRazorEngineTemplate interface
    • RazorEngineTemplateBase methods go virtual
  • 2020.5.1
    • Async methods (thanks @wdcossey)
    • Microsoft.AspNetCore.Razor.Language 3.1.1 -> 3.1.4
    • Microsoft.CodeAnalysis.CSharp 3.4.0 -> 3.6.0
  • 2020.3.3
    • Model with generic type arguments compiling fix
  • 2020.3.2
    • External assembly referencing
    • Linq included by default
  • 2020.3.1
    • In attribute rendering fix #4
  • 2020.2.4
    • Null values in model correct handling
    • Null model fix
    • Netstandard2 insted of netcore3.1
  • 2020.2.3
    • Html attribute rendering fix
    • Html attribute rendering tests

Supported by

razorenginecore's People

Contributors

304notmodified avatar a9g-data-droid avatar adoconnection avatar daghb avatar danielstout5 avatar daviddotcs avatar dependabot[bot] avatar itworksonmymachine avatar krmr avatar merlin04 avatar roja avatar shehrozeee avatar spremotely avatar theatomicoption avatar wdcossey avatar yazwh0 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

razorenginecore's Issues

@Model is null when using RazorEngineTemplateBase

I've run into an issue when attempting to strongly type a template.
My template has @inherits RazorEngineCore.RazorEngineTemplateBase<MyModelType> at the top, and this makes intellisense work nicely.

The template compiles just fine, but when I run it, I always get "Object not sent to instance of an object" when I reference any property on my model. I know my model is not null. It works fine when render it without using RazorEngineTemplateBase.

Running a template with @(Model == null) works, but always renders "True".

My generic render function:

private static ConcurrentDictionary<int, IRazorEngineCompiledTemplate<IRazorEngineTemplate>> TemplateCache = 
            new ConcurrentDictionary<int, IRazorEngineCompiledTemplate<IRazorEngineTemplate>>();

public static string Render<TModel>(string template, TModel model, Assembly[] referencedAssemblies = null)
        {
            int templateHashCode = template.GetHashCode();

            var compiledTemplate = TemplateCache.GetOrAdd(templateHashCode, i =>
            {
                var razorEngine = new RazorEngine();

                var compiledTemplate = razorEngine.Compile<RazorEngineTemplateBase<TModel>>(template, builder =>
                {
                    ...
                });

                return compiledTemplate;
            });

            return compiledTemplate.Run(instance =>
            {
                instance.Model = model;
            });
        }

Any help on this would be greatly appreciated. Thanks.

Documentation update to improve usage experience: @Inherits directive

Firstly thank you for this project. I have battled with various other packages and couldn't get them to work reliably with .NET Core 3.1 running in an Azure Function. Yours works perfectly.

Here's something I feel would improve the user experience if it was documented...

For anyone who is storing their templates in CSHTML files either in the file system or as an embedded resource, the lack of the @model and @using statements mean you can't benefit from Visual Studio's IntelliSense when editing the files. You end up with lots of warnings in the code whereever you reference @Model.Property, or @include (if you are implementing the @include support from your wiki).

I have found that when using a strongly typed model, adding an @inherits directive to the file greatly improves this.

@inherits RazorEngineCore.RazorEngineTemplateBase<MyModel>

Or in my case where I'm using a custom template base to implement the include functionality, I'm using:

@inherits FunctionsApp1.Email.CustomRazorEngineTemplateBase<MyClassLib.EmailModels.WelcomeModel>

I hope this helps.

Unable to migrate from RazorEngine: "error: (19, 18) The name 'inherits' does not exist in the current context"

I'm currently trying to migrate away from the old RazorEngine v3.10.0 to RazorEngineCore v2.2.6. I changed the package and my project compiles. After getting a message related to the @model directive, I found out it is not supported in the Core version, and that, if one wants to have intellisense, one has to add an @inherits tag.

https://github.com/adoconnection/RazorEngineCore/wiki/Switch-from-RazorEngine-cshtml-templates#template

However, when I add that in place of the old @model, I get an exception:

 RazorEngine.Templating.TemplateCompilationException : Errors while compiling a Template.
    Please try the following to solve the situation:
      * If the problem is about missing/invalid references or multiple defines either try to load 
        the missing references manually (in the compiling appdomain!) or
        Specify your references manually by providing your own IReferenceResolver implementation.
        See https://antaris.github.io/RazorEngine/ReferenceResolver.html for details.
        Currently all references have to be available as files!
      * If you get 'class' does not contain a definition for 'member': 
            try another modelType (for example 'null' to make the model dynamic).
            NOTE: You CANNOT use typeof(dynamic) to make the model dynamic!
        Or try to use static instead of anonymous/dynamic types.
    More details about the error:
     - error: (19, 18) The name 'inherits' does not exist in the current context

I tried both:

  • @inherits RazorEngineCore.RazorEngineTemplateBase<MyModel>
    (which actually gives me red squiggly lines in the editor)
    as well as
  • @inherits RazorEngine.Templating.TemplateBase<MyModel>

What am I missing?

Can I use the @model type directive in my template?

It might just be me, but I get an error saying "The name 'model' does not exist in the current context" whenever I have a @model directive in my strongly typed template. It runs without it, but I'd rather have it there than not. I've been through the gamut trying fixes outlined in this and this stack overflow post.

Dependency issue with CodeAnalysis.CSharp

Severity	Code	Description	Project	File	Line	Suppression State
Error	NU1608	Detected package version outside of dependency constraint: Microsoft.CodeAnalysis.CSharp.Workspaces 3.3.1 requires Microsoft.CodeAnalysis.CSharp (= 3.3.1) but version Microsoft.CodeAnalysis.CSharp 3.8.0 was resolved.	Joinder.Enterprise.Api	C:\projects\secret project\secret project.csproj	1	

Calling extension methods from template

Hi,

Is there a way to call extension methods from templates?

I have an object in an external assembly, and in that assembly there is a public static class without a namespace that contains some extension methods for that object.

I want to call @Model.MyObject.MyExtensionMethod(parameter) from within the template, but I get a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException exception throw with the error:

'MyLibrary.MyObject' does not contain a definition for 'MyExtensionMethod'

I have tried adding a reference to MyLibrary this way:

var template = razorEngine.Compile<RazorEngineTemplateBase<TestModel>>(content, builder =>
{
	builder.AddAssemblyReference(typeof(MyLibrary.MyObject));
});

But without any luck.

Is this achievable?

CI

Hey! I noticed this repo isn't building on a CI in the cloud. Do you like any help on setting this up? (AppVeyor, it's free for OSS)

It's my way to say: thx :)

RazorEngineCompiledTemplate.Run() can hang

Hallo,

currently there is only RazorEngineCompiledTemplate.Run() with a strange code:
instance.ExecuteAsync().Wait();

It can lead to hang.
Please provide/replace with async version of the method.

how can I reference other assemblies and use inject?

I tried to use localization in razor:

@using Microsoft.Extensions.Localization

@inject IStringLocalizer Localizer

@{
   <h1>Localizer["Header"]<h1>;
}

I added reference to my project. Result:
Unable to compile template: skvbsxxk.c3i(3,17): error CS0234: The type or namespace name 'Extensions' does not exist in the namespace 'Microsoft'

When I add any other reference I get the same result. Can I manage this?

Linq functions I can use in template

What im doing wrong here:

@using System.Linq
@inherits RazorEngineCore.RazorEngineTemplateBase<SummaryData>

<div>
@if (Model.Data.Any()) {
}
</div>

we did add references

var compiletView = await razorEngine.CompileAsync(view, builder =>
                    {
                        builder.AddAssemblyReferenceByName("System.Linq");
                        builder.AddAssemblyReference(typeof(System.Linq.Enumerable));
                    });

but we get error that Any is not a function
System.Private.CoreLib: Exception while executing function: PDFGenerator. Anonymously Hosted DynamicMethods Assembly: 'object' does not contain a definition for 'Any'

Data is property used from model is IEnumerable<stirng>

'Any' or FirstOrDefault or any Linq method are not working

Could not load file or assembly 'Microsoft.CodeAnalysis

I'm trying to use this lib to generate HTML on an Azure Function, not sure what could be going wrong here.

public static string RenderViewToString(RedactedViewModel model)
{
    const string templateName = "redacted";
    string viewPath = Path.Combine(Constants.VIEW_FOLDER_PATH, templateName + ".cshtml");

    return new RazorEngine()
        .Compile(File.ReadAllText(viewPath))
        .Run(model);
}

System.IO.FileNotFoundException
HResult=0x80070002
Message=Could not load file or assembly 'Microsoft.CodeAnalysis, Version=3.6.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35'. The system cannot find the file specified.
Source=RazorEngineCore
StackTrace:
at RazorEngineCore.RazorEngineCompilationOptions..ctor()
at RazorEngineCore.RazorEngineCompilationOptionsBuilder..ctor(RazorEngineCompilationOptions options)

HTML encoding by default

I was checking out this project and saw on this page that the output of @Foo is not HTML-encoded by default. Why was this design decision made?

I'd like to use RazorEngineCore for rendering HTML reports, so I would really prefer it encoded content by default and let me use @Raw in rare cases where I don't need it.

The name 'Html' does not exist in the current context'

First of all I would like to thank you for this great library. Very needed and useful.

Just trying to wrap my head around the concepts.

First Hello World was to implement your library with a simple template that has some Html tags.

For instance, as simple as it gets

 string content = @"
                    @using System.Web.Mvc;
                   @foreach (var item in Model.Items.OrderByDescending(x => x))
                   {
                      <p>Number @item, @Html.Hidden(""StudentId"")</p>                  
                   }

                ";

var template1 = razorEngine1.Compile<RazorEngineTemplateBase<TestModel>>(content, builderAction => {
                builderAction.AddAssemblyReferenceByName("System.Web.Mvc");

            });


But I get an exception :)

Can you point me in a direction.

Cheers
Janus

Error when trying to use @inherits directive

I'm trying to use the @inherits directive (as the documentation says here) in my template so I can use intellisense and code suggestions.

But the build is throwing this error:

C:\project\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\template_detalhado_cshtml.g.cs(39,135): error CS0103: The name 'StartTagHelperWritingScope' does not exist in the current context

C:\project\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\template_detalhado_cshtml.g.cs(39,163): error CS0103: The name 'EndTagHelperWritingScope' does not exist in the current context

C:\project\Microsoft.NET.Sdk.Razor.SourceGenerators\Microsoft.NET.Sdk.Razor.SourceGenerators.RazorSourceGenerator\template_detalhado_cshtml.g.cs(138,73): error CS0103: The name 'CreateTagHelper' does not exist in the current context

Does anyone know why is this happening and how can I prevent it?

Problems migrating working template to library throwing weird errors

I have a project that I am migrating from WebForms to Blazor Servers side in .NET 5. The original project used this library from https://antaris.github.io/RazorEngine/. This library wasnt working and I wanted to use a library that was more supported. This library seems like a good fit. I have a report cshtml file that is 99% the same as the original working report (except for different @using statement locations, but it is lighting up and the projects have the proper project references), and code that is doing exactly what it originally did and getting a DTO that is exactly the same as the original. When I run the code I get the following errors:

Unable to compile template: s1wj2dld.c0p(5,7): error CS0246: The type or namespace name 'Bridgespan' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(6,7): error CS0246: The type or namespace name 'Bridgespan' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(7,7): error CS0246: The type or namespace name 'Bridgespan' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(8,7): error CS0246: The type or namespace name 'Bridgespan' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(10,7): error CS0103: The name 'model' does not exist in the current context
s1wj2dld.c0p(13,2): error CS0103: The name 'Layout' does not exist in the current context
s1wj2dld.c0p(19,16): error CS0103: The name 'Enum' does not exist in the current context
s1wj2dld.c0p(19,38): error CS0246: The type or namespace name 'AnswerResult' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(19,58): error CS0246: The type or namespace name 'AnswerResult' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(19,109): error CS0246: The type or namespace name 'AnswerInfoAttribute' could not be found (are you missing a using directive or an assembly reference?)
s1wj2dld.c0p(22,9): error CS0103: The name 'AnswerResult' does not exist in the current context
s1wj2dld.c0p(24,9): error CS0103: The name 'AnswerResult' does not exist in the current context
s1wj2dld.c0p(26,9): error CS0103: The name 'AnswerResult' does not exist in the current context
s1wj2dld.c0p(28,9): error CS0103: The name 'AnswerResult' does not exist in the current context
s1wj2dld.c0p(30,9): error CS0103: The name 'AnswerResult' does not exist in the current context
s1wj2dld.c0p(32,9): error CS0103: The name 'AnswerResult' does not exist in the current context

Not sure what is missing since the project has the proper references. Check out this video that shows me walking through this here: https://www.screencast.com/t/irmDwQTo

I have also enclosed the reporting file. Any help figuring out how to get this to work would be great!
PartialIndividualResults.zip

Followed @Include and @Layout wiki But Getting Exception

Target Framework is net48.
Here's the MWE :

using System;
using System.Collections.Generic;
using System.Linq;
using RazorEngineCore;

namespace mwe
{
    public static class RazorEngineCoreExtensions
    {
        public static RazorCompiledTemplate Compile(this IRazorEngine razorEngine, string template, IDictionary<string, string> parts)
        {
            return new RazorCompiledTemplate(
                    razorEngine.Compile<RazorTemplateBase>(template),
                    parts.ToDictionary(
                            k => k.Key,
                            v => razorEngine.Compile<RazorTemplateBase>(v.Value)));
        }
    }
    
    public class RazorTemplateBase: RazorEngineTemplateBase
    {
        public Func<string, object, string> IncludeCallback { get; set; }

        public Func<string> RenderBodyCallback { get; set; }
        public string Layout { get; set; }

        public string Include(string key, object model = null)
        {
            return this.IncludeCallback(key, model);
        }

        public string RenderBody()
        {
            return this.RenderBodyCallback();
        }
    }

    public class TestModel
    {
        public string Name{get; set;}

        public string Age{get; set;}

        public void Initialize()
        {
            Name = "name";
            Age = "age";
        }
    }

    public class RazorCompiledTemplate
    {
        private readonly IRazorEngineCompiledTemplate<RazorTemplateBase> compiledTemplate;
        private readonly Dictionary<string, IRazorEngineCompiledTemplate<RazorTemplateBase>> compiledParts;

        public RazorCompiledTemplate(IRazorEngineCompiledTemplate<RazorTemplateBase> compiledTemplate, Dictionary<string, IRazorEngineCompiledTemplate<RazorTemplateBase>> compiledParts)
        {
            this.compiledTemplate = compiledTemplate;
            this.compiledParts = compiledParts;
        }

        public string Run(object model)
        {
            return this.Run(this.compiledTemplate, model);
        }

        public string Run(IRazorEngineCompiledTemplate<RazorTemplateBase> template, object model)
        {
            RazorTemplateBase templateReference = null;

            string result = template.Run(instance =>
            {
                // if I comment out the following if clause, it works.
                if (!(model is AnonymousTypeWrapper))
                {
                    model = new AnonymousTypeWrapper(model);
                }

                instance.Model = model;
                instance.IncludeCallback = (key, includeModel) => this.Run(this.compiledParts[key], includeModel);

                templateReference = instance;
            });

            if (templateReference.Layout == null)
            {
                return result;
            }

            return this.compiledParts[templateReference.Layout].Run(instance =>
            {
                if (!(model is AnonymousTypeWrapper))
                {
                    model = new AnonymousTypeWrapper(model);
                }

                instance.Model = model;
                instance.IncludeCallback = (key, includeModel) => this.Run(this.compiledParts[key], includeModel);
                instance.RenderBodyCallback = () => result;
            });
        }
    }

    public class Program
    {
        static void Main(string[] args)
        {
            var model = new TestModel();
            var testpayload = @"

@inherits RazorEngineCore.RazorEngineTemplateBase<TestModel>
@{
    Model.Initialize();
}
    <b>@Model.Name</b>
";
            var engine = new RazorEngine();
            var compiled = engine.Compile(testpayload, new Dictionary<string, string>());

            var result = compiled.Run(model);
            Console.WriteLine(result);
            Console.ReadKey();
        }
    }
}

Here's the exception I get when I run this mwe:

D:\mwe> dotnet run .\Program.cs
Unhandled Exception: Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'RazorEngineCore.AnonymousTypeWrapper' does not contain a definition for 'Initialize'
   at CallSite.Target(Closure , CallSite , Object )
   at System.Dynamic.UpdateDelegates.UpdateAndExecuteVoid1[T0](CallSite site, T0 arg0)
   at TemplateNamespace.Template.<ExecuteAsync>d__0.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 RazorEngineCore.RazorEngineCompiledTemplate`1.<RunAsync>d__12.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 RazorEngineCore.RazorEngineCompiledTemplate`1.Run(Action`1 initializer)
   at mwe.RazorCompiledTemplate.Run(IRazorEngineCompiledTemplate`1 template, Object model) in D:\mwe\Program.cs:line 71
   at mwe.RazorCompiledTemplate.Run(Object model) in D:\mwe\Program.cs:line 64
   at mwe.Program.Main(String[] args) in D:\mwe\Program.cs:line 119

Any idea where I did it wrong? If I just fall back to the basic usage, it also works:

 var compiled = engine.Compile(testpayload);
 var result = compile.Run(model);
 Console.WriteLine(result);
 Console.ReadKey();

Partial Pages support

Hello,

We are using RazorEngineCore for our report templating needs (thank you for your time and effort!).

For our current scenario, I'd like to break out parts of a report into components. These components could then be shared by other reports.

Do you have a recommendation on how to achieve this?

Thanks!

assembly.GetType returning null, and "Could not load file or assembly RazorEngineCore"

I'm working on a PR that will add support for compiling multiple templates in one assembly, but I can't get any of the unit tests that involve running a template to run successfully. I get an exception like this:

Test method RazorEngineCore.Tests.TestCompileAndRun.TestCompileAndRun_HtmlLiteral threw exception: 
System.ArgumentNullException: Value cannot be null. (Parameter 'type')
    at System.Activator.CreateInstance(Type type, Boolean nonPublic, Boolean wrapExceptions)
   at System.Activator.CreateInstance(Type type)
   at RazorEngineCore.RazorEngineCompiledTemplate.RunAsync(Object model)

It seems like the issue is with line 18 of RazorEngineCompiledTemplate.cs:

this.templateType = assembly.GetType("TemplateNamespace.Template");

The call to GetType doesn't throw an exception, but it returns null. If I use the debugger to look at the DefinedTypes property of assembly, I get this exception:

System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types.
Could not load file or assembly 'RazorEngineCore, Version=2020.6.1.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

Any idea why I'm getting this error?

Layout not working

Following the example from the wiki regarding layouts, (which stemmed from this issue) it doesn't compile. This line:

MyCompiledTemplate compiledTemplate = razorEngine.Compile(template, parts);

results in this compilation error:

Argument 2: cannot convert from System.Collections.Generic.IDictionary<string, string>' to 'System.Action<RazorEngineCore.IRazorEngineCompilationOptionsBuilder>'

I've tried looking into the IRazorEngineCompilationOptionsBuilder for a feature to specify layouts, but I don't see anything. Has this feature been removed?

Can't get extension methods to work

Hello! I am coming across an issue where extension methods are not being identified properly. In my sample below, I am trying to use LINQ's single, and the error is:

'System.Collections.Generic.List' does not contain a definition for 'First'

I've added the required assemblies using AddAssemblyReferenceByName() and assume it would load correctly. Yet I'm still getting the error.

When I call the extension method fully qualified, it works. ie, calling System.Linq.First(myList) instead of myList.Single().

Any guidance would be greatly appreciated!

Sample code:

class Program
{
    static string Content = @"
        Hello @Model.Name

        First item: @Model.Items.First();

        @foreach(var item in @Model.Items)
        {
            <div>- @item</div>
        }

        <div data-name=""@Model.Name""></div>

        <area>
            @{ RecursionTest(3); }
        </area>

        @{
            void RecursionTest(int level){
                if (level <= 0)
                {
                    return;
                }
                    
                <div>LEVEL: @level</div>
                @{ RecursionTest(level - 1); }
            }
        }";

    static void Main(string[] args)
    {
        IRazorEngine razorEngine = new RazorEngine();
        IRazorEngineCompiledTemplate template = razorEngine.Compile(Content,
            builder =>
            {
                builder.AddAssemblyReferenceByName("System.Collections");
                builder.AddAssemblyReferenceByName("System.Linq");
            });

        string result = template.Run(new
        {
                Name = "Alexander",
                Items = new List<string>()
                {
                        "item 1",
                        "item 2"
                }
        });

        Console.WriteLine(result);
        Console.ReadKey();
    }
}

The type 'List<>' is defined in an assembly that is not referenced. You must add a reference to assembly 'System.Collections,

        public string GenerateTemplate(XYZ Model, string templateName)
        {
            string templateText = ReadTemplate(templateName);

            IRazorEngineCompiledTemplate<RazorEngineTemplateBase<XYZ>> template = 
                _razorEngine.Compile<RazorEngineTemplateBase<XYZ>> (templateText);

            string result = template.Run(instance =>
            {
                instance.Model = Model;
            });

            return result;

        }

Hello, worked fine with normal models, but with this XYZ model, it is not working and showing me the following error:
RazorEngineCore.RazorEngineCompilationException
HResult=0x80131500
Source=RazorEngineCore
StackTrace:
at RazorEngineCore.RazorEngine.CreateAndCompileToStream(String templateSource, RazorEngineCompilationOptions options)
at RazorEngineCore.RazorEngine.Compile[T](String content, Action`1 builderAction)
at RazorEngineHelper.GenerateTemplate(XYZ Model, String templateName) in C:...\RazorEngineHelper.cs:line 27

Thank you.

Is this right?

IRazorEngine razorEngine = new RazorEngine(); IRazorEngineCompiledTemplate<RazorEngineTemplateBase<DDLTable>> template = razorEngine.Compile<RazorEngineTemplateBase<DDLTable>>(templateContent, builder => { builder.AddAssemblyReferenceByName("System.Collections"); });

@for (var i = 0; i < @Model.Columns.Count; i++){
  var [email protected][i];
  Name: @col2.Name 
}

RazorEngineCore.RazorEngineCompilationException : Unable to compile template: mnoilfrp.af3(21,19): error CS1002: ; expected

But:

@for (var i = 0; i < @Model.Columns.Count; i++){
  var [email protected][i];
  <p>Name: @col2.Name</p> 
}

Name: owner_code

Name: company_name_cn

Name: booking_no

Name: license

All errors produce same warning message

To reporoduce, add Microsoft.AspNetCore.Mvc.ViewFeatures and RazorEngineCore.Extensions assemblies and compile using RazorEngineCorePageModel from RazorEngin Extensyions project:

var compiledTemplateLocal = razorEngine.Compile<RazorEngineCorePageModel<TModel>>(template, builder =>
                    {
builder.AddAssemblyReference(typeof(RazorEngineCorePageModel));
builder.AddAssemblyReference(typeof(ITempDataDictionary));
});

Observed:

compilation produces warning:

Warning CS1701: Assuming assembly reference 'Microsoft.AspNetCore.Mvc.ViewFeatures, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' used by 'Eeva' matches identity 'Microsoft.AspNetCore.Mvc.ViewFeatures, Version=5.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60' of 'Microsoft.AspNetCore.Mvc.ViewFeatures', you may need to supply runtime policy

Version 5.0.0.0 of Microsoft.AspNetCore.Mvc.ViewFeatures assembly does not exist. Latest is 2.2.0.0

RazorEngine assigns first message from compiler message list to exception Message property. So every compilation exception returns this same warning message.

Issue with including variables within cshtml attributes

        RazorEngine razorEngine = new RazorEngine();
        RazorEngineCompiledTemplate template = razorEngine.Compile("<div class=\"circle\" style=\"background-color: hsla(@Model.Colour, 70%, 80%, 1);\">");

        string actual = template.Run(new
        {
            Colour = 88
        });

actual is incorrectly generated as:

<div class="circle" style="background-color:" style="hsla(" style="88" style="," style="70" style="%," style="80" style="%," style="1);">

Clode blocks appear in output as plain text

To reproduce, add code block to template like

@{
var test=1;
}

Works as expected.
This will appear in result as plain text.

How to run code blocks like in real Razor ?

Using

@if (true) {
var test=1;
}

How can I use LINQ

I have model with IEnumerable and need sort collection in Razor.

   public class TestModel: RazorEngineTemplateBase
   {
       public string Name { get; set; }
       public IEnumerable<int> Items { get; set; }
   }

var content = @"
@using System.Collections;
@using System.Collections.Generic;
@using System.Linq;

Hello @Name
@{ var  ordered = System.Linq.Enumerable.OrderByDescending(Items, x=>x.Order);
    @foreach (var item in ordered)
           {
              <p>@item</p>                  
           }
}
";
           RazorEngineCompiledTemplate<TestModel> template = razorEngine.Compile<TestModel>(content);

           string result = template.Run(instance =>
           {
               instance.Name = "Alexander";
               instance.Items = new List<int>() {5,2,9,1,7};
           });

Unable to compile template: 4i13fl12.2ad(8,19): error CS1069: The type name 'Enumerable' could not be found in the namespace 'System.Linq'. This type has been forwarded to assembly 'System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' Consider adding a reference to that assembly.

I also tried to call OrderBy on model
var ordered = Items.OrderByDescending(x=>x);

Unable to compile template: 0xdlwlef.t31(9,22): error CS1061: 'IEnumerable' does not contain a definition for 'OrderByDescending' and no accessible extension method 'OrderByDescending' accepting a first argument of type 'IEnumerable' could be found (are you missing a using directive or an assembly reference?)

Raw

Is there a way of causing RazorEngineCore to output a raw string within a template? Full fat razor does so using @Html.Raw().

Update referenced NuGet packages to newer versions

Hi, would it be possible to update the NuGet packages RazorEngineCore uses? The ones currently in the latest release are quite out of date.

For instance, Microsoft.AspNetCore.Razor.Language is at 5.0.2 at this time.

Please add StrongName support

Warning CS8002 Referenced assembly 'RazorEngineCore, Version=2021.3.1.0, Culture=neutral, PublicKeyToken=null' does not have a strong name.

Not a big deal but annoying without it. Thanks.

Microsoft.AspNetCore.Razor.Language Version=3.1.1.0

image

Hi there.
Trying to use your lib in my project with Azure Function.
I am getting the next issue that I mentioned above.

In the output window, it says "Exception thrown: 'System.IO.FileNotFoundException' in RazorEngineCore.dll", but actually my template exists...

image

I tried to install such Microsoft.AspNetCore.Razor.Language Version=3.1.1 in the project directly, but it still says the same.

Any thoughts?

Issues with .NET Standard reference on Linux starting with 2020.9.1

After updating to version 2020.9.1, I get the following exception when rendering templates:

RazorEngineCore.RazorEngineCompilationException: Unable to compile template: (28,29): error CS0012: The type 'Object' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'.
at RazorEngineCore.RazorEngine.CreateAndCompileToStream(String templateSource, RazorEngineCompilationOptions options)
at RazorEngineCore.RazorEngine.Compile[T](String content, Action`1 builderAction)

This happens on Linux only (see this build), the same logic works on Windows as expected (with identical SDK versions etc.).

Do you have an idea how to overcome this issue? I tried to tweak the assembly references, but I suspect the compilation process of the template is missing some .NET Standard reference.

Extending RazorEngineCore

@adoconnection

Can you have a look at this commit on my (working) fork of RazorEngineCore

wdcossey@4751912

This will have some breaking changes for Strongly typed model
The only actual breaking change is you will always have to use @Model. when using RazorEngineTemplateBase<T>

for example

string content = @"Hello @A, @B, @Decorator(123)";

will have to be rewritten as:

string content = @"Hello @Model.A, @Model.B, @Model.Decorator(123)";

which will behave like real Razor PageModel.

These changes will greatly improve the ability to extend RazorEngineCore with the use of the Interfaces (that are also in the branch).

My company is shifting to .Net Core from RazorEngine (for .Net Framework) and I need to extend RazorEngineCore rather than creating another private fork.

If you have time, pull that branch have a look at the code and templates.

Problems with run template

Hi,

Since i'm porting my .net framework project to .net Core 5.0 there are some issues with the razorengine.

In the project we are using the Extent reporting library that uses the razor engine.

When i try to run the compiled template this error occurs:
System.InvalidCastException: 'Unable to cast object of type 'TemplateNamespace.Template' to type 'RazorEngineCore.IRazorEngineTemplate'.'

sample code to reproduce error:

string content = @"Hello";

IRazorEngine razorEngine = new RazorEngineCore.RazorEngine();
IRazorEngineCompiledTemplate compiledTemplate = razorEngine.Compile(content);
 string result = compiledTemplate.Run(new { name = "Hello2" });

The same error occurs in the Extent library at:

Report = new AventStack.ExtentReports.ExtentReports();
Report.AttachReporter(htmlReporter);
Report.Flush();

ProjectFile:

  <PropertyGroup>
    <TargetFramework>net5.0-windows</TargetFramework>
	  <SkipMicrosoftUIXamlCheckTargetPlatformVersion>true</SkipMicrosoftUIXamlCheckTargetPlatformVersion>
	  <UseWindowsForms>true</UseWindowsForms>
    <IsPackable>false</IsPackable>
    <Platforms>AnyCPU;x64</Platforms>
    <ApplicationIcon />
    <OutputType>Library</OutputType>
	  <ProduceReferenceAssembly>false</ProduceReferenceAssembly>
    <StartupObject />
  </PropertyGroup>

<PackageReference Include="RazorEngine.NetCore" Version="3.1.0" />

Do you have any idea's to bypass the problem?
Anyway thanks for looking at the issue.

在 .net Framework 4.7 的winfrom程序下运行报错

public class RazorEngineCompilationOptions { public HashSet<Assembly> ReferencedAssemblies { get; set; } = new HashSet<Assembly>() { typeof(object).Assembly, Assembly.Load(new AssemblyName("Microsoft.CSharp")), typeof(RazorEngineTemplateBase).Assembly, Assembly.Load(new AssemblyName("System.Runtime")), Assembly.Load(new AssemblyName("System.Linq")), Assembly.Load(new AssemblyName("System.Linq.Expressions")) }; ....... }

err info :System.IO.FileNotFoundException:“未能加载文件或程序集“Microsoft.CSharp”或它的某一个依赖项。系统找不到指定的文件。”

已经在引用中添加了 Microsoft.CSharp,System.Runtime,System.Linq,System.Linq.Expressions 等包 依旧报错

Cacheing

We are currently using RazorEngine like this:

if (Engine.Razor.IsTemplateCached(TemplateName, typeof(BaseEmailModel)))
{
    parsedContent = Engine.Razor.Run(TemplateName, typeof(BaseEmailModel), model);
}
else
{
    var viewPath = Path.Combine(Statics.EmailTemplatesPath, $"{TemplateName}.cshtml");
    var viewContent = ReadTemplateContent(viewPath);
    parsedContent = Engine.Razor.RunCompile(viewContent, TemplateName, null, model);
}

if I use your suggested static cacheing how do I perform a similar test in order to get things moving on?

RazorEngineCore.RazorEngine.Compile not work when publish to single file

target framework is .net5
when i publish exe to single file ,compile a templeate ,get this error:
System.ArgumentException: Empty path name is not legal. (Parameter 'path')
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options)
at System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
at System.IO.File.OpenRead(String path)
at Roslyn.Utilities.FileUtilities.OpenFileStream(String path)
at Microsoft.CodeAnalysis.MetadataReference.CreateFromFile(String path, MetadataReferenceProperties properties, DocumentationProvider documentation)
at RazorEngineCore.RazorEngine.<>c.b__4_1(Assembly ass)
at System.Linq.Enumerable.SelectEnumerableIterator2.MoveNext() at System.Collections.Generic.List1.InsertRange(Int32 index, IEnumerable1 collection) at System.Collections.Generic.List1.AddRange(IEnumerable1 collection) at System.Linq.Enumerable.ConcatIterator1.ToList()
at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at RazorEngineCore.RazorEngine.CreateAndCompileToStream(String templateSource, RazorEngineCompilationOptions options) at RazorEngineCore.RazorEngine.Compile(String content, Action1 builderAction)

if not single file , it ok

-p:PublishTrimmed=true and Microsoft.CSharp assembly.

The "-p:PublicTrimmed=true" option causes an error that the Microsoft.CSharp assembly cannot be found.

The full command to publish executable is as follows:

"C:\Program Files\dotnet\dotnet.exe" publish -c Release -r win-x64 --self-contained true -p:PublishReadyToRun=false -p:PublishSingleFile=true -p:PublishTrimmed=true -p:IncludeNativeLibrariesForSelfExtract=true -o publish\release\win-x64

The error that occurs is as follows:

System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.CSharp, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.

File name: 'Microsoft.CSharp, Culture=neutral, PublicKeyToken=null'
at System.Reflection.RuntimeAssembly.InternalLoad(ObjectHandleOnStack assemblyName, ObjectHandleOnStack requestingAssembly, StackCrawlMarkHandle stackMark, Boolean throwOnFileNotFound, ObjectHandleOnStack assemblyLoadContext, ObjectHandleOnStack retAssembly)
at System.Reflection.RuntimeAssembly.InternalLoad(AssemblyName assemblyName, RuntimeAssembly requestingAssembly, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, AssemblyLoadContext assemblyLoadContext)
at System.Reflection.Assembly.Load(AssemblyName assemblyRef)
at RazorEngineCore.RazorEngineCompilationOptions..ctor()
at RazorEngineCore.RazorEngineCompilationOptionsBuilder..ctor(RazorEngineCompilationOptions options)
at RazorEngineCore.RazorEngine.Compile(String content, Action`1 builderAction)

If I do not use the "-p:PublicTrimmed=true" option, errors will not occur and work well. However, if I do not use the "-p:PublicTrimmed=true" option, the executable size will increase from 50MB to 80MB.

Async template writing not supported

@Html.PartialAsync in template causes error.

How to add something like

        protected async Task<IHtmlstring> PartialAsync<T>(string viewName, T model)
        {
            // http://stackoverflow.com/questions/483091/render-a-view-as-a-string
            ViewData.Model = model;
            using (var sw = new StringWriter())
            {
                var viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
                var viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
                viewResult.View.Render(viewContext, sw);
                viewResult.ViewEngine.ReleaseView(ControllerContext, viewResult.View);
                return new Htmlstring  (sw.GetStringBuilder().ToString());
            }
        }

to Template base class so @Html.PartialAsync or partial tag helper can used. Unfortunately, async template writing is not supported.

Nullables treated as non-nullable at runtime

My model includes a DateTime? property

public class CampaignDesignerRequest
{
     //...
     public DateTime? CampaignStartDate { get; set; }
     //...
}

My view inherits the model

@inherits RazorEngineCore.RazorEngineTemplateBase<Fourstarzz.Accessors.ReportTemplates.Models.DesignedCampaign_RenderModel>

At write time, the intellisense recognizes CampaignStartDate as a nullable and shows an error hint if I try to run date string formatting without specifying .Value

Model.CampaignStartDate.Value.ToShortDateString()

However when I run the code, it gives me the error

Microsoft.CSharp.RuntimeBinder.RuntimeBinderException : 'System.DateTime' does not contain a definition for 'Value'

I've tested the same on other value types, like int and double, and get the same kind of error.

Versions

  • RazoreEngineCore 2020.9.1
  • .NET framework 4.8.

Any thoughts on potential causes?

Does "@addTagHelper" supported ?

Does "@addTagHelper" supported ?Thanks!

            IRazorEngineCompiledTemplate<RazorEngineTemplateBase<JavaMapperConfig>> template
                = razorEngine.Compile<RazorEngineTemplateBase<JavaMapperConfig>>(templateContent, builder =>
                {
                    builder.AddAssemblyReferenceByName("System.Collections");
                    builder.AddAssemblyReference(typeof(CodeUtil)); // by type
                    builder.AddAssemblyReference(typeof(ReverseStrTagHelper)); // by type
                });

how build C# code

it's not support generate C# code ?
how can generate code file for project as like as winform's design.cs

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.