有没有可能有一个ASP。NET MVC路由,使用子域信息来确定它的路由?例如:

user1.domain。例子只有一个 user2.domain。例子指向另一个?

或者,我可以让这两个都去到相同的控制器/动作与用户名参数?


当前回答

为了在使用Web API时捕获子域,重写Action Selector以注入子域查询参数。然后在控制器的动作中使用子域查询参数,如下所示:

public string Get(string id, string subdomain)

这种方法使调试更加方便,因为当使用localhost而不是实际的主机名时,可以手动指定查询参数(有关详细信息,请参阅标准MVC5路由答案)。这是动作选择器的代码:

class SubdomainActionSelector : IHttpActionSelector
{
    private readonly IHttpActionSelector defaultSelector;

    public SubdomainActionSelector(IHttpActionSelector defaultSelector)
    {
        this.defaultSelector = defaultSelector;
    }

    public ILookup<string, HttpActionDescriptor> GetActionMapping(HttpControllerDescriptor controllerDescriptor)
    {
        return defaultSelector.GetActionMapping(controllerDescriptor);
    }

    public HttpActionDescriptor SelectAction(HttpControllerContext controllerContext)
    {
        var routeValues = controllerContext.Request.GetRouteData().Values;
        if (!routeValues.ContainsKey("subdomain")) {
            string host = controllerContext.Request.Headers.Host;
            int index = host.IndexOf('.');
            if (index >= 0)
                controllerContext.Request.GetRouteData().Values.Add("subdomain", host.Substring(0, index));
        }
        return defaultSelector.SelectAction(controllerContext);
    }
}

通过将其添加到WebApiConfig来替换默认的动作选择器。注册:

config.Services.Replace(typeof(IHttpActionSelector), new SubdomainActionSelector(config.Services.GetActionSelector()));

其他回答

要在保留标准MVC5路由特性的同时捕获子域,请使用以下从Route派生的SubdomainRoute类。

此外,SubdomainRoute允许将子域可选地指定为查询参数,使sub.example.com/foo/bar和example.com/foo/bar?subdomain=sub等效。这允许您在配置DNS子域之前进行测试。查询参数(在使用时)通过Url生成的新链接传播。行动等。

查询参数还可以使用Visual Studio 2013进行本地调试,而无需使用netsh进行配置或以管理员身份运行。默认情况下,IIS Express只在未提升时绑定到本地主机;它不会绑定到像sub.localtest.me这样的同义主机名。

class SubdomainRoute : Route
{
    public SubdomainRoute(string url) : base(url, new MvcRouteHandler()) {}

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var routeData = base.GetRouteData(httpContext);
        if (routeData == null) return null; // Only look at the subdomain if this route matches in the first place.
        string subdomain = httpContext.Request.Params["subdomain"]; // A subdomain specified as a query parameter takes precedence over the hostname.
        if (subdomain == null) {
            string host = httpContext.Request.Headers["Host"];
            int index = host.IndexOf('.');
            if (index >= 0)
                subdomain = host.Substring(0, index);
        }
        if (subdomain != null)
            routeData.Values["subdomain"] = subdomain;
        return routeData;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        object subdomainParam = requestContext.HttpContext.Request.Params["subdomain"];
        if (subdomainParam != null)
            values["subdomain"] = subdomainParam;
        return base.GetVirtualPath(requestContext, values);
    }
}

为了方便起见,从你的RegisterRoutes方法中调用下面的MapSubdomainRoute方法,就像你将普通的MapRoute一样:

static void MapSubdomainRoute(this RouteCollection routes, string name, string url, object defaults = null, object constraints = null)
{
    routes.Add(name, new SubdomainRoute(url) {
        Defaults = new RouteValueDictionary(defaults),
        Constraints = new RouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary()
    });
}

最后,为了方便地访问子域(从真正的子域或查询参数),创建一个具有这个subdomain属性的Controller基类是很有帮助的:

protected string Subdomain
{
    get { return (string)Request.RequestContext.RouteData.Values["subdomain"]; }
}

这不是我的工作,但我必须把它加到这个答案上。

这里有一个解决这个问题的好办法。martin Balliauw编写了创建DomainRoute类的代码,该类可以与正常的路由使用非常相似。

http://blog.maartenballiauw.be/post/2009/05/20/ASPNET-MVC-Domain-Routing.aspx

示例使用如下所示……

routes.Add("DomainRoute", new DomainRoute( 
    "{customer}.example.com", // Domain with parameters 
    "{action}/{id}",    // URL with parameters 
    new { controller = "Home", action = "Index", id = "" }  // Parameter defaults 
))

;

几个月前,我开发了一个属性,将方法或控制器限制在特定的域。

它很容易使用:

[IsDomain("localhost","example.com","www.example.com","*.t1.example.com")]
[HttpGet("RestrictedByHost")]
public IActionResult Test(){}

也可以直接应用到控制器上。

public class IsDomainAttribute : Attribute, Microsoft.AspNetCore.Mvc.Filters.IAuthorizationFilter
{

    public IsDomainAttribute(params string[]  domains)
    {
        Domains = domains;
    }

    public string[] Domains { get; }

    public void OnAuthorization(AuthorizationFilterContext context)
    {
        var host = context.HttpContext.Request.Host.Host;
        if (Domains.Contains(host))
            return;
        if (Domains.Any(d => d.EndsWith("*"))
                && Domains.Any(d => host.StartsWith(d.Substring(0, d.Length - 1))))
            return;
        if (Domains.Any(d => d.StartsWith("*"))
                && Domains.Any(d => host.EndsWith(d.Substring(1))))
            return;

        context.Result = new Microsoft.AspNetCore.Mvc.NotFoundResult();//.ChallengeResult
    }
}

限制: 你可能不能在不同的过滤器的不同方法上有两个相同的路由 我的意思是下面可能会抛出重复路由的异常:

[IsDomain("test1.example.com")]
[HttpGet("/Test")]
public IActionResult Test1(){}

[IsDomain("test2.example.com")]
[HttpGet("/Test")]
public IActionResult Test2(){}

你可以通过创建一个新路由并将其添加到global.asax中的RegisterRoutes中的routes集合来实现。下面是一个自定义路由的简单例子:

public class ExampleRoute : RouteBase
{

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var url = httpContext.Request.Headers["HOST"];
        var index = url.IndexOf(".");

        if (index < 0)
            return null;

        var subDomain = url.Substring(0, index);

        if (subDomain == "user1")
        {
            var routeData = new RouteData(this, new MvcRouteHandler());
            routeData.Values.Add("controller", "User1"); //Goes to the User1Controller class
            routeData.Values.Add("action", "Index"); //Goes to the Index action on the User1Controller

            return routeData;
        }

        if (subDomain == "user2")
        {
            var routeData = new RouteData(this, new MvcRouteHandler());
            routeData.Values.Add("controller", "User2"); //Goes to the User2Controller class
            routeData.Values.Add("action", "Index"); //Goes to the Index action on the User2Controller

            return routeData;
        }

        return null;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        //Implement your formating Url formating here
        return null;
    }
}

是的,但是你必须创建你自己的路由处理器。

通常情况下,路由不知道域,因为应用程序可以部署到任何域,路由不会关心这种或那种方式。但在你的情况下,你想要基于域的控制器和动作,所以你必须创建一个自定义路由,它可以感知域。