MVC自定义路由子域

时间:2016-02-16 19:37:27

标签: asp.net-mvc asp.net-mvc-4 url-routing asp.net-mvc-routing routeconfig

我正在尝试构建一个附加到MVC区域的“租户”子域路由。在这种情况下,我有一个名为“租户”的区域,它有两个控制器;公共和管理员。我的自定义Route用于获取Subdomain(如果匹配),然后将它们路由到正确的Controller-Action-Area。

该项目的基础来自以下内容 http://www.matrichard.com/post/asp.net-mvc-5-routing-with-subdomain

我遇到的问题是在自定义子域路由中。当我点击Public/Index路由时,routeData返回null,我看到以下错误。虽然路线是/admin,但它会返回正确的routeData

  应用程序中的服务器错误。

     

匹配的路线不包含“控制器”路线值,这是必需的。

它似乎总是使用RouteDebugger工具匹配,这是我的问题的线索吗?

示例路线:

controller = Public action = Index,area = Tenant

http://tenant1.mydomain.com:8080/

http://tenant1.mydomain.com:8080/logon

controller =管理员操作=索引,区域=租户

http://tenant1.mydomain.com:8080/admin

http://tenant1.mydomain.com:8080/admin/edit

-

SubdomainRouteP.cs

public class SubdomainRouteP : Route
{
    public string Domain { get; set; }

    public SubdomainRouteP(string domain, string url, RouteValueDictionary defaults): this(domain, url, defaults, new MvcRouteHandler())
    {
    }

    public SubdomainRouteP(string domain, string url, object defaults): this(domain, url, new RouteValueDictionary(defaults), new MvcRouteHandler())
    {
    }

    public SubdomainRouteP(string domain, string url, object defaults, IRouteHandler routeHandler): this(domain, url, new RouteValueDictionary(defaults), routeHandler)
    {
    }

    public SubdomainRouteP(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler): base(url, defaults, routeHandler)
    {
        this.Domain = domain;
    }

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        // 
        // routeData object returns null in some cases 
        // 
        var routeData = base.GetRouteData(httpContext);

        var subdomain = httpContext.Request.Url.Host.Split('.').First();

        string[] blacklist = { "www", "mydomain", "localhost" };

        // This will ignore anything that is not a client tenant prefix
        if (blacklist.Contains(subdomain))
        {
            return null; // Continue to the next route
        }

        // Why is this NULL?
        if (routeData == null)
        {

            routeData = new RouteData(this, new MvcRouteHandler());

        }

        routeData.DataTokens["Area"] = "Tenant";
        routeData.DataTokens["UseNamespaceFallback"] = bool.FalseString;
        routeData.Values.Add("subdomain", subdomain);

        // IMPORTANT: Always return null if there is no match.
        // This tells .NET routing to check the next route that is registered.
        return routeData;
    }

}

RouteConfig.cs

        routes.Add("Admin_Subdomain", new SubdomainRouteP(
            "{client}.mydomain.com", //of course this should represent the real intent…like I said throwaway demo project in local IIS
            "admin/{action}/{id}",
            new { controller = "Admin", action = "Index", id = UrlParameter.Optional }));

        routes.Add("Public_Subdomain", new SubdomainRouteP(
            "{client}.mydomain.com", //of course this should represent the real intent…like I said throwaway demo project in local IIS
            "{controller}/{action}/{id}",
            new { controller = "Public", action = "Index", id = UrlParameter.Optional }));

        // This is the MVC default Route
        routes.MapRoute(
            "Default",
            "{controller}/{action}/{id}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional });

以下网址为我提供了RouteDebugger的以下结果。在测试1和2期间,路线仍然匹配/ admin。

测试失败1:http://tenant.mydomain.com/

测试失败2:http://tenant.mydomain.com/logon

成功3:http://tenant.mydomain.com/admin

  

匹配网址默认值

     

真实 admin/{action}/{id} controller = Admin, action = Index

     

真实 {controller}/{action}/{id} controller = Public, action = Index

1 个答案:

答案 0 :(得分:1)

您链接到的帖子有一个错误:当约束或网址不匹配时,<dependentAssembly> <assemblyIdentity name="Newtonsoft.Json" PublicKeyToken="30ad4fe6b2a6aeed" /> <bindingRedirect oldVersion="0.0.0.0-8.0.0.0" newVersion="8.0.0.0"/> </dependentAssembly> 方法将返回base.GetRouteData。在这种情况下,将子域名添加到路由字典中显然会引发异常。在该行之前应该有一个空保护条款。

null

与您的路线一样。您需要确保在基类返回null的情况下返回null(表示URL或约束不匹配,我们需要跳过处理此路由)。

另外,我不确定它是否与将数据直接添加到public override RouteData GetRouteData(HttpContextBase httpContext) { var routeData = base.GetRouteData(httpContext); if (routeData != null) { routeData.Values.Add("client", httpContext.Request.Url.Host.Split('.').First()); } return routeData; } 有什么不同,但MVC框架有DataTokens可以实现以配置路由适用的区域

IRouteWithArea

我无法弄清楚您要对public class SubdomainRouteP : Route, IRouteWithArea { public string Area { get; private set; } public SubdomainRouteP(string area, string url, RouteValueDictionary defaults): this(area, url, defaults, new MvcRouteHandler()) { } public SubdomainRouteP(string area, string url, object defaults): this(area, url, new RouteValueDictionary(defaults), new MvcRouteHandler()) { } public SubdomainRouteP(string area, string url, object defaults, IRouteHandler routeHandler): this(area, url, new RouteValueDictionary(defaults), routeHandler) { } public SubdomainRouteP(string area, string url, RouteValueDictionary defaults, IRouteHandler routeHandler): base(url, defaults, routeHandler) { this.Area = area; } public override RouteData GetRouteData(HttpContextBase httpContext) { var routeData = base.GetRouteData(httpContext); // This will ignore anything where the URL or a constraint doesn't match // in the call to base.GetRouteData(). if (routeData != null) { var subdomain = httpContext.Request.Url.Host.Split('.').First(); string[] blacklist = { "www", "mydomain", "localhost" }; // This will ignore anything that is not a client tenant prefix if (blacklist.Contains(subdomain)) { return null; // Continue to the next route } routeData.DataTokens["UseNamespaceFallback"] = bool.FalseString; routeData.Values.Add("subdomain", subdomain); } // IMPORTANT: Always return null if there is no match. // This tells .NET routing to check the next route that is registered. return routeData; } } 参数做些什么。该网址很可能会返回某些内容。所以,看起来你应该在第一个domain路线中有一个约束,否则你永远不会有一个会传递到默认路线的情况。或者,您可以在URL中使用显式段,以便区分它(与管理路由相同)。

"{controller}/{action}/{id}"

另一种选择是添加另一个构造函数参数以传入要检查的有效域的显式列表。