Embedded view can not be found in ASP.NET Core MVC
Asked Answered
P

2

8

I can't reuse my cshtml files from another assembly. Here's the bare-bone sample:

  • Create an ASP.NET Core Web Application project with default template (using Web-Application, Model-View-Controller), and name it ViewReuse
  • Add a class library called ViewLibrary
  • Add a reference to Microsoft.AspNetCore.All metapackage in ViewLibrary
  • Create a folder called Views, then create another folder called Shared, and inside it create a simple cshtml file called ReusedLayout.cshtml
  • Add EmbeddedResources Include='Views\**\*.cshtml' to csproj of ViewLibrary, to include all views inside the ViewLibrary.dll
  • In ViewReuse project, inside Startup.cs, change configuration of MVC service to services.AddMvc().ConfigureApplicationPartManager(p => { p.ApplicationParts.Add(new AssemblyPart(typeof(ReusedController).Assembly)); });
  • Change About.cshtml to use the layout from ViewLibrary: Layout = "/Views/Shared/ReusedLayout.cshtml"
  • Then run the application, and navigate to /home/about.

For me I encountered this error:

InvalidOperationException: The layout view '/Views/Shared/ReusedLayout.cshtml' could not be located. The following locations were searched: /Views/Shared/ReusedLayout.cshtml

What have I done wrong? How do I solve this issue?

Pleuro answered 1/1, 2018 at 16:49 Comment(0)
D
2

I solved it by the following way:

Razor class library project

First I created a solution called RazorDll with a Razor dll library project and deleted everything in it. Now create the MVC structure for the views. For testing purpose, I added a file called _Layout2 there.

enter image description here

Also add an empty Startup class in the project root for assembly detection later:

namespace RazorDll {
    public class Startup {
    }
}

Its important to have all Razor filed embedded! You have two ways of doing this:

Embedd all in the .csproj file properties

If you have a project just for embedding all Razor view, this is the best option since you don't have to edit file propertys for every view by hand. Just right click on the project and choose edit project file, or open the corresponding .csproj file with any text editor and insert the following in <Project>

  <ItemGroup>
    <EmbeddedResource Include="Views\**\*.cshtml">
      <CopyToOutputDirectory>Never</CopyToOutputDirectory>
    </EmbeddedResource>
  </ItemGroup>

Embedd single Razor views by hand

Just right click on a Razor views .cshtml file, choose properties and set the build action to embedded ressource. Required for every view you want to use from another .NET Core assembly.

enter image description here

Consuming MVC project for the Razor class library

Now create the MVC project, called MvcDemo here. This is a normal ASP.NET Core 2.1 MVC project (choosed the LTS here, but should also work with 2.2) that got linked to our Razor dll

enter image description here enter image description here

To search for Razor views in the Assembly, we add it in Startup.ConfigureServices method:

var viewAssembly = typeof(RazorDll.Startup).GetTypeInfo().Assembly;
var fileProvider = new EmbeddedFileProvider(viewAssembly);
services.Configure<RazorViewEngineOptions>(options => {
    options.FileProviders.Add(fileProvider);
});

Notice the full qualified type in typeof to distinct between the Startup class of the consuming MVC project (which would be loaded without namespace) and the Razor class library.

You're ready to change e.g. _ViewStart.cshtml to consume our test _Layout2 from our Razor class library:

@{
    Layout = "_Layout2";
}

Result of a simple POC demo project:

enter image description here

Detruncate answered 20/9, 2019 at 17:35 Comment(1)
I am having a similar issue with an application in .NET 6.0 with mixed Razor pages and WebApi, attempting to use your solution but FileProviders does not seem to be available in RazorViewEngineOptions. Any thoughts?Confidential
J
0

Try right-click over the view files and in properties change to embedded resource.

Jazmin answered 22/12, 2018 at 21:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.