Antaris / RazorEngine

Open source templating engine based on Microsoft's Razor parsing engine
http://antaris.github.io/RazorEngine
Other
2.13k stars 576 forks source link

Overidding the base template with Roslyn #517

Open stusklinar opened 6 years ago

stusklinar commented 6 years ago

Overriding the base template, and providing your own template of T, which also has a constructor means that the roslyn code won't be able to create your base template type of T.

For instance.

My client implements their own ViewBase<T>: TemplateBase<T> with a constructor of ViewContext - this contains things that are relevant for rendering their view (Common data or properties etc).

Under the new Roslyn code - the compilation.Emit(..) will fail not knowing how to create the type of ViewBase<T>.

In previous versions this was done using the TemplateActivator

stusklinar commented 6 years ago

Ok, I've looked further into this.

The RazorTemplateEngine generates the code, however when it creates the constructor it doesn't take into account any base constructors required to generate that class.

Generated Source from RazorTemplateEngine

 public class RazorEngine_cbb4eacf6f8e44e68fbdc911a5970a7a : MyNamespace.ViewBase<MyNamespace.MyModel>
    {
        #line hidden
        public RazorEngine_cbb4eacf6f8e44e68fbdc911a5970a7a()
        {
        }
    }

ViewBase class requiring a ctor param(Created by TemplateActivator)

public ViewBase(IComponentContext componentContext)
    {
        Contract.Requires(componentContext != null);

        _componentContext = componentContext;
    }

What we need generated for this to work.

 public class RazorEngine_cbb4eacf6f8e44e68fbdc911a5970a7a : MyNamespace.ViewBase<MyNamespace.MyModel>
    {
        #line hidden
        public RazorEngine_cbb4eacf6f8e44e68fbdc911a5970a7a(IComponentContext componentContext):base(context)
        {
        }

I got this working by manually change the source code before it's saved to file and adding this constructor in, the rest of the template compilation and loading works as expected from there on.

From where I see things, we can do this with changing the syntax tree and adding in the ctor(s) and their params should the base class require them, or we could provide a <func>/CSharpSyntaxRewriter param via config to allow for this to be provided in by the consumer as a pre-emit call?

Or - it's not a RazorEngine issue, and it's one for the MS Razor Team to also supply a method to create base classes so the code they provide doesn't need amending after it being created.

Happy to provide a pull request for this fix, just provide some guidance on how you want it done.

Thoughts?

stusklinar commented 6 years ago

CC @conniey