ビューコンポーネント(ASP.NET MVC 6の新機能)をMVC 6 Webスタートアッププロジェクトとは別のアセンブリで定義して、複数のWebプロジェクトで再利用できるようにしたいと思います。サンプルソリューションは次のようになります。
新しいクラスライブラリ(パッケージ)を作成し、その中にビューコンポーネントを作成しました。また、ネストされたフォルダーの規則に従ってビューを作成しました。私のBookStore.Components
プロジェクトは次のようになります。
Webプロジェクトからこのビューコンポーネントを呼び出そうとすると、次のようになります。
@Component.Invoke("BookOfTheMonth")
...コンテンツ本文が空の場合に500エラーが発生します。 ViewComponentクラスが検出されたようですが、コンポーネントのかみそりビューは検出されていません。
また、DefaultViewComponentDescriptorProvider
を拡張して、BookStore.Components
アセンブリのビューコンポーネントを検出できるようにしました。
public class AssemblyProvider : IAssemblyProvider
{
public IEnumerable<Assembly> CandidateAssemblies
{
get
{
yield return typeof(AssemblyProvider).Assembly;
yield return typeof(BookStore.Components.BookOfTheMonthViewComponent).Assembly;
}
}
}
builder.RegisterType<AssemblyProvider>()
.AsImplementedInterfaces();
builder.RegisterType<DefaultViewComponentDescriptorProvider>()
.AsImplementedInterfaces();
上記のDefaultViewComponentDescriptorProvider
の登録が必要かどうかわからないので、登録の有無にかかわらず試しましたが、ビューコンポーネントが呼び出されたページで500エラーが発生します。
MVC6 Webプロジェクトとは別のアセンブリにあるビューコンポーネントを呼び出すにはどうすればよいですか?
更新2017-03-09
Visual Studio 2017では、MSBuildを使用して状況が少し変わりました。幸いなことに、それははるかに簡単です。これを機能させる方法は次のとおりです。
外部アセンブリで、これをcsprojファイルに追加します。
<ItemGroup>
<EmbeddedResource Include="Views/**/*.cshtml" />
</ItemGroup>
メインのWebプロジェクトで、次のNuGetパッケージを追加します:Microsoft.Extensions.FileProviders.Embedded
次に、スタートアップで、外部アセンブリをファイルプロバイダーのリストに追加します。
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
# Prior to .Net Standard 2.0
# typeof(SampleClassInAssembly).GetTypeInfo().Assembly
));
});
人々がまだこれを古いバージョンの.NetCoreとproject.json
で動作させようとしている場合に備えて、今のところ元の答えを残しておきます。
================================================== ==============
これを機能させるための手順は次のとおりです。
WebプロジェクトのStartup.cs
にCompositeFileProvider
を登録します。
services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProvider = new CompositeFileProvider(
new EmbeddedFileProvider(
typeof(BookOfTheMonthViewComponent).GetTypeInfo().Assembly,
"BookStore.Components"
),
options.FileProvider
);
});
CompositeFileProvider
とEmbeddedFileProvider
はどちらも新しいため、aspnetvnext
NuGetフィードからこれらを取得する必要があります。私はこのソースを追加することによってこれを行いました:
project.json
に依存関係を追加します。
"Microsoft.AspNet.FileProviders.Composite": "1.0.0-*",
"Microsoft.AspNet.FileProviders.Embedded": "1.0.0-*",
最後に、これをComponents
アセンブリのproject.json
に追加します。
"resource": "Views/**"
これを機能させるには、これで十分です。
動作するデモは次のとおりです: https://github.com/johnnyoshika/mvc6-view-components/tree/master
この回答は、ここでのこのディスカッションから作成されました: https://github.com/aspnet/Mvc/issues/375
更新2016-01-15現在、外部ビューコンポーネントに1つの問題があります。ビューのcshtmlファイルに加えた変更は、自動的に再コンパイルされません。強制的なVisualStudioのクリーンアップと再構築でさえ、それを行いません。ビューの再コンパイルをトリガーするには、コンポーネントアセンブリの.csファイルを変更する必要がありますが、これは将来修正される予定のようです。この問題の理由はここで説明されています: https://github.com/aspnet/Mvc/issues/3750#issuecomment-1717653
Githubで調査を行ったところ、PhysicalFileProvider
( link )IFileInfo GetFileInfo(string subpath)
メソッドがRazorエンジン( link )で使用されていることがわかりました。コンパイルする実際のファイルを取得します。
このメソッドの現在の実装
public IFileInfo GetFileInfo(string subpath)
{
if (string.IsNullOrEmpty(subpath))
{
return new NotFoundFileInfo(subpath);
}
// Relative paths starting with a leading slash okay
if (subpath.StartsWith("/", StringComparison.Ordinal))
{
subpath = subpath.Substring(1);
}
// Absolute paths not permitted.
if (Path.IsPathRooted(subpath))
{
return new NotFoundFileInfo(subpath);
}
var fullPath = GetFullPath(subpath);
if (fullPath == null)
{
return new NotFoundFileInfo(subpath);
}
var fileInfo = new FileInfo(fullPath);
if (FileSystemInfoHelper.IsHiddenFile(fileInfo))
{
return new NotFoundFileInfo(subpath);
}
return new PhysicalFileInfo(_filesWatcher, fileInfo);
}
private string GetFullPath(string path)
{
var fullPath = Path.GetFullPath(Path.Combine(Root, path));
if (!IsUnderneathRoot(fullPath))
{
return null;
}
return fullPath;
}
ここで、絶対パスも許可もされておらず、GetFullPath
メソッドはパスをメインのWebアプリケーションルートパスであるRoot
と組み合わせていることがわかります。
したがって、現在のフォルダ以外のフォルダからViewComponent
を開くことはできないと思います。
。NetCore v3.x現在:
Microsoft.Extensions.FileProviders.Embedded
_ nugetパッケージを削除しますMicrosoft.AspNetCore.Mvc.Razor.RuntimeCompilation
_ nugetパッケージをインストールします.AddRazorRuntimeCompilation()
を呼び出します。例:services.AddMvc().AddRazorRuntimeCompilation()
_services.Configure<RazorViewEngineOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
));
});
_
これを追加:
_services.Configure<MvcRazorRuntimeCompilationOptions>(options =>
{
options.FileProviders.Add(new EmbeddedFileProvider(
typeof(SampleClassInAssembly).Assembly
));
});
_
そして、あなたは行ってもいいです。