You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用AddApplicationPart注册控制器时如何配置Area区域?

实现无[Area]特性的控制器区域配置

要实现无需在控制器上标记[Area]特性即可灵活配置所属区域(包括多区域),可以通过**自定义控制器模型约定(IControllerModelConvention)**结合配置驱动的方式来实现,以下是具体步骤:

1. 定义配置结构

首先在appsettings.json中添加模块的区域-控制器映射配置,支持一个控制器关联多个区域:

"Modules": {
  "MyModule": {
    "ApplicationParts": ["MyModule.Controllers.dll"],
    "AreaMappings": [
      {
        "AreaName": "MyArea",
        "ControllerNames": ["UserController"]
      },
      {
        "AreaName": "AnotherArea",
        "ControllerNames": ["UserController"]
      }
    ]
  }
}

然后创建对应的配置模型类,用于绑定配置:

public class AreaMappingConfig
{
    public string AreaName { get; set; }
    public List<string> ControllerNames { get; set; } = new();
}

public class MyModuleConfig
{
    public List<string> ApplicationParts { get; set; } = new();
    public List<AreaMappingConfig> AreaMappings { get; set; } = new();
}

2. 自定义控制器模型约定

实现IControllerModelConvention,在控制器初始化时根据配置自动添加区域元数据(模拟[Area]特性的作用):

public class ConfigurableAreaConvention : IControllerModelConvention
{
    private readonly List<AreaMappingConfig> _areaMappings;

    public ConfigurableAreaConvention(List<AreaMappingConfig> areaMappings)
    {
        _areaMappings = areaMappings;
    }

    public void Apply(ControllerModel controller)
    {
        foreach (var mapping in _areaMappings)
        {
            if (mapping.ControllerNames.Contains(controller.ControllerName))
            {
                // 为匹配的控制器添加Area特性,支持多区域关联
                controller.Attributes.Add(new AreaAttribute(mapping.AreaName));
            }
        }
    }
}

3. 修改模块注册逻辑

更新MyModule的RegisterModule方法,读取配置并注入自定义约定:

public class MyModule : IModule
{
    public IServiceCollection RegisterModule(IServiceCollection services)
    {
        var configuration = AppSettingsHelper.Configuration;
        if (configuration == null) return services;

        // 绑定模块配置
        var moduleConfig = configuration.GetSection("Modules:MyModule").Get<MyModuleConfig>();
        if (moduleConfig == null) return services;

        foreach (var assemblyFileName in moduleConfig.ApplicationParts)
        {
            var moduleAssembly = AppDomain.CurrentDomain
                .GetAssemblies()
                .FirstOrDefault(a => a.FullName == Path.GetFileName(assemblyFileName));

            if (moduleAssembly == null && !string.IsNullOrEmpty(assemblyFileName))
            {
                moduleAssembly = Assembly.LoadFrom(assemblyFileName);
            }

            if (moduleAssembly != null)
            {
                services.AddMvcCore()
                    .AddApplicationPart(moduleAssembly)
                    .AddControllersAsServices()
                    .AddMvcOptions(options =>
                    {
                        // 添加自定义区域约定
                        options.Conventions.Add(new ConfigurableAreaConvention(moduleConfig.AreaMappings));
                    });
            }
        }

        return services;
    }

    public IEndpointRouteBuilder MapEndpoints(IEndpointRouteBuilder endpoints)
    {
        var moduleConfig = AppSettingsHelper.Configuration.GetSection("Modules:MyModule").Get<MyModuleConfig>();
        if (moduleConfig != null)
        {
            // 为每个配置的区域注册路由
            foreach (var areaMapping in moduleConfig.AreaMappings)
            {
                endpoints.MapAreaControllerRoute(
                    areaName: areaMapping.AreaName,
                    name: areaMapping.AreaName,
                    pattern: $"{areaMapping.AreaName}/{{controller}}/{{action}}"
                );
            }
        }

        return endpoints;
    }
}

4. 简化控制器代码

移除控制器上的[Area]特性,调整路由模板让区域前缀自动拼接:

[ApiController]
[Route("{controller}")]
public class UserController : ControllerBase
{
    [HttpGet("{id}")]
    public IActionResult GetById([FromRoute]int id, [FromBody] UserMode user)
    {
        return Ok();
    }

    [HttpGet]
    public IActionResult GetAll()
    {
        return Ok();
    }
}

关键说明

  • 该方案通过配置文件灵活控制控制器与区域的关联,无需修改控制器代码
  • 支持单个控制器关联多个区域,每个区域对应独立的路由访问路径(如MyArea/User/GetById和AnotherArea/User/GetById)
  • 自定义约定完全贴合ASP.NET Core的路由机制,无需额外修改路由核心逻辑

内容的提问来源于stack exchange,提问作者Colin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 03:07:49