RazorViewEngine in console app cannot find View

I have the following

  • dotnet core 6 console app
  • dotnet core 6 Razor Class Libary (with .cshtml)

I'm doing a View Engine RenderAsync() that works just fine in web api. When running in a console app cannot find the template, template is there in the dll.

enter image description here

First question, what is the relative/absolute path to that cshtml? I'm using: @"Templates/Pdf/LevelsEmail.cshtml"

Console App startup

IServiceCollection serviceCollection = new ServiceCollection();
services.AddScoped<ITemplateBuilder, TemplateBuilder>();
var listener = new DiagnosticListener("Microsoft.AspNetCore");
services.AddSingleton(listener);
services.AddSingleton<DiagnosticSource>(listener);
services.AddRazorPages();
// rest of deps
var scope = provider.CreateScope();
await scope.ServiceProvider.GetRequiredService<Runner>().ProcessAsync();

in RCL csproj

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

    <PropertyGroup>
        <TargetFramework>net6.0</TargetFramework>
        <AddRazorSupportForMvc>true</AddRazorSupportForMvc>
    </PropertyGroup>
    
    <ItemGroup>
        <FrameworkReference Include="Microsoft.AspNetCore.App" />
    </ItemGroup>

</Project>

Trying to GetView or FindView

var httpContext = new DefaultHttpContext
        {
            RequestServices = _serviceProvider
        };
    var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());

Searching the ViewEngineResult

    var viewResult = _viewEngine.GetView(executingFilePath: viewPath, viewPath: viewPath, isMainPage);
    if (getViewResult.Success)
    {
        return getViewResult;
    }

    var findViewResult = _viewEngine.FindView(actionContext, viewPath, isMainPage);
    if (findViewResult.Success)
    {
        return findViewResult;
    }

Then rendering (this is just an example, problem is at fetching the View)

var viewContext = new ViewContext(actionContext, 
                        viewResult.View, 
                        viewDictionary,
                        new TempDataDictionary(httpContext, _tempDataProvider), 
                        outputWriter, 
                        new HtmlHelperOptions());
      await viewResult.View.RenderAsync(viewContext);

Second question: is this possible to use RazorViewEngine in a console app (not a web app)?


Solution 1:

Found one workaround, it is not the answer to the question, so I will keep it open, but it does the trick for me.

So:

Changed console app to web

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

to

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

Program looks like:

var builder = WebApplication.CreateBuilder();
builder.Configuration.AddJsonFile("appsettings.json", optional: true);

builder.Services.AddModules(builder.Configuration);

var app = builder.Build();

ITemplateService myBuilder = app.Services.GetRequiredService<ITemplateBuilder>();

MyModel email = new MyModel{ Data = InitData() };

string compiled = await myBuilder.RenderAsync(MyModel.Template, email, true);

Mandatory to have on services collection

.AddRazorPages();

rest of the dependencies required in console app DiagnosticListener and DiagnosticSource no longer needed to be explicit injected, web project takes care of that.

For me this is a good solution because this console apps runs in docker containers, I did not tested if this can run in a durable azure function or aws lambda function, I have a feeling is not, but it must to be tested.