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

时间:2017-05-10 20:34:06

标签: asp.net-core asp.net-core-mvc asp.net-core-viewcomponent

我正在使用最新的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"

2 个答案:

答案 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 ApplicationPartEmbeddedFileProviderEmbeddedFileProvider可以访问程序集中嵌入的视图,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包。如果它仍然不起作用,你可以发布这两个项目,以便我可以帮助调试吗?