adoconnection / RazorEngineCore

.NET6 Razor Template Engine
MIT License
576 stars 85 forks source link

Documentation update to improve usage experience: @Inherits directive #13

Closed AndyMDoyle closed 4 years ago

AndyMDoyle commented 4 years ago

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.

adoconnection commented 4 years ago

Thank you for the kind words. Im surprised RazorEngine dont mind to see several @include directives :)

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

Sushi21 commented 3 years ago

@AndyMDoyle

Im trying to run few tests before deciding to use or not that library for our future pdf engine

I'm having some compile error when Im adding that line at the top of my template

image Do I miss any nuget other that RazorEngineCore?

I'm using Core3.1 API

jackhamby commented 3 years ago

can we get this opened up again. the linked issue is completely separate. im having the same issue running in net5.0

error
adoconnection commented 3 years ago

I have attached sample ConsoleApp48 that runs on NET5

ConsoleApp48.zip

using RazorEngineCore;
using System;
using System.IO;

namespace ConsoleApp48
{
    class Program
    {
        static void Main(string[] args)
        {
            RazorEngine razorEngine = new RazorEngine();
            string templateText = File.ReadAllText("Template.cshtml");

            IRazorEngineCompiledTemplate<RazorEngineTemplateBase<EmailModel>> compiledTemplate = razorEngine.Compile<RazorEngineTemplateBase<EmailModel>>(templateText);

            string result = compiledTemplate.Run(instance => {
                instance.Model = new EmailModel
                {
                    Email = "mail@example.com",
                    FirstName = "Jack"
                };
            });

            Console.WriteLine(result);

            Console.ReadKey();
        }
    }
}
namespace ConsoleApp48
{
    public class EmailModel
    {
        public string Email { get; set; }
        public string FirstName { get; set; }
    }
}
@inherits RazorEngineCore.RazorEngineTemplateBase<ConsoleApp48.EmailModel>

<html>
    <body>
        <h1>Hello @Model.FirstName</h1>
    </body>
</html>
jackhamby commented 3 years ago

thanks for taking a look. i ran your stuff locally and it does work perfectly.

the code you have for the template and compiling is nearly exactly the same as what we have.

main difference i see is this is a console app whereas we have ASP.NET core MVC app.

i spun up an mvc app that tries to compile a single template with the @inherits directive and return an OK result with the resulting string. it blows up in the same way as our actual application (which is during the build with the same errors i posted above)

if you clone this repo and try to build it, you should see the same https://github.com/jackhamby/RazorEngineCoreError

again thanks for looking, any advice is greatly appreciated

wdcossey commented 3 years ago

The most likely scenario is that the .cshtml is being compiled automatically during the build process (i.e via Sdk.Razor.CurrentVersion.props. Basically you are building an MVC app so it will try compile all the .cshtml files it finds.

A simple workaround is to rename the file extension or change the way the file is handled in the .csproj

jackhamby commented 3 years ago

thanks @wdcossey. changing the extension does work, i did .cshtml -> .mcshtml and i was able to compile successfully. do you know how to handle this in the .csproj instead? it would be nice to keep .cshtml extention so at least VS recognizes the extension.

wdcossey commented 3 years ago

@jackhamby something like the following.

<Project Sdk="Microsoft.NET.Sdk.Web">

    <PropertyGroup>
        <TargetFramework>netcoreapp3.1</TargetFramework>
        <EnableDefaultContentItems>false</EnableDefaultContentItems>
    </PropertyGroup>

    <ItemGroup Condition="'$(EnableDefaultItems)' == 'true' And '$(EnableDefaultContentItems)' == 'false'">
        <Content Include="**\*.cshtml" 
                 ExcludeFromSingleFile="true" 
                 CopyToPublishDirectory="PreserveNewest" 
                 Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(DefaultWebContentItemExcludes);Templates\**\*.cshtml" />
        <None Remove="**\*.cshtml" />
        <Content Include="Templates\Template.cshtml">
            <CopyToOutputDirectory>Always</CopyToOutputDirectory>
        </Content>
    </ItemGroup>
</Project>
wdcossey commented 3 years ago

EnableDefaultContentItems is from Sdk.Razor.CurrentVersion.props, I just changed the logic slightly.

    <!--
    Set to true to automatically include certain file types, such as .cshtml files, as content in the project.
    When referenced via Microsoft.NET.Sdk.Web, this additionally includes all files under wwwroot, and any config files.
    -->
    <EnableDefaultContentItems Condition="'$(EnableDefaultContentItems)'==''">true</EnableDefaultContentItems>

Default code:

  <ItemGroup Condition="'$(EnableDefaultItems)' == 'true' And '$(EnableDefaultContentItems)' == 'true'">
    <Content Include="**\*.cshtml" ExcludeFromSingleFile="true" CopyToPublishDirectory="PreserveNewest" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(DefaultWebContentItemExcludes)" />
    <Content Include="**\*.razor" ExcludeFromSingleFile="true" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder);$(DefaultWebContentItemExcludes)" />
    <None Remove="**\*.cshtml" />
    <None Remove="**\*.razor" />
  </ItemGroup>

I updated the Exclude property in my .csproj to exclude Templates\**\*.cshtml

jackhamby commented 3 years ago

thanks for all this. i played around with those snippets you sent but kept having the same issue. this weekend i finally got something to work. i changed the BuildAction property on the .cshtml file itself, from Content to EmbeddedResource.

image

once i got that switched over i could build and run. compilation works great as well as the intellisense provided by @inherits directive. thanks again for the help in this.

vukasinpetrovic commented 1 year ago

@jackhamby Man, you saved me. That's what I needed. Thank you very much!