如何在 ASP.NET Core 中处理路由请求 "john.myexample.com"

How to handle routing request "john.myexample.com" in ASP.NET Core

假设我的应用程序 URL 是 myexample.com,myexample.com 有用户 john 他有一个 public 个人资料 link john.myexample.com 如何在 ASP.NET 核心应用程序中处理此类请求并映射到具有操作 ProfileUserControllerusername 作为参数和 returns Johns 配置文件.

routes.MapRoute(
                name: "user_profile",
                template: "{controller=User}/{action=Profile}/{username}");

Built-in ASP.NET Core Routing 不提供请求子域的任何模板。这就是为什么你需要实现自定义路由器来覆盖这种情况。

实施将非常简单。您应该解析传入请求的主机名以检查它是否是配置文件子域。如果是这样,你在路由数据中填写控制器、动作和用户名。

这是一个工作示例:

路由器实现:

public class SubdomainRouter : IRouter
{
    private readonly Regex hostRegex = new Regex(@"^(.+?)\.(.+)$", RegexOptions.Compiled);

    private readonly IRouter defaultRouter;
    private readonly string domain;
    private readonly string controllerName;
    private readonly string actionName;

    public SubdomainRouter(IRouter defaultRouter, string domain, string controllerName, string actionName)
    {
        this.defaultRouter = defaultRouter;
        this.domain = domain;
        this.controllerName = controllerName;
        this.actionName = actionName;
    }

    public async Task RouteAsync(RouteContext context)
    {
        var request = context.HttpContext.Request;
        var hostname = request.Host.Host;

        var match = hostRegex.Match(hostname);
        if (match.Success && String.Equals(match.Groups[2].Value, domain, StringComparison.OrdinalIgnoreCase))
        {
            var routeData = new RouteData();
            routeData.Values["controller"] = controllerName;
            routeData.Values["action"] = actionName;
            routeData.Values["username"] = match.Groups[1].Value;

            context.RouteData = routeData;
            await defaultRouter.RouteAsync(context);
        }
    }

    public VirtualPathData GetVirtualPath(VirtualPathContext context)
    {
        return defaultRouter.GetVirtualPath(context);
    }
}

在Startup.Configure()中注册:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMvc(routes =>
    {
        routes.Routes.Add(new SubdomainRouter(routes.DefaultHandler, "myexample.com", "User", "Profile"));

        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
}

示例控制器:

public class UserController : Controller
{
    [HttpGet]
    public IActionResult Profile(string username)
    {
        return Ok();
    }
}

Sample Project on GitHub

UPDATE(在开发环境中使用本地主机的路由)

在开发环境中为本地主机使用此类路由有两种选择:

  1. 第一个完全模拟生产环境中的子域 URLs。要使其工作,您应该配置您的主机文件,以便 john.myexample.com 指向 127.0.0.1 并使您的 ASP.NET 核心应用程序接受对此类主机的请求。在这种情况下,您不需要对路由进行任何额外的调整,因为请求将具有与生产中相同的 URLs(只是添加了端口):http://john.myexample.com:12345/

  2. 如果你想保持简单并使用指向本地主机的常规开发 URLs,你应该绕过描述的 SubdomainRouter(因为它解析子域,这将不起作用对于 localhost) 并使用通常的 ASP.NET 核心路由。这是针对这种情况调整的路由配置:

    app.UseMvc(routes =>
    {
        if (env.IsDevelopment())
        {
            routes.MapRoute(
                name: "user-profile",
                template: "profiles/{username}",
                defaults: new { controller = "User", action = "Profile" });
        }
        else
        {
            routes.Routes.Add(new SubdomainRouter(routes.DefaultHandler, "myexample.com", "User", "Profile"));
        }
    
        routes.MapRoute(
            name: "default",
            template: "{controller=Home}/{action=Index}/{id?}");
    });
    

    现在,如果您像 http://localhost:12345/profiles/john 一样向 URL 发送请求,将使用正确的用户名调用 UserController.Profile 操作。