2015-10-01 2 views
1

У меня есть настраиваемая система маршрутизации в моем веб-приложении, где у меня есть база данных с моими маршрутами (url, Controller, Action и еще одна дополнительная информация). Каждый запрос, который делается на сервер, отправляется в базу данных, запрашивает этот маршрут по URL-адресу и возвращает набор, который мне нужно сохранить для будущего рендеринга Filter, Controller и View, я храню эти данные в глобальном var на моем Global.asax файл:C# MVC Routing With RouteBase

public static class GlobalVars 
{ 
    public static Redirect reqContext { get; set; } 
    public static UnidadeHotSite HotSite { get; set; } 
} 

Моя проблема заключается в том, что сейчас эта информация становится смешано через пользователей, иногда, когда я нахожусь в своем браузере и у меня есть 3 открытых вкладок и я обновить их в «почти» то же самое время последнего будет получать данные маршрута предыдущего загруженного.

Например мой HotSite вар сохраняет некоторую Subsite информацию как name, url, ID и т.д., подсайт URL будет: abc.com/subsite. Когда я загружаю первую вкладку, я получаю правильные данные, которые являются данными субсайта, вторая вкладка находится за пределами области подсайта, abc.com, и я получаю те же данные, что и последняя загруженная вкладка.

Теперь, в чем проблема? Я уже использовал NoStore на OutputCache и попытался отключить сеанс, но ничего не работает.

Это мой путь Handler:

[OutputCache(NoStore = true, Duration = 0)] 
public class RouteHandler : MvcRouteHandler 
{ 
    private static string RedirectAction { get; set; } 
    private static string UnidadeURL { get; set; } 

    protected override IHttpHandler GetHttpHandler(RequestContext requestContext) 
    { 
     var friendlyUrl = (string)requestContext.RouteData.Values["RedirectUrl"]; 
     var objRet  = BuscaURL(friendlyUrl, requestContext); 

     GlobalVars.reqContext = objRet[0] as Redirect; 

     return base.GetHttpHandler(objRet[1] as RequestContext); 
    } 

    private static object[] BuscaURL(string pURL, RequestContext reqContext) 
    { 
     RedirectAction = "Index"; 
     var isHotSite = BuscaHotSiteInfo(pURL); 

     var tRedirect = !isHotSite ? BuscaURLWS(pURL) : BuscaURLHS(pURL); 

     if(tRedirect == null || "NotFound".Equals(tRedirect.controller)) 
     { 
      Configuracoes.GeraLog("pURL", pURL); 
      if(tRedirect == null) 
       Configuracoes.GeraLog("tRedirect", "NULL"); 
      else 
       HelperController.GeraLog(tRedirect); 

      tRedirect  = RedirectController.BuscaPaginaPorUrlWS(5); 
      RedirectAction = "Index"; 

      reqContext.RouteData.DataTokens["Namespaces"] = "Site.Controllers"; 
     } 

     if(tRedirect != null && tRedirect.paginaId > 0 && RedirectAction == "Index") 
     { 
      using(var db = new SkillSite()) 
      { 
       var pagina = db.Pagina.First(x => x.ID == tRedirect.paginaId && x.ativo == 1); 
       RedirectAction = pagina.action; 
      } 
     } 

     reqContext.RouteData.Values["controller"] = tRedirect.controller; 
     reqContext.RouteData.Values["action"]  = RedirectAction; 
     reqContext.RouteData.Values["id"]   = tRedirect.ID; 

     return new object[] { tRedirect, reqContext }; 
    } 

    private static Redirect BuscaURLHS(string pUrl) 
    { 
     Redirect redirect = null; 

     pUrl = pUrl.Replace(UnidadeURL, "").Replace("teste", "").TrimStart('/').TrimEnd('/'); 

     if(!string.IsNullOrEmpty(pUrl) && !string.IsNullOrWhiteSpace(pUrl)) 
     { 
      var splitUrl = pUrl.Split('/').ToList(); 

      if(splitUrl.Count > 1) 
      { 
       if("cursos".Equals(splitUrl[0])) 
       { 
        if(splitUrl.Count == 2) 
        { 
         redirect = RedirectController.SearchPageByUrlWS(1, splitUrl[1]); 
        } 
        else if(splitUrl.Count == 3) 
        { 
         redirect = RedirectController.SearchPageByUrlWS(2, splitUrl[1], splitUrl[2]); 
        } 
       } 
      } 
      else 
      { 
       redirect = RedirectController.SearchPageByUrlWS(0, "", "", splitUrl[0]); 
      } 
     } 
     else 
     { 
      redirect = RedirectController.SearchPageByUrlWS(0, "", "", "home"); 
     } 

     return redirect; 
    } 

    private static Redirect BuscaURLWS(string pUrl) 
    { 
     Redirect redirect = null; 

     if(!string.IsNullOrEmpty(pUrl) && !string.IsNullOrWhiteSpace(pUrl)) 
     { 
      var splitUrl = pUrl.TrimEnd('/').Split('/').ToList(); 

      if(splitUrl.Count > 1) 
      { 
       if("cursos".Equals(splitUrl[0])) 
       { 
        if(splitUrl.Count == 2) 
        { 
         redirect = RedirectController.SearchPageByUrlHS(1, splitUrl[1]); 
        } 
        else if(splitUrl.Count == 3) 
        { 
         redirect = RedirectController.SearchPageByUrlHS(2, splitUrl[1], splitUrl[2]); 
        } 
       } 
      } 
      else 
      { 
       redirect = RedirectController.SearchPageByUrlHS(0, "", "", splitUrl[0]); 
      } 
     } 
     else 
     { 
      redirect = RedirectController.SearchPageByUrlHS(0, "", "", "home"); 
     } 

     return redirect; 
    } 
} 

Это контроллер, который делает поисковые запросы на DB

[OutputCache(NoStore = true, Duration = 0)] 
public class RedirectController 
{ 
    public static Redirect SearchPageByUrlWS(int tipo, string cursoCURL = "", string cursoURL = "", string redirectURL = "", string redirectURLTwo = "") 
    { 
     using(var db = new Site()) 
     { 
      IQueryable<Redirect> redirects; 

      if(tipo == 1) 
      { 
       redirects = from redirect in db.Redirect 
          where redirect.url == cursoCURL && redirect.cursoCatId > 0 
          select redirect; 
      } 
      else 
      { 
       redirects = from redirect in db.Redirect 
          where redirect.url == redirectURL && 
          redirect.cursoCatId == 0 && 
          redirect.regulamentoId == 0 && 
          redirect.noticiaId == 0 && 
          redirect.ebookId == 0 && 
          redirect.conhecaId == 0 
          select redirect; 
      } 

      return (redirects.ToList().Count > 0) ? redirects.ToList()[0] : null; 
     } 
    } 

    public static HS_Redirect SearchPageByUrlHS(int tipo, string cursoCURL = "", string cursoURL = "", string redirectURL = "", string redirectURLTwo = "") 
    { 
     using(var dbHS = new HS()) 
     { 
      IQueryable<HS_Redirect> redirects; 

      if(tipo == 4) 
      { 
       redirects = from redirect in dbHS.HS_Redirect 
          where redirect.url == redirectURL && redirect.noticiaId > 0 && redirect.unidadeCE == GlobalVars.HotSite.unidadeHS.unidadeCE 
          select redirect; 
      } 
      else 
      { 
       redirects = from redirect in dbHS.HS_Redirect 
          where 
           redirect.url   == redirectURL && 
           redirect.cursoCatId == 0 && 
           redirect.regulamentoId == 0 && 
           redirect.noticiaId  == 0 && 
           redirect.ebookId  == 0 && 
           redirect.conhecaId  == 0 
          select redirect; 
      } 

      return (redirects.ToList().Count > 0) ? redirects.ToList()[0] : null; 
     } 
    } 
} 

EDIT:

мне удалось сделать @ NightOwl888 ответ работа с областями и всем остальным, что мне нужно, я не собираюсь публиковать это здесь, так как он немного большой, вот вот код: http://pastebin.com/yTdWKMp4

EDIT 2

Я обновил файл на Pastebin с некоторыми изменениями, чтобы улучшить скорость и удобство использования: http://pastebin.com/yTdWKMp4

+0

Используйте словарь 'Session' **, а не статическую глобальную переменную **, чтобы хранить информацию о пользователях. – Jasen

+0

Дело в том, что я не храню информацию пользователя, а информацию о странице, маршруте и контроллере ... они не основаны на пользователе – Terkhos

+0

Каждый запрос перезаписывает статическую глобальную переменную. – Jasen

ответ

1

Есть несколько проблем с вашим подходом:

  1. Никогда не расширяющие MvcRouteHandler сделать пользовательскую схему URL.Маршрутизация URL-адресов - это двухсторонний процесс, и обработчики маршрутов могут обрабатывать только входящие маршруты, но не строить исходящие URL-адреса.
  2. Вы на самом деле не «маршрутизируетесь» здесь. Маршрутизация подразумевает, что вы сопоставляете входящий запрос с ресурсом. То, что вы делаете, позволяет получить запрос, решая, что с ним делать, затем перенаправляет браузеру на другой URL-адрес. Это вызывает еще одну ненужную поездку на сервер, что плохо для производительности и SEO.
  3. Атрибут OutputCache работает только с методами управления контроллером и применяется только к кешированию . Это не относится к кэшированию данных.

Если вы хотите иметь управляемую базой данных маршрутизацию, вы должны подкласс RouteBase. Это дает вам возможность сопоставить URL-адрес с набором значений маршрута (который представляет собой действие и параметры контроллера), а также отобразить значения маршрута обратно на URL-адрес (так что ActionLink и RouteLink будут корректно работать в ваших представлениях).

Посмотрите на this answer для надежного подхода. Он также включает в себя кеш для данных URL-адреса и блокировки потоков, чтобы гарантировать, что кеш обновляется только одним потоком (а база данных только один раз), когда истекает срок действия кэша.

Если вам нужно сделать его более многоразовым (то есть работать с большим количеством контроллеров и методов действий), вы можете сделать его более похожим на это MVC 6 sample, передав ему информацию о контроллере и действии и экземпляр поставщика данных через конструктор вашего обычая RouteBase и регистрации маршрута более одного раза в вашей конфигурации (с разными параметрами, конечно).

+0

Да, похоже, что это исправит мою проблему, но как я могу реализовать этот пример MVC6 на этом коде, который вы предоставили?Спасибо: D – Terkhos

+1

Используйте другое решение в [этом ответе] (http://stackoverflow.com/questions/31934144/multiple-levels-in-mvc-custom-routing/31958586#31958586). Решение MVC 6 было именно таким, чтобы вы могли видеть, как сделать его более общим, подвергая параметры конструктору класса и создавая отдельную службу для поставщика данных. Помимо этого, они в основном одинаковы. – NightOwl888

+0

Он работал очень, только один вопрос ... что делает GetVirtualPath? Я немного изменил ваш код, чтобы он сделал то, что мне нужно, вы можете взглянуть? Благодарю. http://pastebin.com/CZYPSH1J – Terkhos

2

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

В основном, использует Session хранения для отслеживания страницы настроек отдельных пользователей (см this article для получения дополнительной информации).

Кроме того, как и в стороне, я заметил, что вы дублировали код в BuscaURLWS и BuscaURLHS - не делайте этого! См. DRY, почему бы и нет. Кроме того, вы используете свой токенинг URL вручную; есть много инструментов для этого легко (см. Uri для получения дополнительной информации).

+0

Последнее: если я неправильно понимаю вас, и вы пытаетесь сделать какое-то кэширование, использование статического кеша полностью прекрасное. Если вы пытаетесь сделать это для каждого пользователя, этот ответ - хороший способ сделать это. Если вы пытаетесь сделать что-то, что должно быть сделано при * запуске приложения *, то используйте 'Application_Start' – funbrigade

+0

Да, они выглядят повторяющимися, потому что я скрыл часть кода, это было довольно обширно, но спасибо за подсказку в любом случае. О кешировании, я не хочу никакого кеша вообще, я не могу этого сделать, потому что контент может и будет меняться, я хочу, чтобы каждый запрос обрабатывался однозначно, и они не смешиваются друг с другом – Terkhos

+0

Где я могу это использовать, так как мне нужен сеанс, инициализированный для его использования, и у меня его нет в данный момент? И я делаю это на Application_Start, у меня есть собственный маршрут, который будет выполнять мой RouteHandler. – Terkhos