扩展 AspNetCore 视图发现
Extend AspNetCore View Discovery
我正在寻找一种方法来扩展 AspNetCore MVC 视图发现逻辑。我希望能够从控制器继承并让新控制器能够访问基本控制器的操作。有没有一种方法可以扩展视图发现逻辑,以便您可以告诉控制器在哪里寻找它的视图,在控制器的文件夹中查找,根据基本控制器的名称在文件夹中查找,甚至在基于控制器命名空间的文件夹?
~/Controllers/UserAccountController.cs
namespace App.Controllers.UserAccount
{
public class UserAccountController {
public virtual async Task<IActionResult> Action1()
{
return View();
}
}
}
~/Controllers/UserAccountExtController.cs
namespace App.Controllers.UserAccount
{
public class UserAccountExtController : UserAccountController {
public override async Task<IActionResult> Action1()
{
return View();
}
}
}
有没有一种方法可以扩展视图发现逻辑,如果它在视图文件夹中找不到与控制器名称同名的视图,它将根据控制器的属性,还是继承控制器的文件夹,控制器所在的文件夹,还是基于控制器命名空间的文件夹?
由于 RandyBuchholz 关于将 ActionContext 转换为 ControllerActionContext 的提示,我最终使用 IViewLocationExpander 来解决问题,这使我能够识别控制器的 BaseType。如果控制器的默认位置不存在视图,这允许添加检查 BaseController 的默认位置的约定。
public class MyViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
// list used for future extension
var alternateLocations = new List<string>();
if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor descriptor)
{
var baseType = descriptor.ControllerTypeInfo.BaseType.Name;
if (!baseType.StartsWith("Controller"))
{
var baseLocation = baseType.Replace("Controller", string.Empty);
alternateLocations.Add("/Views/" + baseLocation + "/{0}.cshtml");
}
}
var locations = viewLocations.ToList();
locations.InsertRange(locations.IndexOf("/Views/Shared/{0}.cshtml") - 1, alternateLocations);
return locations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
}
然后只需在 Startup.cs
中注册 IViewLocationExpander
public void ConfigureServices(IServiceCollection services)
{
//...
services.Configure<RazorViewEngineOptions>(options =>
{
var expander = new MyViewLocationExpander();
options.ViewLocationExpanders.Add(expander);
});
//...
}
我正在寻找一种方法来扩展 AspNetCore MVC 视图发现逻辑。我希望能够从控制器继承并让新控制器能够访问基本控制器的操作。有没有一种方法可以扩展视图发现逻辑,以便您可以告诉控制器在哪里寻找它的视图,在控制器的文件夹中查找,根据基本控制器的名称在文件夹中查找,甚至在基于控制器命名空间的文件夹?
~/Controllers/UserAccountController.cs
namespace App.Controllers.UserAccount
{
public class UserAccountController {
public virtual async Task<IActionResult> Action1()
{
return View();
}
}
}
~/Controllers/UserAccountExtController.cs
namespace App.Controllers.UserAccount
{
public class UserAccountExtController : UserAccountController {
public override async Task<IActionResult> Action1()
{
return View();
}
}
}
有没有一种方法可以扩展视图发现逻辑,如果它在视图文件夹中找不到与控制器名称同名的视图,它将根据控制器的属性,还是继承控制器的文件夹,控制器所在的文件夹,还是基于控制器命名空间的文件夹?
由于 RandyBuchholz 关于将 ActionContext 转换为 ControllerActionContext 的提示,我最终使用 IViewLocationExpander 来解决问题,这使我能够识别控制器的 BaseType。如果控制器的默认位置不存在视图,这允许添加检查 BaseController 的默认位置的约定。
public class MyViewLocationExpander : IViewLocationExpander
{
public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
{
// list used for future extension
var alternateLocations = new List<string>();
if (context.ActionContext.ActionDescriptor is ControllerActionDescriptor descriptor)
{
var baseType = descriptor.ControllerTypeInfo.BaseType.Name;
if (!baseType.StartsWith("Controller"))
{
var baseLocation = baseType.Replace("Controller", string.Empty);
alternateLocations.Add("/Views/" + baseLocation + "/{0}.cshtml");
}
}
var locations = viewLocations.ToList();
locations.InsertRange(locations.IndexOf("/Views/Shared/{0}.cshtml") - 1, alternateLocations);
return locations;
}
public void PopulateValues(ViewLocationExpanderContext context)
{
}
}
然后只需在 Startup.cs
中注册 IViewLocationExpander public void ConfigureServices(IServiceCollection services)
{
//...
services.Configure<RazorViewEngineOptions>(options =>
{
var expander = new MyViewLocationExpander();
options.ViewLocationExpanders.Add(expander);
});
//...
}