3

I want to find my cshtml file in my ASP.NET Core 2.1 Web API project. To do it, I'm using this code:

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

var viewResult = this.razorViewEngine.FindView(
                actionContext,
                "~/PdfTemplate/ProjectRaport.cshtml",
                false);

The file is here:

enter image description here

But from code above, the View (that is ~/PdfTemplate/ProjectRaport.cshtml) is null.

How to find specific file by path in WebApi Core?

This code works ok:

var viewResult = this.razorViewEngine.FindView(actionContext,
                Path.Combine(this.hostingEnvironment.ContentRootPath, "PdfTemplate", "ProjectRaport.cshtml"),
                false);

Path to file is ok, but the View in viewResult is still null

When I tried GetView:

var viewResult = this.razorViewEngine.GetView(
                Path.Combine(this.hostingEnvironment.ContentRootPath, "PdfTemplate", "ProjectRaport.cshtml"),
                Path.Combine(this.hostingEnvironment.ContentRootPath, "PdfTemplate", "ProjectRaport.cshtml"),
                false);

the viewResult.View is still null

EDIT

In SearchedLocations the path is ok:

enter image description here

enter image description here

When I deleted .cshtml extension, SearchedLocations is empty

Dragos Durlut
  • 8,018
  • 10
  • 47
  • 62
michasaucer
  • 4,562
  • 9
  • 40
  • 91

2 Answers2

9

I recently tried to implement the razor email template explained by Scott Sauber

Tutorial here: https://scottsauber.com/2018/07/07/walkthrough-creating-an-html-email-template-with-razor-and-razor-class-libraries-and-rendering-it-from-a-net-standard-class-library/

Issue was that I had to overcome a bug(https://stackoverflow.com/a/56504181/249895) that needed the relative netcodeapp2.2 that the asemblied resided in.

var viewPath = ‘~/bin/Debug/netcoreapp2.2/Views/MainView.cshtml’;

_viewEngine.GetView(executingFilePath: viewPath , viewPath: viewPath , isMainPage: true);

Getting the bin\Debug\netcoreapp2.2 can be achieved by using this code:

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
public class RenderingService : IRenderingService
{

    private readonly IHostingEnvironment _hostingEnvironment;
    public RenderingService(IHostingEnvironment hostingEnvironment)
    {
    _hostingEnvironment = hostingEnvironment;
    }

    public string RelativeAssemblyDirectory()
    {
        var contentRootPath = _hostingEnvironment.ContentRootPath;
        string executingAssemblyDirectoryAbsolutePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
        string executingAssemblyDirectoryRelativePath = System.IO.Path.GetRelativePath(contentRootPath, executingAssemblyDirectoryAbsolutePath);
        return executingAssemblyDirectoryRelativePath;
    }
}

All fine and dandy until I had issues regarding the template file. Problem was that even though the file is in ~\bin\Debug\netcoreapp2.2 it searches for the template in the root folder such as rootfolder\Views\Shared\_Layout.cshtml and not in rootfolder\bin\Debug\netcoreapp2.2\Views\Shared\_Layout.cshtml.

This is most likely generated by the fact that I have the views as an embedded resource in a CLASS LIBRARY and not in a Web Api solution directly. class library folder structure

The weird part is that if you do not have the files in the root folder, you still get the CACHED Layout page.

The good part is that when you PUBLISH the solution, it flattens the solution so the VIEWS are in ROOT folder.

publish

[Solution]

The solution seems to be in the Startup.cs folder.

Got my solution from here: Cannot find view located in referenced project

//https://stackoverflow.com/q/50934768/249895
services.Configure<Microsoft.AspNetCore.Mvc.Razor.RazorViewEngineOptions>(o => {
                o.ViewLocationFormats.Add("/Views/{0}" + Microsoft.AspNetCore.Mvc.Razor.RazorViewEngine.ViewExtension);
                o.FileProviders.Add(new Microsoft.Extensions.FileProviders.PhysicalFileProvider(AppContext.BaseDirectory));
            });

After this, you can put your code like this:

var contentRootPath = _hostingEnvironment.ContentRootPath;
string executingAssemblyDirectoryAbsolutePath = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
string executingAssemblyDirectoryRelativePath = System.IO.Path.GetRelativePath(contentRootPath, executingAssemblyDirectoryAbsolutePath);

string executingFilePath = $"{executingAssemblyDirectoryAbsolutePath.Replace('\\', '/')}/Views/Main.cshtml";
string viewPath = "~/Views/Main.cshtml";
string mainViewRelativePath = $"~/{executingAssemblyDirectoryRelativePath.Replace('\\','/')}/Views/Main.cshtml";

var getViewResult = _viewEngine.GetView(executingFilePath: executingFilePath, viewPath: viewPath, isMainPage: true);

<!-- OR -->

var getViewResult = _viewEngine.GetView(executingFilePath: viewPath, viewPath: viewPath, isMainPage: true);
Dragos Durlut
  • 8,018
  • 10
  • 47
  • 62
  • Info also here: http://justcodesnippets.durlut.ro/index.php/2019/11/01/issue-of-razorviewengine-caching-and-layout-location-in-net-core/ – Dragos Durlut Nov 01 '19 at 14:46
0

I didn't find a working response to my question, so I posted my solution that works.

Instead of using PathCombine with ContentRootPath, just type :

string viewPath = "~/PdfTemplate/ProjectRaport.cshtml";
var viewResult = this.razorViewEngine.GetView(viewPath, viewPath, false);

and it works ok

Dragos Durlut
  • 8,018
  • 10
  • 47
  • 62
michasaucer
  • 4,562
  • 9
  • 40
  • 91
  • Just to add to your comment, you might also have some caching issues. Your solution worked, but only after I copied the Views folder with all its content to these folders: bin\Debug\ and bin\ . After you delete the folders from there, it keeps working. Pretty stupid. – Dragos Durlut Nov 01 '19 at 09:14
  • 1
    I developed a bit more on the subject here: http://justcodesnippets.durlut.ro/index.php/2019/11/01/getting-relative-path-to-bindebugnetcoreapp2-2-in-asp-net-core-2/ – Dragos Durlut Nov 01 '19 at 09:57
  • Amazing stuff! Please post it as answer so another will find it easier – michasaucer Nov 01 '19 at 10:27
  • Still have to fix the caching issues. Apparently if I change the layout from red to green it still displays the red one. – Dragos Durlut Nov 01 '19 at 10:39
  • I've added my findings – Dragos Durlut Nov 01 '19 at 13:03