Search code examples
razor.net-coreasp.net-core-2.0razorengine

Generate Razor HTML emails in dotnet core 2


How can you generate emails (html) using Razor in dotnetcore - and not from an MVC app (think from a console app)?

RazorEngine does a great job in .net 4.x, but is not working in dotnet core.

RazorEngineLight works in dotnet core 1.x, but not in 2.x.

Some other options are mentioned in this post: Using Razor outside of MVC in .NET Core but none of them actually work in .net core 2.0

Edit two years later:

In case somebody comes here looking for answers on this... I (OP) have stopped entirely relying on Razor to generate emails using templates etc. It is very fragile and error-prone - a non-stop headache. I prefer Mandrill or Sendgrid these days - using templates.


Solution

  • In a comment on this provided answer from the link provided you stated

    I am not able to get this to work. I get the error: Unable to resolve service for type 'Microsoft.AspNetCore.Mvc.Razor.IRazorViewEngine' while attempting to activate 'Mvc.RenderViewToString.RazorViewToStringRenderer'.'

    This normally indicates that a required service was not registered with the service collection so the provider is unable to resolve the service when needed.

    That answer did not refer to the additional service configuration and only had

    public void ConfigureServices(IServiceCollection services)
    {
         services.AddScoped<IViewRender, ViewRender>();
    }
    

    as it was already being run in an Asp.Net Core environment, which meant that the services manually added in the console application were already being done in start up.

    Pay attention to this snippet from the answer that was linked to from the answer you commented on.

    private static void ConfigureDefaultServices(IServiceCollection services) {
        var applicationEnvironment = PlatformServices.Default.Application;
        services.AddSingleton(applicationEnvironment);
    
        var appDirectory = Directory.GetCurrentDirectory();
    
        var environment = new HostingEnvironment
        {
            WebRootFileProvider = new PhysicalFileProvider(appDirectory),
            ApplicationName = "RenderRazorToString"
        };
        services.AddSingleton<IHostingEnvironment>(environment);
    
        services.Configure<RazorViewEngineOptions>(options =>
        {
            options.FileProviders.Clear();
            options.FileProviders.Add(new PhysicalFileProvider(appDirectory));
        });
    
        services.AddSingleton<ObjectPoolProvider, DefaultObjectPoolProvider>();
    
        var diagnosticSource = new DiagnosticListener("Microsoft.AspNetCore");
        services.AddSingleton<DiagnosticSource>(diagnosticSource);
    
        services.AddLogging();
        services.AddMvc();
        services.AddSingleton<RazorViewToStringRenderer>();
    }
    

    The important part above is

    services.AddMvc();
    

    That will add the relevant view engine dependencies to the service collection

    MvcServiceCollectionExtensions.cs

    public static IMvcBuilder AddMvc(this IServiceCollection services) {
    
        //...code removed for brevity
    
        // Default framework order
        builder.AddFormatterMappings();
        builder.AddViews();
        builder.AddRazorViewEngine();
        builder.AddRazorPages();
        builder.AddCacheTagHelper();
    
        //...code removed for brevity
    
    }
    

    Everything else as currently presented is sound and should work as intended.

    You should review

    https://github.com/aspnet/Entropy/tree/93ee2cf54eb700c4bf8ad3251f627c8f1a07fb17/samples/Mvc.RenderViewToString

    and follow a similar structure to get the code to work in your scenario. From there you can start making your custom modification and monitor where it breaks.

    The modular nature of .Net Core allows for such customizations as the different modules can be stripped out and used in other environments.