我有一个具有不同程序集(模块)的 ASP.NET Core MVC Web 应用程序。每个模块都定义有相应的 URL。
我创建了一个新的路由前缀,将模块名称添加到 URL 中。该前缀称为
module
。
另一方面,我有 2 个模块,称为
AccessControl
和 TimeAttendance
。它们都有以下控制器(注意它们具有相同的名称)
namespace Modules.AccessControl.UI.Controllers
{
[Route("[module]/[controller]")]
public class AreaController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
}
}
和
namespace Modules.TimeAttendance.UI.Controllers
{
[Route("[module]/[controller]")]
public class AreaController : Controller
{
[HttpGet]
public IActionResult Index()
{
return View();
}
}
}
两者都有相应的视图,称为
Index
:
和
嗯....当我在浏览器中加载此内容时:
https://localhost:44375/TimeAttendance/Area
,执行了正确的Index
操作(来自Modules.TimeAttendance.UI
程序集),但是,正在尝试查看来自Modules.AccessControl.UI
的视图。
关于这个我知道两件事:
return View()
AccessControl
模块是第一个要加载的程序集(模块),我认为这就是显示该程序集视图的原因。默认调用
return View()
时,有没有办法使用完整的程序集来寻址视图?
我之前在 Swagger 中也遇到过同样的问题,但是,我可以设置使用完整的程序集名称。我希望在解决正确的观点时我也能这样做。
编辑:
我创建了一个自定义
IViewLocationExpander
来修改视图搜索路径。现在显示此错误:
如何使用完整路径来寻址视图?我也尝试过
/Modules.TimeAttendance.UI/Views/Area/Index.cshtml
,但也没有用。
编辑2:路由
public class Module(string routePrefix, IModuleStartup startup)
{
/// <summary>
/// Gets the route prefix to all controller and endpoints in the module.
/// </summary>
public string RoutePrefix { get; } = routePrefix;
/// <summary>
/// Gets the startup class of the module.
/// </summary>
public IModuleStartup Startup { get; } = startup;
/// <summary>
/// Gets the assembly of the module.
/// </summary>
public Assembly Assembly => Startup.GetType().Assembly;
}
public class ModuleRoutingConvention(IEnumerable<Module> modules) : IActionModelConvention
{
private readonly IEnumerable<Module> _modules = modules;
public void Apply(ActionModel action)
{
var module = _modules.FirstOrDefault(m => action.Controller.ControllerType.Assembly.FullName?.StartsWith($"Modules.{m.RoutePrefix}") ?? false);
if (module == null)
{
return;
}
action.RouteValues.Add("module", module.RoutePrefix);
}
}
public class ModuleRoutingMvcOptionsPostConfigure : IPostConfigureOptions<MvcOptions>
{
private readonly IEnumerable<Module> _modules;
public ModuleRoutingMvcOptionsPostConfigure(IEnumerable<Module> modules)
{
_modules = modules;
}
public void PostConfigure(string? name, MvcOptions options)
{
options.Conventions.Add(new ModuleRoutingConvention(_modules));
}
}
/// <summary>
/// Adds a module.
/// </summary>
/// <param name="services"></param>
/// <param name="routePrefix">The prefix of the routes to the module.</param>
/// <typeparam name="TStartup">The type of the startup class of the module.</typeparam>
/// <returns></returns>
public static class ModuleServiceCollection
{
/// <summary>
/// Adds a module.
/// </summary>
/// <param name="services"></param>
/// <param name="routePrefix">The prefix of the routes to the module.</param>
/// <typeparam name="TStartup">The type of the startup class of the module.</typeparam>
/// <returns></returns>
public static IServiceCollection AddModule<TStartup>(this IServiceCollection services, string routePrefix, IConfiguration configuration)
where TStartup : IModuleStartup, new()
{
// Register assembly in MVC so it can find controllers of the module
services.AddControllers().ConfigureApplicationPartManager(manager =>
manager.ApplicationParts.Add(new AssemblyPart(typeof(TStartup).Assembly)));
var startup = new TStartup();
startup.ConfigureServices(services, configuration);
services.AddSingleton(new Module(routePrefix, startup));
return services;
}
}