Reputation: 26096
I am building a class library in C# with .NET 6 (possibly 7) for use with ASP.NET Core sites.
I would like this class library to (among other things), contain a configuration UI (kinda like how Swashbuckle builds up an OpenAPI UI - I checked out the source code and couldn't quite wrap my mind around that portion).
I figured creating controllers/views in the class library would be the way to go.
The controllers are working automatically (although, I'm mildly concerned about routing conflicts -- what if I have a /foo/bar route in my class library and the project using this library also has a /foo/bar route?).
The views, however, do not seem to be added automatically. I've tried embedding and following the folder conventions, but I still get the error:
An unhandled exception occurred while processing the request. InvalidOperationException: The view 'Index' was not found. The following locations were searched: /Views/Foo/Index.cshtml /Views/Shared/Index.cshtml
Here's the relevant portion of the class library:
What do I have to do to get these Views loaded/parsed/working from a class library? (Or is there a better alternative to doing what I'm trying to do without Views?)
Upvotes: 2
Views: 2154
Reputation: 26096
ApplicationParts is the answer, but I found the documentation a little hard to follow, so here's what I did:
var assembly = typeof(FooController).Assembly;
@this.AddControllersWithViews()
.AddApplicationPart(assembly)
.AddRazorRuntimeCompilation();
@this.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{ options.FileProviders.Add(new EmbeddedFileProvider(assembly)); });
The key for me was .AddRazorRuntimeCompilation();
and the following line to add a file provider.
Upvotes: 1
Reputation: 93551
I followed the previous answer and found it, and the referenced pages, were missing key details to make it work (marking views as embedded resources and views appear to become case sensitive):
Cloned the Microsoft Sample app mentioned on this page
Ran WebAppParts sample (.Net core 3.0) - Worked
Updated WebAppParts sample to .Net 6.0 - Worked
Created a brand new .Net 6 Web Application
Added MySharedApp .Net 6 library
Added Snippet to the program main setup and called this instead of AddControllersWithViews
public static void ConfigureServices(IServiceCollection services)
{
var assembly = typeof(MySharedController).Assembly;
services.AddControllersWithViews()
.AddApplicationPart(assembly)
.AddRazorRuntimeCompilation();
services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{ options.FileProviders.Add(new EmbeddedFileProvider(assembly)); });
}
Added menu hyperlink to MyShared/index
in _Layout.cshtml - It cannot find the view
Diff'ed the sample project against my new one and slowly migrated settings/changes across.
Added Microsoft.Extensions.FileProviders.Embedded
NuGet to library.
Found that any shared views needed to be marked as Embedded resource
in the views Build Action
. This was not apparent in the sample app as the view displays as Content
in the sample app, despite this entry in the .csproj
<ItemGroup>
<EmbeddedResource Include="Views\MyShared\Index.cshtml" />
</ItemGroup>
After all these changes, my .Net 6.0 test web app started sharing the library's views and controller.
Final example below is what I reduced my app code to in Program.Main()
. Feel free to remove the Auth or Json lines if not needed:
var assembly = typeof(AnySharedController).Assembly;
builder.Services.AddRazorPages()
.AddJsonOptions(x => x.JsonSerializerOptions.DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull)
.AddApplicationPart(assembly)
.AddRazorRuntimeCompilation()
.AddMicrosoftIdentityUI();
builder.Services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(assembly));
});
While migrating Views to a library, I found that partial views were not found unless the view or partial view name was the same case.
e.g. This one failed
@(await Html.PartialAsync("titlepartial"))
Then this one worked
@(await Html.PartialAsync("TitlePartial"))
Upvotes: 1