1

Я пытаюсь построить маршрут субдомена «Арендатор», который прикрепляется к области MVC. В этом случае у меня есть зона под названием «Арендатор», которая имеет два контроллера; Public и Admin. Мой пользовательский маршрут используется для захвата субдомена, если он соответствует, а затем перенаправляет их в надлежащую область действия контроллера.Субдомен пользовательской маршрутизации MVC

Основа этого проекта возникла из следующего http://www.matrichard.com/post/asp.net-mvc-5-routing-with-subdomain

Проблема у меня есть в обычае Subdomain маршрута. Когда я попал в маршрут Public/Index, routeData возвращает значение null, и я вижу следующую ошибку. Хотя если маршрут /admin, он возвращает правильный routeData.

Ошибка сервера в приложении «/».

Соответствующий маршрут не включает в себя значение маршрута «контроллер», которое требуется.

Он также, кажется, всегда подходит с помощью инструмента RouteDebugger, это ключ к моей проблеме?

Примеры Маршруты:

контроллер = Общественное действие = Индекс, площадь = Наниматель

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

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

контроллер действие = Администратор = индекс, площадь = Наниматель

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

адреса URL ниже дает мне следующие результаты RouteDebugger. Во время испытаний 1 и 2 маршрут по-прежнему соответствует/admin.

Неудачные Тест 1: http://tenant.mydomain.com/

Ошибка Тест 2: http://tenant.mydomain.com/logon

Успешное 3: http://tenant.mydomain.com/admin

Похожее Url Defaults

Правдаadmin/{action}/{id}controller = Admin, action = Index

Правда{controller}/{action}/{id}controller = Public, action = Index

+0

Я также посмотрел на это сообщение, но он имеет жестко закодированные маршруты, когда мне действительно нужны значения по умолчанию. http://stackoverflow.com/questions/278668/is-it-possible-to-make-an-asp-net-mvc-route-based-on-a-subdomain/15287579#15287579 – phanf

ответ

1

Сообщение, что вы связаны есть ошибка: Когда ограничение или URL не совпадает, метод base.GetRouteData будет возвращать null. В этом случае добавление имени поддомена в словарь маршрута, очевидно, вызовет исключение. Перед этой строкой должно быть предложение null guard.

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; 
} 

Как и в случае с вашим маршрутом. Вы должны убедиться, что вы возвращаете значение null в случае, когда базовый класс возвращает null (что указывает, что URL-адрес или ограничение не совпадают, и нам нужно пропустить обработку этого маршрута).

Кроме того, я не уверен, что это имеет значение, чем добавление данных непосредственно к DataTokens, но структура MVC имеет 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}", иначе у вас никогда не будет случая, который пройдет до маршрута по умолчанию. Или вы можете использовать явный сегмент в URL-адресе, чтобы вы могли его отличить (так же, как и с вашим маршрутом администратора).

routes.Add("Admin_Subdomain", new SubdomainRouteP(
    "Tenant", 
    "admin/{action}/{id}", 
    new { controller = "Admin", action = "Index", id = UrlParameter.Optional })); 

routes.Add("Public_Subdomain", new SubdomainRouteP(
    "Tenant", 
    "public/{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 }); 

Другим вариантом было бы добавить еще один параметр конструктора для передачи в явном списке допустимых доменов для проверки.

+0

- NightOwl888, Спасибо за ваш ответ, я изменил исходный код, как вы предложили, и он работает отлично! Я включил параметр области IRouteWithArea', это будет полезно позже в проекте. Меня также смутил дополнительный параметр 'domain' из ссылки matrichard. Спасибо за вашу помощь. Я отметил это как решение. – phanf

Смежные вопросы