何でエリアを利用するかについては省きます。
##バージョン
.net 5.0
Microsoft Visual Studio Community 2019 Version 16.8.6
##フォルダー構成
例えアプリにPersonnelとTreasurerという二つの論理グループがあるとします、エリアを利用するとフォルダー構造は次のようになります。
*プロジェクト名
|-Areas
|-Personnel
|-Controllers
|-HomeController.cs
|-Models
|-HomeModel.cs
|-Views
|-Home
|-Index.cshtml
|-About.cshtml
|-Treasurer
|-Controllers
|-HomeController.cs
|-Models
|-HomeModel.cs
|-Views
|-Home
|-Index.cshtml
|-About.cshtml
|-Controllers
|-Models
|-Views
|-wwwroot
エリアを利用する時の構造は一般的にこうなっているですが、MVCの規約ではViewファイルのみこの構造に従う必要がある、ModelとControllerは従わなくても問題がない、外だしは可能ということです。
##エリアを作成
プロジェクトで右クリック⇒追加⇒新規スキャフォールディングアイテム
##エリアルートを追加
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
//ルーティングのルールによって、エリアを持つルートはエリアを持たないルート具体的なので、前に配置する必要がある
endpoints.MapControllerRoute(
name: "areas",
pattern: "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
上記コードの「{area:exists}」ではルートが必ず一つのエリアと一致しなければならないという制約を掛けている
詳細なルーティング制約はここから参照
##エリアのコントローラー作成
namespace WebAppForDotNetCore5.Areas.Personnel.Controllers
{
//エリア属性によって、該当コントローラーを指定のエリアと関連付ける
[Area("Personnel")]
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
##_ViewStart.cshtml と _ViewImports.cshtml
この二ファイルの影響先はファイルを配置しているフォルダー及びその下級フォルダーのみ、なのでエリアじゃなく普通のViewsフォルダーにあるこの二ファイルはAreasに対しては影響を与えることはできない。
ViewsとAreasの両方に対して影響を与えたい場合はアプリケーションのルートフォルダ(Startup.csを含むフォルダ)にそのファイルを配置もしくはコピーすること。
_ViewStart.cshtmlの詳細はここから参照
_ViewImports.cshtmlの詳細はここから参照
##Areasのフォルダー名変更
既定のエリアフォルダー「Areas」を変更することはできます
public void ConfigureServices(IServiceCollection services)
{
services.Configure<RazorViewEngineOptions>(options =>
{
//既存のエリアビューの検出ルールをクリア
options.AreaViewLocationFormats.Clear();
//新しいエリアビューの検出ルールを登録する
options.AreaViewLocationFormats.Add("/MyAreas/{2}/Views/{1}/{0}.cshtml");
options.AreaViewLocationFormats.Add("/MyAreas/{2}/Views/Shared/{0}.cshtml");
options.AreaViewLocationFormats.Add("/Views/Shared/{0}.cshtml");
});
services.AddControllersWithViews();
}
##Area属性の応用
前述のようにエリアとコントローラーを関連付けるため、ントローラーにArea属性を定義する必要が有ります、もしそのエリアに沢山のコントローラーがあったらそれ全部を定義する必要が有ります。そうなると問題が発生し易くなります。
[System.AttributeUsage(System.AttributeTargets.Class | System.AttributeTargets.Method, AllowMultiple=false, Inherited=true)]
public class AreaAttribute : Microsoft.AspNetCore.Mvc.Routing.RouteValueAttribute
AreaAttributeクラスの定義から見るとArea属性が継承を許されていることがわかる、つまり親にArea属性を設定するとそのクラスを継承した子にもArea属性が適用されます。よってエリアコントローラーは次のように変更可能
namespace WebAppForDotNetCore5.Areas.Personnel.Controllers
{
//親コントローラーにArea属性を設定
//Controllerが抽象クラスなので、PersonnelBaseControllerは抽象にしてもしなくても良いです
[Area("Personnel")]
public abstract class PersonnelBaseController: Controller
{
}
}
namespace WebAppForDotNetCore5.Areas.Personnel.Controllers
{
//親コントローラーにエリア属性を設定しているので、該当子コントローラーには設定しなくてもPersonnelエリアと関連付けている
public class HomeController : PersonnelBaseController
{
public IActionResult Index()
{
return View();
}
}
}
##まとめ
#####エリアのビューの検出順序
- /Areas/<Area-Name>/Views/<Controller-Name>/<Action-Name>.cshtml
- /Areas/<Area-Name>/Views/Shared/<Action-Name>.cshtml
- /Views/Shared/<Action-Name>.cshtml
- /Pages/Shared/<Action-Name>.cshtml
#####長くなるので、エリア毎に認証スキーム設定に関しては別の記事でまとめる