且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

无法找到外部程序集中的 ViewComponent

更新时间:2023-10-23 16:25:34

我做了很多试验和错误,终于能够让它工作.有很多关于这方面的指南,但它们都是针对 .NET Core 1.0 的,而且我还发现在使用来自另一个解决方案的 DLL 引用时它们不起作用.

I did a lot of trial-and-error and was finally able to get this working. There's a number of guides on this, but they're all for .NET Core 1.0, and I also found they did not work when using a DLL reference from another solution.

我们先说一下组件名称.组件名称由约定或属性确定.按照约定命名,类名必须以ViewComponent"结尾,然后组件名将是ViewComponent"之前的所有内容(就像控制器名称一样).如果你只是用 [ViewComponent] 装饰类,组件名将明确地是类名.您也可以使用属性的 Name 参数直接将名称设置为其他名称.

Let's talk about component name first. The component name is determined either by convention or attribute. To name by convention, the class name must end in "ViewComponent", and then the component name will be everything prior to "ViewComponent" (just like Controller names work). If you just decorate the class with [ViewComponent], the component name will explicitly be the class name. You can also directly set the name to something else with the attribute's Name parameter.

所有这三个示例都会生成一个名为GoogleAdsense"的组件.

All three of these examples produce a component name of "GoogleAdsense".

public class GoogleAdsenseViewComponent : ViewComponent { }

[ViewComponent]
public class GoogleAdsense : ViewComponent { }

[ViewComponent(Name = "GoogleAdsense")]
public class Foo: ViewComponent { }

之后,请确保您的视图位于正确的文件夹结构中.

After that, be sure your views are in the proper folder structure.

├── Views
│   ├── Shared
│   │   ├── Components
│   │   │   ├── GoogleAdsense <--component name
│   │   │   │   ├── Default.cshtml

然后,视图必须全部作为嵌入资源包含在内.在视图上右键单击 > 属性并将构建操作设置为嵌入式资源".您也可以在 .csproj 中手动执行此操作(如果您有很多视图,还可以利用通配符).

Then, the Views must all be included as embedded resources. Right-click > Properties on the view and set the Build Action to "Embedded resource". You can also do this manually in the .csproj (and take advantage of globbing if you have a lot of Views).

  <ItemGroup>
    <EmbeddedResource Include="ViewsSharedComponentsGoogleAdsenseDefault.cshtml" />
  </ItemGroup>

源项目就是这样.请注意,您必须进行构建才能显示对视图的任何更改,因为它们已包含在 DLL 中.这似乎很明显,但它与您通常与视图交互的方式有所不同.

That's it for the source project. Make note that you must do a build for any changes to your views to show up, since they are being included in the DLL. This seems obvious, but it's a change from how you normally interact with views.

现在到消费项目.在 Startup.cs 的 ConfigureServices 中,您必须将组件的程序集添加为 MVC ApplicationPartEmbeddedFileProvider.EmbeddedFileProvider 允许访问嵌入在程序集中的视图,ApplicationPart 设置 MVC 以将其包含在其搜索路径中.

Now to the consuming project. In ConfigureServices in Startup.cs, you must add your component's assembly as both an MVC ApplicationPart and as an EmbeddedFileProvider. The EmbeddedFileProvider gives access to the views embedded in the assembly, and the ApplicationPart sets up MVC to include it in its search paths.

var myAssembly = typeof(My.External.Project.GoogleAdsenseViewComponent).Assembly;

services.AddMvc().AddApplicationPart(myAssembly);

services.Configure<RazorViewEngineOptions>(options =>
{
    options.FileProviders.Add(new EmbeddedFileProvider(myAssembly, "My.External.Project"));
});

如果您在该程序集中有多个 ViewComponent,这对所有这些都足够了.您可以选择为 EmbeddedFileProvider 提供基本命名空间.我已经找到了需要的时候和不需要的时候,所以***只是提供它.这个命名空间应该是你项目的默认命名空间属性(属性 -> 应用程序 -> 默认命名空间).

If you have multiple ViewComponents in that assembly, this will suffice for all of them. You can optionally provide a base namespace to EmbeddedFileProvider. I have found times when it was necessary and times when it was not, so it is best to just provide it. This namespace should be the Default Namespace property of your project (Properties -> Application -> Default Namespace).

最后,要调用 ViewComponent,请使用组件名称.请记住,组件名称可能与类名称不同.除非你使用[ViewComponent]将组件名设置为类名,否则你不能使用nameof.

Finally, to invoke the ViewComponent, use the component name. Remember that the component name may differ from the class name. Unless you used [ViewComponent] to set the component name to be the class name, you cannot use nameof.

@await Component.InvokeAsync("GoogleAdsense")