如何在 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 核心应用程序中处理此类请求并映射到具有操作 Profile
的 UserController
以 username
作为参数和 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();
}
}
UPDATE(在开发环境中使用本地主机的路由)
在开发环境中为本地主机使用此类路由有两种选择:
第一个完全模拟生产环境中的子域 URLs。要使其工作,您应该配置您的主机文件,以便 john.myexample.com
指向 127.0.0.1
并使您的 ASP.NET 核心应用程序接受对此类主机的请求。在这种情况下,您不需要对路由进行任何额外的调整,因为请求将具有与生产中相同的 URLs(只是添加了端口):http://john.myexample.com:12345/。
如果你想保持简单并使用指向本地主机的常规开发 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
操作。
假设我的应用程序 URL 是 myexample.com
,myexample.com 有用户 john
他有一个 public 个人资料 link john.myexample.com
如何在 ASP.NET 核心应用程序中处理此类请求并映射到具有操作 Profile
的 UserController
以 username
作为参数和 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();
}
}
UPDATE(在开发环境中使用本地主机的路由)
在开发环境中为本地主机使用此类路由有两种选择:
第一个完全模拟生产环境中的子域 URLs。要使其工作,您应该配置您的主机文件,以便
john.myexample.com
指向127.0.0.1
并使您的 ASP.NET 核心应用程序接受对此类主机的请求。在这种情况下,您不需要对路由进行任何额外的调整,因为请求将具有与生产中相同的 URLs(只是添加了端口):http://john.myexample.com:12345/。如果你想保持简单并使用指向本地主机的常规开发 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
操作。