Razorlight: The name 'section' does not exist in the current context in .net core 3

Created on 8 Jan 2020  Â·  28Comments  Â·  Source: toddams/RazorLight

Describe the bug
Since upgrading to the latest version of Razorlight official release (I was using unofficial before) I am experience the issue that sections aren't working anymore. I keep getting the error: The name 'section' does not exist in the current context.

To Reproduce
I am working on a unit test which coverage this breakage

Expected behavior

Information (please complete the following information):

  • OS: Ubuntu
  • Platform .net Core 3.0
  • RazorLight version 2.0-beta4
  • Are you using the OFFICIAL RazorLight package? Yes
  • Visual Studio version I am using Rider 2019.3

Additional context
I had to upgrade from the unofficial package to the official beta 4 because it has net core 3 support before I was using the .net core 2.2 which worked happilly

Investigate bug help wanted

Most helpful comment

Thanks for your efforts on this project.

Just wondering if there has there been any progress on this issue? Seems can't use RazorLight version 2.0-beta4 in .net core 3.1 if you define a @section ?

All 28 comments

THanks for writing a unit test. Feel free to push it as a PR. I am OK with failing tests.

I'm experiencing the same issue in .Net. Core 3.1 console application.

OS: Windows 10
Platform .net Core 3.1
RazorLight version 2.0-beta4
Are you using the OFFICIAL RazorLight package? Yes
Visual Studio version I am using: 16.4.2

Seems that SectionDirective is not registered by default in RazorEngine.Features collection.

Issue can be easily reproduced when running Samples.EntityFrameworkProject under Net.Core 3.0.
Just update template entities:

           dbContext.Templates.Add(new TemplateEntity()
            {
                Id = 1,
                Content = @"
                    <html>
                        @RenderSection(""TMP"")
                        @RenderBody()
                    </html>"
            });

            dbContext.Templates.Add(new TemplateEntity()
            {
                Id = 2,
                Content = @"
                    @model Samples.EntityFrameworkProject.TestViewModel
                    @{
                        Layout = 1.ToString(); //This is an ID of your layout in database
                     }
                     @section TMP {
                            <h2>TMP</h2>
                      }
                    <body> Hello, my name is @Model.Name and I am @Model.Age </body>"
            });

Yes, that's true. I sorry forgot to make the PR. I have been a bit distract with work stuff.

I have added a bunch of tests to cover my personal common cases that I use Razorlight for, see pull request #309

Any idea for a workaround? We use a lot of section tags.

My workaround was to get rid of the sections :(

Sent from my iPhone

On 23 Jan 2020, at 17:24, Aaron notifications@github.com wrote:


Any idea for a workaround? We use a lot of section tags.

—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub, or unsubscribe.

My workaround was to get rid of the sections :(
…
Sent from my iPhone
On 23 Jan 2020, at 17:24, Aaron @.*> wrote:  Any idea for a workaround? We use a lot of section tags. — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.

Refactored our code to remove @sections and working for us too.

@ADNewsom09 You refactored a lot of section tags in 2 hours and 30 minutes? You must be really fast typer!

I plan to sort through this stuff. I just have vacation coming up Feb 1-9 so trying to get my projects done before then. As always, this is unpaid time, so if it's not a pain point for me, it's not urgent.

I had separately reached out to the maintainer of the Snapper library so PR #309 could advance forward.

@ADNewsom09 You refactored a lot of section tags in 2 hours and 30 minutes? You must be really fast typer!

lol thanks, apparently the person that wrote the templates used them all over but they weren't using them to do much. A quick script to just remove the text "@section XXXXX {" and the corresponding "}" throughout the app got my proof of concept dot net core 3.1 branch working.

I have a workaround for this.
First, you creating custom engine builder:

CustomRazorLightEngineBuilder

public class CustomRazorLightEngineBuilder : RazorLightEngineBuilder
    {
        public override RazorLightEngine Build()
        {
            var options = new RazorLightOptions();

            if (namespaces != null)
            {
                options.Namespaces = namespaces;
            }

            if (dynamicTemplates != null)
            {
                options.DynamicTemplates = dynamicTemplates;
            }

            if (metadataReferences != null)
            {
                options.AdditionalMetadataReferences = metadataReferences;
            }

            if (excludedAssemblies != null)
            {
                options.ExcludedAssemblies = excludedAssemblies;
            }

            if (prerenderCallbacks != null)
            {
                options.PreRenderCallbacks = prerenderCallbacks;
            }

            if (cachingProvider != null)
            {
                options.CachingProvider = cachingProvider;
            }

            //options.DisableEncoding = disableEncoding;


            var metadataReferenceManager = new DefaultMetadataReferenceManager(options.AdditionalMetadataReferences, options.ExcludedAssemblies);
            var assembly = operatingAssembly ?? Assembly.GetEntryAssembly();
            var compiler = new RoslynCompilationService(metadataReferenceManager, assembly);

            var sourceGenerator = new RazorSourceGenerator(CustomRazorEngine.Instance, project, options.Namespaces);
            var templateCompiler = new RazorTemplateCompiler(sourceGenerator, compiler, project, options);
            var templateFactoryProvider = new TemplateFactoryProvider();

            var engineHandler = new EngineHandler(options, templateCompiler, templateFactoryProvider, cachingProvider);

            return new RazorLightEngine(engineHandler);
        }
    }

Second, you copy DefaultRazorEngine to your code and change Instance field implementation to this:

CustomRazorEngine


public static RazorEngine Instance
        {
            get
            {
                var configuration = RazorConfiguration.Default;
                var razorProjectEngine = RazorProjectEngine.Create(configuration, new NullRazorProjectFileSystem(), builder =>
                {
                    RazorLight.Instrumentation.InjectDirective.Register(builder);
                    RazorLight.Instrumentation.ModelDirective.Register(builder);

                    //In RazorLanguageVersion > 3.0 (at least netcore 3.0) the directives are registed out of the box.
                    if (!RazorLanguageVersion.TryParse("3.0", out var razorLanguageVersion)
                        || configuration.LanguageVersion.CompareTo(razorLanguageVersion) < 0)
                    {
                        NamespaceDirective.Register(builder);
                        FunctionsDirective.Register(builder);
                        InheritsDirective.Register(builder);
                        SectionDirective.Register(builder);
                    }
                    var sectionDirective = builder.Features.OfType<SectionDirectivePass>().FirstOrDefault();
                    if (sectionDirective == null)
                    {
                        SectionDirective.Register(builder);
                    }

                    builder.Features.Add(new ModelExpressionPass());
                    builder.Features.Add(new RazorLightTemplateDocumentClassifierPass());
                    builder.Features.Add(new RazorLightAssemblyAttributeInjectionPass());
                   \\#if NETSTANDARD2_0
           builder.Features.Add(new InstrumentationPass());
                   \\#endif
                    //builder.Features.Add(new ViewComponentTagHelperPass());

                    builder.AddTargetExtension(new Microsoft.AspNetCore.Razor.Language.Extensions.TemplateTargetExtension()
                    {
                        TemplateTypeName = "global::RazorLight.Razor.RazorLightHelperResult",
                    });

                    OverrideRuntimeNodeWriterTemplateTypeNamePhase.Register(builder);
                });

                return razorProjectEngine.Engine;
            }
        }

Note the following piece of code:

var sectionDirective = builder.Features.OfType<SectionDirectivePass>().FirstOrDefault();
if (sectionDirective == null)
{
    SectionDirective.Register(builder);
}

And you also have to copy OverrideRuntimeNodeWriterTemplateTypeNamePhase to your project.

Now you can use CustomRazorLightEngineBuilder that will produce correct engine setup.

@VadimBurshtyn That is a strange fix. It implies the statement directly above it is wrong.

I'm not sure i'm following you. I'm not saying this is a fix, otherwise i'd create a PR. This is a workaround.

Look at this code, in sequence:

```c#
//In RazorLanguageVersion > 3.0 (at least netcore 3.0) the directives are registed out of the box.
if (!RazorLanguageVersion.TryParse("3.0", out var razorLanguageVersion)
|| configuration.LanguageVersion.CompareTo(razorLanguageVersion) < 0)
{
NamespaceDirective.Register(builder);
FunctionsDirective.Register(builder);
InheritsDirective.Register(builder);
SectionDirective.Register(builder);
}

                var sectionDirective = builder.Features.OfType<SectionDirectivePass>().FirstOrDefault();
                if (sectionDirective == null)
                // the only reason this would be null is if SectionDirective.Register(builder) above never gets hit
                {
                    SectionDirective.Register(builder);
                }

```

There is a list of registered features before any modifications:
Features:
Microsoft.AspNetCore.Razor.Language.DefaultImportProjectFeature
Microsoft.AspNetCore.Razor.Language.DefaultRazorDirectiveFeature
Microsoft.AspNetCore.Razor.Language.Extensions.DefaultMetadataIdentifierFeature
Microsoft.AspNetCore.Razor.Language.DefaultRazorParserOptionsFactoryProjectFeature
Microsoft.AspNetCore.Razor.Language.DefaultRazorCodeGenerationOptionsFactoryProjectFeature
Microsoft.AspNetCore.Razor.Language.DefaultRazorParserOptionsFeature
Microsoft.AspNetCore.Razor.Language.DefaultRazorCodeGenerationOptionsFeature
Microsoft.AspNetCore.Razor.Language.DefaultDirectiveSyntaxTreePass
Microsoft.AspNetCore.Razor.Language.HtmlNodeOptimizationPass
Microsoft.AspNetCore.Razor.Language.DefaultDocumentClassifierPass
Microsoft.AspNetCore.Razor.Language.Extensions.MetadataAttributePass
Microsoft.AspNetCore.Razor.Language.Extensions.DesignTimeDirectivePass
Microsoft.AspNetCore.Razor.Language.DirectiveRemovalOptimizationPass
Microsoft.AspNetCore.Razor.Language.Extensions.DefaultTagHelperOptimizationPass
Microsoft.AspNetCore.Razor.Language.Extensions.PreallocatedTagHelperAttributeOptimizationPass
Microsoft.AspNetCore.Razor.Language.Extensions.EliminateMethodBodyPass
Microsoft.AspNetCore.Razor.Language.DefaultRazorTargetExtensionFeature
Microsoft.AspNetCore.Razor.Language.DefaultDocumentClassifierPassFeature
Microsoft.AspNetCore.Razor.Language.Extensions.FunctionsDirectivePass
Microsoft.AspNetCore.Razor.Language.Extensions.ImplementsDirectivePass
Microsoft.AspNetCore.Razor.Language.Extensions.InheritsDirectivePass
Microsoft.AspNetCore.Razor.Language.Extensions.AttributeDirectivePass
Microsoft.AspNetCore.Razor.Language.Components.ComponentImportProjectFeature
Microsoft.AspNetCore.Razor.Language.Components.ComponentInjectDirectivePass
Microsoft.AspNetCore.Razor.Language.Components.ComponentLayoutDirectivePass
Microsoft.AspNetCore.Razor.Language.Components.ComponentPageDirectivePass
Microsoft.AspNetCore.Razor.Language.Components.ComponentDocumentClassifierPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentWhitespacePass
Microsoft.AspNetCore.Razor.Language.Components.ComponentComplexAttributeContentPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentLoweringPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentScriptTagPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentEventHandlerLoweringPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentKeyLoweringPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentReferenceCaptureLoweringPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentSplatLoweringPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentBindLoweringPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentTemplateDiagnosticPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentGenericTypePass
Microsoft.AspNetCore.Razor.Language.Components.ComponentChildContentDiagnosticPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentMarkupDiagnosticPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentMarkupBlockPass
Microsoft.AspNetCore.Razor.Language.Components.ComponentMarkupEncodingPass

I'm targeting test console app to NetCore 3.1. Seems defaults have changed.

I think the problem is:

c# if (!RazorLanguageVersion.TryParse("3.0", out var razorLanguageVersion) || configuration.LanguageVersion.CompareTo(razorLanguageVersion) < 0)

As Microsoft continues to refactor the engine, they are moving more stuff out of the configuration pipeline and into the common engine, likely to reduce passes to improve performane.

Thanks for your efforts on this project.

Just wondering if there has there been any progress on this issue? Seems can't use RazorLight version 2.0-beta4 in .net core 3.1 if you define a @section ?

As it has been a while, I'm just here to report that the temporary workaround proposed by VadimBurshtyn works like a charm in my particular case.

If you apply the workaround, then sections will work in .NET Core 3.1 and RazorLight 2.0-beta4.

Thanks for helping solving this issue. I have shared the fix. I am not working for the company anymore were I was using this library

Hi everyone, thank you for the awesome work on this :)

We are currently moving everything over to DotNet Core, and now we too need sections to work, but the workaround proposed by @VadimBurshtyn seems to no longer work, or i at least I cannot seem to get it working.

I run into the following exception no matter what i do:
Method 'GetItem' in type 'NullRazorProjectFileSystem' from assembly 'MyProj.RazorEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' does not have an implementation.

Our Setup:
A .net standard 2.0 class library with RazorLight 2.0.0-Beta7, templates and models, using "Embedded Ressources Project".
It calls itself for the operatingAssembly (RazorEngine is in the root of the class library): .SetOperatingAssembly(Assembly.GetAssembly(typeof(RazorEngine)))

This is so that we can call and test it from LinqPad 5/6, DotNet core and framework.
And everything resolves and works flawlessly except when adding a @section 😢

Also @jzabroski is there any ETA on this being fixed without having to use workarounds?

Update:
Figured it out, and just sharing this in case someone else runs into the same issue.

It seems to satisfy the GetItem in a RazorProject i needed to specifically reference this package version in the netstandard2.0 project hosting RazorLight
<PackageReference Include="Microsoft.AspNetCore.Razor.Language" Version="3.1.4" />

and now all is good 😊

I have this working in my local and the fix is shockingly simple that I'm disappointed I didn't put more effort in earlier to fix it. But I hope you'll all give me a pass given COVID-19.

Remaining task is to figure out why this broke in the first place. My memory is one thing, and the facts I observe are another. I believe its a "modus ponens" logic error, but I need to think it through to make sure I understand how this defect emerged.

After spending a couple of weeks working on a netstandard2.0 library with RazorLight testing it with both net472 and net-core, i hit a road-bump yesterday where this simply cannot be called from an ASP.NET 4.7.2 running in IIS... this looks to be due to some old assembly refs that RazorLight depends upon! and there is no way to make it work with our current solution as it cannot resolve the dependencies..

Can you show me a repro? Is this problem related to sections or should you open a new issue so we can discuss your problems there? Thanks.

Yes you are right @jzabroski, it does not belong here.
I will create a new issue for this, and make a simple repro when i have a bit of time. :)

Fixed in RazorLight-2.0.0-beta8. But please use beta9 instead if targeting .netcoreapp3.1 due to bug in dotnet pack: #348

Was this page helpful?
0 / 5 - 0 ratings