同一应用程序ASP.NET Core 2.0中的不同域

Nor*_*isz 7 c# asp.net-core asp.net-core-routing

我在Azure Web应用程序中托管了ASP.NET Core 2.0应用程序。

此应用已配置域domainA.com

我的应用程序中有一条路由,例如domainA.com/route。现在,我只想将其他域固定到该路由,例如domainB.com

做这个的最好方式是什么?

Yan*_*nga 6

对于 .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;
        }
    }
} 
Run Code Online (Sandbox Code Playgroud)

在你的控制器中可以这样使用它:

    [ConstraintHostRoute("myroute1/xxx", "domaina.com")]
    [ConstraintHostRoute("myroute2/yyy", "domainb.com")]
    public async Task<ActionResult> MyController()
    {
      return View();
    }
Run Code Online (Sandbox Code Playgroud)


Jer*_*ney 6

从 ASP.NET Core 3.0 开始,随着 ASP.NET Core 5.0 和 6.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?}"
  );

});
Run Code Online (Sandbox Code Playgroud)

或者,如果您更喜欢@yanga 方法中使用的属性路由,您现在可以使用新的(但未记录?)HostAttribute

[Host("domainb.com")]
public DomainController: Controller
{
  … 
}
Run Code Online (Sandbox Code Playgroud)

显然,这并没有解决最初的问题,即针对 ASP.NET Core 2.0。但是,由于这是一个未(未)记录的功能,因此我想将它留在这里供人们尝试为 ASP.NET Core 3.0+ 解决此问题。


Nig*_*888 5

实现此目的的一种方法是创建自定义路由约束,以指定每个域名的路由功能。

域约束

    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);
        }
    }
Run Code Online (Sandbox Code Playgroud)

用法

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?}");
});
Run Code Online (Sandbox Code Playgroud)

请注意,如果您在Visual Studio中启动此功能,则无法使用标准配置。为了便于调试而无需更改配置,可以将带有域的URL指定为查询字符串参数:

/route?domain=domaina.com
Run Code Online (Sandbox Code Playgroud)

这样做是为了您不必重新配置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") }
);
Run Code Online (Sandbox Code Playgroud)