我正在使用最新的VS.2017更新和MVC .NET Core Web应用程序模板。我决定在外部装配中使用ViewComponents,因为我读了几篇帖子表明没有奇怪的技巧就不可能。
我有我的主Web应用程序,然后我创建了一个名为MySite.Components 的 .NET Framework类库,这是“外部程序集”。在其中我安装了ViewFeatures NuGet。我在/Views/Shared/Components/GoogleAdsense/Default.cshtml中创建了我的View组件CSHTML。
我注意到我的CSPROJ已将GoogleAdSense作为嵌入式资源:
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
<EmbeddedResource Include="Views\Shared\Components\GoogleAdsense\Default.cshtml" />
</ItemGroup>
视图组件实际上非常简单:
namespace MySite.Components.ViewComponents {
[ViewComponent(Name = "GoogleAdsense")]
public class GoogleAdsense : ViewComponent {
public async Task<IViewComponentResult> InvokeAsync(string adSlot, string clientId, string adStyle = "")
{
var model = await GetConfigAsync(adSlot, clientId, adStyle);
return View(model);
}
private Task<GoogleAdUnitCompModel> GetConfigAsync(string adSlot, string clientId, string adStyle)
{
GoogleAdUnitCompModel model = new GoogleAdUnitCompModel
{
ClientId = clientId, // apparently we can't access App_Data because there is no AppDomain in .NET core
SlotNr = adSlot,
Style = adStyle
};
return Task.FromResult(model);
}
}
}
然后在主项目(ASP.NET核心Web应用程序)中安装了文件提供程序NuGet并修改了我的启动:
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(MySite.Components.ViewComponents.GoogleAdsense).GetTypeInfo().Assembly,
"MySite.Components.ViewComponents"
));
});
然后我尝试在这样的视图中使用视图组件:
@using MySite.Components.ViewComponents
:
@Component.InvokeAsync(nameof(GoogleAdsense), new { adSlot = "2700000000", clientId = "ca-pub-0000000000000000", adStyle="" })
我收到错误
*InvalidOperationException: A view component named 'GoogleAdsense' could not be found.*
还尝试使用没有nameof()的表示法,它使用InvokeAsync的泛型参数但是也失败但是
*"Argument 1: cannot convert from 'method group' to 'object'"*
使用TagHelper表单只是将其呈现为无法识别的HTML:
<vc:GoogleAdsense adSlot = "2700000000" clientId = "ca-pub-0000000000000000"></vc:GoogleAdsense>
最后,在主程序集(实际的Web应用程序)上,我使用外部程序集类型上的GetManifestResourceNames()来验证它是否已嵌入,并且返回的列表将其列为:
[0] = "MySite.Components.Views.Shared.Components.GoogleAdsense.Default.cshtml"
答案 0 :(得分:4)
我做了很多反复试验,终于能够让这个工作了。这里有很多指南,但它们都是针对.NET Core 1.0的,我还发现它们在使用来自其他解决方案的DLL引用时不起作用。
我们先来谈谈组件名称。组件名称由约定或属性确定。按照惯例命名,类名必须以“ViewComponent”结尾,然后组件名称将是“ViewComponent”之前的所有内容(就像Controller名称一样)。如果只使用[ViewComponent]
装饰类,则组件名称将明确为类名。您还可以使用属性的Name参数直接将名称设置为其他名称。
这三个示例中的所有三个都会生成一个名为“GoogleAdsense”的组件名称。
public class GoogleAdsenseViewComponent : ViewComponent { }
[ViewComponent]
public class GoogleAdsense : ViewComponent { }
[ViewComponent(Name = "GoogleAdsense")]
public class Foo: ViewComponent { }
之后,请确保您的观点位于正确的文件夹结构中。
├── Views
│ ├── Shared
│ │ ├── Components
│ │ │ ├── GoogleAdsense <--component name
│ │ │ │ ├── Default.cshtml
然后,视图必须全部包含在嵌入式资源中。右键单击&gt;视图上的属性,并将“构建操作”设置为“嵌入式资源”。您也可以在.csproj中手动执行此操作(如果您有大量视图,则可以利用通配)。
<ItemGroup>
<EmbeddedResource Include="Views\Shared\Components\GoogleAdsense\Default.cshtml" />
</ItemGroup>
这就是源项目。请注意,您必须对要显示的视图的任何更改进行构建,因为它们包含在DLL中。这似乎很明显,但它与您通常与视图交互的方式有所不同。
现在进入消费项目。在Startup.cs中的ConfigureServices中,必须将组件的程序集添加为MVC ApplicationPart
和EmbeddedFileProvider
。 EmbeddedFileProvider
可以访问程序集中嵌入的视图,ApplicationPart
设置MVC以将其包含在搜索路径中。
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"));
});
如果在该程序集中有多个ViewComponents,则这对所有这些都是足够的。您可以选择为EmbeddedFileProvider
提供基本命名空间。我已经找到了必要的时间和不需要的时间,所以最好只提供它。此命名空间应该是项目的Default Namespace属性(Properties - &gt; Application - &gt; Default Namespace)。
最后,要调用ViewComponent,请使用组件名称。请记住,组件名称可能与类名称不同。除非您使用[ViewComponent]
将组件名称设置为类名,否则无法使用nameof
。
@await Component.InvokeAsync("GoogleAdsense")
答案 1 :(得分:0)
通过从&#34; external&#34;生成并安装NuGet包,我能够从外部解决方案中获得ViewComponent。毫无问题地装配到消耗解决方案中。我最初尝试添加对dll的引用而不创建我自己的NuGet包,但它不起作用。
我建议先尝试NuGet包。如果它仍然不起作用,你可以发布这两个项目,以便我可以帮助调试吗?