3

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.

Kjensen
  • 12,447
  • 36
  • 109
  • 171
  • 1
    There's a lengthy reply to [Using Razor outside of MVC in .NET Core](https://stackoverflow.com/questions/38247080/using-razor-outside-of-mvc-in-net-core) which should offer you guidance. – Mark G May 11 '18 at 17:42
  • Thanks, Mark. They are good options, but I can't get any of them to work. :( – Kjensen May 14 '18 at 09:40
  • You mention that the suggested options do not work. Can you show what you have done so far and where they are causing problem in a [mcve] that can be used to reproduce the problem. May be we can help from there. Based on a comment you left on one of the suggested answers you seem to have not registered a dependency service but can't say for sure from what you have currently shown – Nkosi May 14 '18 at 09:51
  • I could show you each of the 4 different examples, that I have worked on, but since I was unable to get any of then working, and none of them have been verified working in .net core 2 outside an MVC project - I think it would just add confusion. I hope somebody turns up and says "Hey, I got RazorLight to work in .net core 2 in a console app" - and then we can take it from there. – Kjensen May 14 '18 at 10:04
  • Fair enough. The answer where you left the comment. That answer simplified the one it took example from I believe it omitted some dependent services when configuring during startup, but wanted to see what you did so that I can identify the missing service based on the error you are getting. – Nkosi May 14 '18 at 10:10
  • I just came by that question. My answer https://stackoverflow.com/a/47756437/403671 works in .net core 2.0 – Simon Mourier Jul 22 '18 at 07:29
  • 2 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. I prefer Mandrill or Sendgrid these days - using templates. – Kjensen Feb 01 '20 at 17:16

1 Answers1

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.

Nkosi
  • 235,767
  • 35
  • 427
  • 472
  • Great answer, I think this is close... Now, what I don't understand is, what do I need to make a reference to, in order to get services.AddMvc() to work? – Kjensen May 14 '18 at 11:17
  • @Kjensen That extension method lives in the `Microsoft.Extensions.DependencyInjection` namespace but belongs to the `Microsoft.AspNetCore.Mvc` project. Check the link to the source code on Github. – Nkosi May 14 '18 at 11:20
  • Managed to get a bit further... NOw I am stuck with a CS0012: The type 'Attribute' is defined in an assembly that is not referenced. You must add a reference to assembly 'netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. I have already added a reference to .net standard. THis has already cost me almost two days, so I am giving up and an going to create a special .net 4.x project just for generating emails, wrapped in a webservice. I will give you the bounty, since it is the best answer. – Kjensen May 14 '18 at 11:57
  • 1
    @Kjensen Try adding `true` to your csproj file. – Mark G May 14 '18 at 15:54
  • I tried that (saw it somewhere), but it did not help. :( But thanks – Kjensen May 14 '18 at 17:53