Skip to content

RazorEngine.NetFramework 4.1.0

Choose a tag to compare

@github-actions github-actions released this 28 Oct 23:56
· 58 commits to master since this release
af46871

4.1.0 switches templates to a modern C# compiler and removes the APIs that were obsolete since 3.5, as well as VB.NET templates.
Unchanged: the template syntax (Razor 3, Microsoft.AspNet.Razor 3.3.0), the namespaces, the assembly name RazorEngine.NetFramework.dll and its signing key, and .NET Framework 4.8.
Read the breaking changes below before updating; doc/Upgrading.md has the migration steps.

Highlights

  • (NEW) Modern C# in templates. Roslyn (Microsoft.CodeAnalysis.CSharp) is updated from 1.3.2 to 5.6.0 and is now the default compiler. Templates can use C# up to C# 14 instead of C# 5: string interpolation, ?., nameof, tuples and deconstruction, pattern matching, switch expressions and more. For example:

    <p>@($"Hello {Model.Name}!")</p>
    <p>@(Model.Nickname?.ToUpper() ?? "no nickname")</p>
    @{ var text = Model.Age switch { >= 18 => "adult", _ => "child" }; }
    <p>@text</p>
  • (NEW) Fewer dependencies. The package now only depends on Microsoft.AspNet.Razor 3.3.0 and Microsoft.CodeAnalysis.CSharp 5.6.0. The pins of System.Collections.Immutable 1.3.1, System.Reflection.Metadata 1.4.2 and System.Security.Cryptography.X509Certificates 4.3.2, which only existed for the old Roslyn, are gone.

Breaking changes

  • (BREAKING) Roslyn is the default compiler. DefaultCompilerServiceFactory now compiles templates in-process with Roslyn instead of starting csc.exe through CodeDom.

    • Templates are still compiled optimized and with the RAZORENGINE preprocessor symbol, as with CodeDom, so #if RAZORENGINE keeps working.

    • The first compile in a process (or AppDomain) takes longer, because Roslyn is loaded and JIT-compiled there once: about 2 s instead of about 0.2 s with CodeDom. Later compiles do not start a separate csc.exe process and are faster (in a benchmark about 40 ms instead of about 85 ms; 4.2.0 brings this down to about 26 ms). From about 30 templates per process on, Roslyn is faster overall.

    • Roslyn runs inside the process: it needs about 55 MB more memory per process, and per AppDomain of IsolatedRazorEngineService.

    • Debugging: with Roslyn, Debug = true does not let you step into templates with the debugger.

    • To keep the old compiler (C# 5, csc.exe), for example for debugging, use the new CodeDomCompilerServiceFactory:

      config.CompilerServiceFactory = new RazorEngine.Compilation.CodeDomCompilerServiceFactory();

      or in the configuration file: <razorEngine compilerServiceFactoryType="RazorEngine.Compilation.CodeDomCompilerServiceFactory, RazorEngine.NetFramework">.

    • RoslynCompilerServiceFactory still exists and now does the same as DefaultCompilerServiceFactory.

  • (BREAKING) C# 14 can change the meaning of existing template code. Templates were compiled as C# 5 before and are compiled with the newest C# version now. Code that compiles with both usually behaves the same, with one known exception that does not cause a compile error:

    • Since C# 14, field inside a property accessor is the property's backing field. A template that declares its own member named field (for example in @functions) and returns it from a property accessor now gets the backing field instead (for example null).
    • Rename the member, or, from 4.2.0 on, pin LanguageVersion.CSharp13 (see 4.2.0), or keep the CodeDom compiler.
    • Roslyn lists all C# breaking changes in https://github.com/dotnet/roslyn/tree/main/docs/compilers/CSharp.
  • (BREAKING) Binding redirects for Roslyn's dependencies. Roslyn 5.6.0 brings newer System.* assemblies (System.Collections.Immutable 10, System.Reflection.Metadata 10, System.Memory and others). .NET Framework applications need binding redirects for them:

    • SDK-style projects generate them automatically (AutoGenerateBindingRedirects).

    • For packages.config projects, NuGet adds them to app.config/web.config on install. Check that existing, hand-written redirects for these assemblies point to the new versions.

    • A FileLoadException for one of these assemblies at the first template compile means a binding redirect is missing.

    • Custom AppDomains for IsolatedRazorEngineService need the application's configuration file, otherwise the redirects do not apply there. IsolatedRazorEngineService.Create() already does this; for your own domains set it yourself:

      var setup = new AppDomainSetup
      {
          ApplicationBase = AppDomain.CurrentDomain.SetupInformation.ApplicationBase,
          ConfigurationFile = AppDomain.CurrentDomain.SetupInformation.ConfigurationFile
      };
      var service = IsolatedRazorEngineService.Create(() => AppDomain.CreateDomain("Templates", null, setup));
  • (BREAKING) Legacy API removed (obsolete since 3.5). Replacements:

    Removed Use instead
    Razor.Parse(template, model, name) Engine.Razor.RunCompile(template, name, null, model)
    Razor.Compile(template, modelType, name) Engine.Razor.Compile(template, name, modelType)
    Razor.Run(name, model) Engine.Razor.Run(name, null, model)
    TemplateService, ITemplateService RazorEngineService.Create(config), IRazorEngineService
    IsolatedTemplateService IsolatedRazorEngineService.Create(...)
    ITemplate.TemplateService, TemplateBase.TemplateService TemplateBase.Razor
    Parallel query plans (IParallelQueryPlan, ...) your own Parallel.ForEach/PLINQ around Run

    The RunCompile/Compile/Run overloads with a template string are extension methods in RazorEngine.Templating.

  • (BREAKING) Template resolvers removed (obsolete since 3.5). Template managers replace them:

    Removed Use instead
    ITemplateResolver, DelegateTemplateResolver ITemplateManager, e.g. DelegateTemplateManager, ResolvePathTemplateManager, EmbeddedResourceTemplateManager
    config.Resolver config.TemplateManager
    ResolveUsing(ITemplateResolver), ResolveUsing<TResolver>() ManageUsing(...), ManageUsing<TManager>() (ResolveUsing(Func<string, string>) stays)
    templateResolverType="..." in the configuration file templateManagerType="..."
    WrapperTemplateManager an ITemplateManager implementation

    A configuration file that still sets templateResolverType now fails to load with a ConfigurationErrorsException instead of being ignored.

  • (BREAKING) Code inspectors removed (obsolete since 3.5): ICodeInspector, the CodeInspectors properties of the compiler service and the configurations, AddInspector and Inspect(). There is no replacement. They were no security boundary either: templates must come from trusted sources.

  • (BREAKING) APIs announced for removal in 4.0 removed:

    • TemplateCompilationException.Errors: use CompilerErrors.
    • ICompilerService.IncludeAssemblies() and CompilerServiceBase.IncludeAssemblies(): use IncludeReferences().
    • The ExecuteContext(DynamicViewBag) constructor: it always threw; pass the view bag to Run/RunCompile instead.
    • The public TypeHash constructors of the embedded Impromptu code: use TypeHash.Create.
  • (BREAKING) VB.NET templates removed. Removed are Language.VisualBasic, the RazorEngine.Compilation.VisualBasic compiler services, CompilerServicesUtility.ResolveVBTypeName/VBGetRawTypeName/VBCreateGenericType, the VB parser in RazorEngineHost and the .vbhtml lookup of ResolvePathTemplateManager.

    • Templates are always C#. Convert .vbhtml templates to .cshtml.
    • A configuration file with language="VisualBasic" or defaultLanguage="VisualBasic" fails to load.
    • VB.NET applications can still use RazorEngine with C# templates and pass their own (also anonymous) objects as models.

Fixes

  • (BUGFIX) The Roslyn compiler service now prepares the generated code like the CodeDom one. Before, with Roslyn, base template types with constructor parameters failed to compile, dynamic models were not marked, and #line hidden was not removed for debugging.
  • (BUGFIX) The Roslyn compiler service now compiles optimized and defines RAZORENGINE, like CodeDom always did.

Build and tests

  • (BUILD) New tests check that both compilers optimize and define RAZORENGINE, compile modern C# (C# 6 to 8 samples) with Roslyn, and keep the CodeDom fallback tested.
  • (BUILD) The release workflow publishes tagged versions to nuget.org with trusted publishing (introduced for 4.0.0).
  • (PACKAGING) The copyright notice of the package and the assembly keeps the original project's notice and adds the fork's: Copyright © 2011-2017 RazorEngine Project, © 2026 RazorEngine.NetFramework contributors.

NuGet: https://www.nuget.org/packages/RazorEngine.NetFramework/4.1.0