Generate Razor HTML emails in dotnet core 2

Refresh

April 2019

Views

1.8k time

1

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

1 answers

3

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.