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

时间:2018-03-20 07:25:37

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

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

此应用已配置域 domainA.com

我的应用中有一条路线,例如 domainA.com/route 。 现在我想将其他域仅限于此路由,例如 domainB.com

这样做的最佳方式是什么?

3 个答案:

答案 0 :(得分:5)

从ASP.NET Core 3.0开始,并在ASP.NET Core 5.0中提供了持续支持,现在您可以使用新的RequireHost()扩展方法将单个路由定义限制为特定的主机名,如{{3 }}(与问题标题相反,这并非特定于区域)。

因此,要使@ 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的方法中使用的属性路由,则现在可以使用新的(但未记录?)Allow routing to areas by hostname

[Host("domainb.com")]
public DomainController: Controller
{
  … 
}

显然,这不能解决原始问题,该问题是针对ASP.NET Core 2.0的。但是,由于这是一个未公开的功能,因此我想将其留给试图解决ASP.NET Core 3.0+这个问题的人们使用。

答案 1 :(得分:3)

实现此目的的一种方法是使custom route constraint指定每个域名的路由功能。

DomainConstraint

    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中启动它,它将无法使用标准配置。为了便于在不更改配置的情况下进行调试,您可以将域指定为查询字符串参数:

/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") }
);

答案 2 :(得分:3)

对于.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;
        }
    }
} 

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

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