我有一个 ASP.NET Core 2.0 应用程序,托管在 Azure 应用程序服务上。
该应用程序绑定到 domainA.com
. 我的应用里有一条路线--比如。domainA.com/route
.
现在,我想引入另一个域,但只让它响应一个不同的路由--例如。domainB.com
.
最好的方法是什么?
实现这一目标的一种方法是在应用程序中创建一个 自定义路线约束 来指定每个域名的路由功能。
public class DomainConstraint : IRouteConstraint
{
private readonly string[] domains;
public DomainConstraint(params string[] domains)
{
this.domains = domains ?? throw new ArgumentNullException(nameof(domains));
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
string domain =
#if DEBUG
// A domain specified as a query parameter takes precedence
// over the hostname (in debug compile only).
// This allows for testing without configuring IIS with a
// static IP or editing the local hosts file.
httpContext.Request.Query["domain"];
#else
null;
#endif
if (string.IsNullOrEmpty(domain))
domain = httpContext.Request.Host.Host;
return domains.Contains(domain);
}
}
app.UseMvc(routes =>
{
routes.MapRoute(
name: "DomainA",
template: "route",
defaults: new { controller = "DomainA", action = "Route" },
constraints: new { _ = new DomainConstraint("domaina.com") });
routes.MapRoute(
name: "DomainB",
template: "route",
defaults: new { controller = "DomainB", action = "Route" },
constraints: new { _ = new DomainConstraint("domainb.com") });
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
需要注意的是,如果你在Visual Studio中启动这个功能,就无法使用标准配置。为了在不改变配置的情况下方便调试,你可以用域名指定URL作为查询字符串参数。
/route?domain=domaina.com
这只是为了让你不必重新配置IIS和你的本地主机文件来调试(尽管你仍然可以,如果你喜欢这种方式)。在一个 Release
构建这个功能已被删除,因此它将只与 实际 生产中的域名。
由于路由响应于 所有域名 默认情况下,只有当你有大量的功能在域间共享时,这样做才有意义。如果没有,最好为每个域设置单独的区域。
routes.MapRoute(
name: "DomainA",
template: "{controller=Home}/{action=Index}/{id?}",
defaults: new { area = "DomainA" },
constraints: new { _ = new DomainConstraint("domaina.com") }
);
routes.MapRoute(
name: "DomainA",
template: "{controller=Home}/{action=Index}/{id?}",
defaults: new { area = "DomainB" },
constraints: new { _ = new DomainConstraint("domainb.com") }
);
对于.net Core MVC,你可以创建一个新的IRouteConstraint和一个RouteAttribute。
=> IRouteConstraint.cs
using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
namespace Microsoft.AspNetCore.Routing
{
public class ConstraintHost : IRouteConstraint
{
public string _value { get; private set; }
public ConstraintHost(string value)
{
_value = value;
}
public bool Match(HttpContext httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
string hostURL = httpContext.Request.Host.ToString();
if (hostURL == _value)
{
return true;
}
//}
return false;
//return hostURL.IndexOf(_value, StringComparison.OrdinalIgnoreCase) >= 0;
}
public bool Match(HttpContext httpContext, IRouter route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
{
throw new NotImplementedException();
}
}
public class ConstraintHostRouteAttribute : RouteAttribute
{
public ConstraintHostRouteAttribute(string template, string sitePermitted)
: base(template)
{
SitePermitted = sitePermitted;
}
public RouteValueDictionary Constraints
{
get
{
var constraints = new RouteValueDictionary();
constraints.Add("host", new ConstraintHost(SitePermitted));
return constraints;
}
}
public string SitePermitted
{
get;
private set;
}
}
}
而在你的Controller中可以这样使用。
[ConstraintHostRoute("myroute1/xxx", "domaina.com")]
[ConstraintHostRoute("myroute2/yyy", "domainb.com")]
public async Task<ActionResult> MyController()
{
return View();
}
在ASP.NET Core 3.0中,你现在可以通过使用新的定义来将单个路由定义限制为特定的主机名。RequireHost()
扩展方法,如在 允许通过主机名进行区域路由选择 与问题标题相反,这并不是特定的区域)。
所以,为了适应@nightowl888在接受的答案中的例子,你现在可以在不定义自定义的情况下实现同样的结果。IRouteConstraint
:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "DomainA",
template: "route",
defaults: new { controller = "DomainA", action = "Route" }
).RequireHost("domaina.com");
routes.MapRoute(
name: "DomainB",
template: "route",
defaults: new { controller = "DomainB", action = "Route" }
).RequireHost("domainb.com");
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}"
);
});
另外,如果你喜欢属性路由,就像@yanga的方法一样,你现在可以使用新的(但未被记录?HostAttribute
:
[Host("domainb.com")]
public DomainController: Controller
{
…
}
很明显,这并没有解决最初的问题,那是针对ASP.NET Core 2.0的。然而,由于这是一个未被记录的功能,我想把它留在这里,以便人们试图为ASP.NET Core 3.0+解决这个问题。