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

时间:2018-03-23 13:12:38

标签: c# asp.net-core asp.net-core-routing

假设我的应用程序网址为myexample.com,myexample.com有用户john他有一个公开个人资料链接john.myexample.com如何在ASP.NET核心应用程序和地图中处理此类请求到UserController行动Profileusername作为参数和returns Johns个人资料。

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

1 个答案:

答案 0 :(得分:5)

内置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 (在开发环境中使用localhost的路由)

在开发环境中,有两种方法可以将此路由用于localhost:

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

  2. 如果您想保持简单并使用指向localhost的常用开发URL,则应绕过描述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这样的网址发送请求,则会使用正确的用户名调用UserController.Profile操作。