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

如何通过Application Parts复用页面与控制器并配置独立子路由?

复用外部程序集资源并隔离路由的实现方案

核心思路

通过自定义路由约定给外部程序集的控制器、Razor Pages统一添加/legacy路由前缀,同时单独映射其wwwroot资源,彻底隔离原有应用与外部资源的命名冲突。


1. 控制器路由隔离

给外部程序集的所有控制器强制加上/legacy前缀,避免与原有控制器路由冲突。

自定义控制器路由约定

public class LegacyControllerRouteConvention : IApplicationModelConvention
{
    private readonly string _legacyAssemblyName;
    private readonly string _routePrefix;

    public LegacyControllerRouteConvention(string legacyAssemblyName, string routePrefix)
    {
        _legacyAssemblyName = legacyAssemblyName;
        _routePrefix = routePrefix.StartsWith("/") ? routePrefix : $"/{routePrefix}";
    }

    public void Apply(ApplicationModel application)
    {
        foreach (var controller in application.Controllers)
        {
            // 仅处理目标程序集的控制器
            if (controller.ControllerType.Assembly.GetName().Name == _legacyAssemblyName)
            {
                // 清除原有路由规则,避免冲突
                controller.Selectors.Clear();
                // 添加带前缀的新路由
                controller.Selectors.Add(new SelectorModel
                {
                    AttributeRouteModel = new AttributeRouteModel
                    {
                        Template = $"{_routePrefix}/[controller]/[action]"
                    }
                });
            }
        }
    }
}

在Program.cs中注册

// 加载外部程序集(替换为你的Legacy控制器所在类型)
var legacyAssembly = typeof(LegacyProject.HomeController).Assembly;

builder.Services.AddControllersWithViews()
    .AddApplicationPart(legacyAssembly) // 引入外部程序集
    .AddMvcOptions(options =>
    {
        // 添加路由约定
        options.Conventions.Add(new LegacyControllerRouteConvention(legacyAssembly.GetName().Name, "legacy"));
    });

2. Razor Pages路由隔离

同理,给外部程序集的Razor Pages统一添加/legacy前缀,并处理布局冲突。

自定义Page路由约定

public class LegacyPageRouteConvention : IPageRouteModelConvention
{
    private readonly string _legacyAssemblyName;
    private readonly string _routePrefix;

    public LegacyPageRouteConvention(string legacyAssemblyName, string routePrefix)
    {
        _legacyAssemblyName = legacyAssemblyName;
        _routePrefix = routePrefix.StartsWith("/") ? routePrefix : $"/{routePrefix}";
    }

    public void Apply(PageRouteModel model)
    {
        if (model.PageType.Assembly.GetName().Name == _legacyAssemblyName)
        {
            // 修改路由前缀
            var originalTemplate = model.Selectors[0].AttributeRouteModel.Template;
            model.Selectors[0].AttributeRouteModel.Template = $"{_legacyAssemblyName}/{originalTemplate}";
            
            // 强制使用外部程序集的专属布局,解决_Layout命名冲突
            model.ViewData["Layout"] = "/Legacy/Shared/_Layout.cshtml";
        }
    }
}

在Program.cs中注册

builder.Services.AddRazorPages()
    .AddApplicationPart(legacyAssembly)
    .AddRazorPagesOptions(options =>
    {
        options.Conventions.Add(new LegacyPageRouteConvention(legacyAssembly.GetName().Name, "legacy"));
        // 可选:设置legacy页面的默认路由(访问/legacy时指向外部程序集的Index页)
        options.Conventions.AddPageRoute("/Legacy/Index", "legacy");
        // 添加视图查找路径,确保能找到外部程序集的页面
        options.RootDirectory = "/Pages";
    });

3. wwwroot资源隔离

将外部程序集的静态资源映射到/legacy/static路径下,避免与原有wwwroot资源冲突。

第一步:配置外部程序集的嵌入式资源

在外部程序集的csproj文件中添加以下配置,将wwwroot内容打包为嵌入式资源:

<ItemGroup>
    <EmbeddedResource Include="wwwroot/**/*" />
</ItemGroup>

第二步:在现有项目中映射静态资源

// 注册嵌入式文件提供器
builder.Services.AddSingleton<IFileProvider>(
    new EmbeddedFileProvider(legacyAssembly, $"{legacyAssembly.GetName().Name}.wwwroot")
);

// 映射静态资源到/legacy/static路径
app.UseStaticFiles(new StaticFileOptions
{
    RequestPath = "/legacy/static",
    FileProvider = new EmbeddedFileProvider(legacyAssembly, $"{legacyAssembly.GetName().Name}.wwwroot")
});

之后外部程序集的wwwroot/css/site.css即可通过/legacy/static/css/site.css访问。


4. 关键注意点

  • 如果外部程序集的控制器/页面带有自定义路由属性,建议清除原有路由规则(如示例中controller.Selectors.Clear()),避免同时存在根路由和前缀路由。
  • 布局冲突可通过约定强制指定专属布局,或在外部程序集的页面中直接修改Layout属性。
  • 若外部程序集使用了区域(Area),需在路由约定中额外处理区域前缀。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 00:54:59