英文:
Adding asp.net controllers/views from a Class Library
问题
我正在使用C#和.NET 6(可能是7)构建一个类库,用于与ASP.NET Core站点一起使用。
我希望这个类库(除其他功能外),包含一个配置UI(有点像Swashbuckle如何构建OpenAPI UI - 我查看了源代码,但对这部分不太理解)。
我想创建类库中的控制器/视图是一个不错的方法。
控制器自动工作(尽管我对路由冲突有些担忧 - 如果我的类库中有一个/foo/bar路由,使用此类库的项目也有一个/foo/bar路由会怎么样?)。
但是,视图似乎不会自动添加。我尝试了嵌入和遵循文件夹约定,但仍然出现以下错误:
在处理请求时发生未处理的异常。
InvalidOperationException: 未找到视图'Index'。已搜索以下位置:/Views/Foo/Index.cshtml
/Views/Shared/Index.cshtml
这是类库的相关部分:
我必须采取哪些措施才能从类库中加载/解析/运行这些视图?(或者有没有更好的方法可以在没有视图的情况下实现我尝试做的事情?)
英文:
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?)
答案1
得分: 1
ApplicationParts 是答案,但我发现文档有点难以理解,所以这是我所做的:
var assembly = typeof(FooController).Assembly;
@this.AddControllersWithViews()
.AddApplicationPart(assembly)
.AddRazorRuntimeCompilation();
@this.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{ options.FileProviders.Add(new EmbeddedFileProvider(assembly)); });
对我来说关键的部分是 .AddRazorRuntimeCompilation();
以及后面的行来添加文件提供程序。
英文:
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.
答案2
得分: 1
我按照之前的答案并进行了研究,发现相关页面缺少关键细节,以使其正常工作(将视图标记为嵌入式资源,视图似乎变成了区分大小写):
研究步骤:
- 克隆了Microsoft 示例应用程序,如此页面所述。
- 运行了WebAppParts示例(.Net Core 3.0) - 正常工作。
- 将WebAppParts示例升级到.Net 6.0 - 正常工作。
- 创建了一个全新的.Net 6 Web应用程序。
- 添加了MySharedApp .Net 6库。
- 添加了程序主设置的代码片段,并调用它来代替
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)); });
}
- 在_Layout.cshtml中添加了指向
MyShared/index
的菜单超链接 - 无法找到视图。 - 将示例项目与我的新项目进行了比较,并逐渐迁移设置/更改。
- 向库中添加了
Microsoft.Extensions.FileProviders.Embedded
NuGet 包。 - 发现任何共享视图都需要在视图的
Build Action
中标记为Embedded resource
。尽管在.csproj文件中有这个条目,但在示例应用程序中视图显示为Content
,这一点并不明显。
<ItemGroup>
<EmbeddedResource Include="Views\MyShared\Index.cshtml" />
</ItemGroup>
- 在所有这些更改之后,我的.Net 6.0测试Web应用程序开始共享库的视图和控制器。
- 最终的示例如下,是我在
Program.Main()
中简化应用程序代码的内容。如果不需要,请随时删除Auth或Json行:
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));
});
- 在将视图迁移到库时,我发现只有视图或局部视图名称相同时,才能找到局部视图。
例如,这个失败了:
@(await Html.PartialAsync("titlepartial"))
然后这个成功了:
@(await Html.PartialAsync("TitlePartial"))
英文:
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):
Research steps:
-
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 viewsBuild Action
. This was not apparent in the sample app as the view displays asContent
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"))
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论