Гость
Целевая тема:
Создать новую тему:
Автор:
Форумы / ASP.NET [игнор отключен] [закрыт для гостей] / MVC и маршруты / 19 сообщений из 19, страница 1 из 1
17.04.2015, 19:04
    #38939626
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
До этого работал только с WebForms
Надо создать динамическое меню I-го уровня, то есть:

Код: plaintext
1.
2.
3.
site.com/Menu1, 
site.com/Menu2, 
...
site.com/MenuN

Создать Контроллер "Menu1Controller", потом Вьюху "Menu1/Index.cshtml" - вручную можно.
А вот как такое сделать динамически (программно)?
...
Рейтинг: 0 / 0
17.04.2015, 20:33
    #38939657
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkin,

https://github.com/maartenba/MvcSiteMapProvider

для создания навигации, меню и хлебных крошек.


Но если бы ты описал задачу более подробно, можно было бы дать правильные советы и направления.
...
Рейтинг: 0 / 0
17.04.2015, 21:01
    #38939670
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
hVostt
Так, простое меню первого уровня надо создать.
например как на SQL.RU:
Название Гиперссылка Главная http://www.sql.ru/ Форум http://www.sql.ru/forum Рассылка http://www.sql.ru/subscribe/ Поиск http://www.sql.ru/search/
Только динамически, то есть сам пользователь создаёт это меню:
название -> гиперссылка

В ВебФормах я использовал класс Rewriter
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
public class Rewriter : System.Web.IHttpModule
    {
        public void Init(System.Web.HttpApplication Appl)
        {
            Appl.BeginRequest += new System.EventHandler(Rewrite_BeginRequest);
        }

        public void Rewrite_BeginRequest(object sender, System.EventArgs args)
        {
         // ...
        }



А в MVC могу создать только вида:
Название Гиперссылка Форум http://www.sql.ru/home/menu/forum
То есть мне надо как-то убрать из линки "лишние" /home/menu
...
Рейтинг: 0 / 0
17.04.2015, 21:08
    #38939672
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkin,

App_Start\RouteConfig.cs

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.IgnoreRoute("bundles/{*pathInfo}");
            routes.IgnoreRoute("Content/{*pathInfo}");

            routes.MapMvcAttributeRoutes();

            // вот здесь добавляешь свои маршруты, допустим:

            routes.MapRoute(
                name: "MyRoute1",
                url: "/home/{*slugs}",
                defaults: new { controller = "MyController", action = "MyAction" }
            );

            // -- теперь контроллер MyController действием MyAction обрабатывает
            //     любые ссылки вида:
            //         /home
            //         /home/bla
            //         /home/bla/bla/bla
            //         /home/blablablba/ba/sfsdf/sdf/sdf
            //  часть {*slugs} передаётся в виде строкового параметра slugs в действие,
            //  там уже обрабатывай и решай что делать            

            // а это маршрут по умолчанию, должен быть в самом конце
            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
...
Рейтинг: 0 / 0
17.04.2015, 21:09
    #38939673
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkinА в MVC могу создать только вида:

любые можешь создать, какие хочешь, и без реврайта!
...
Рейтинг: 0 / 0
17.04.2015, 21:09
    #38939674
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
редактируй файл App_Start/RouteConfig

что-то типа такого
Код: c#
1.
2.
3.
4.
      routes.MapRoute(
          name: "Default",
          url: "{controller}/{action}/{id}",
          defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }

здесь задан дефолт как для контроллера, так и для экшена. Можешь задать только для экшена
...
Рейтинг: 0 / 0
17.04.2015, 21:10
    #38939676
Shocker.Pro
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
упс, не успел
...
Рейтинг: 0 / 0
17.04.2015, 21:11
    #38939677
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
hVostt,

ошибка, в: "/home/{*slugs}"

правильно: url: "home/{*slugs}"
...
Рейтинг: 0 / 0
17.04.2015, 23:46
    #38939715
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
Для меню первого уровня надо убрать home/
Получим такое:
Код: c#
1.
2.
3.
4.
5.
            routes.MapRoute(
                name: "MyRoute1",
                url: "{*slugs}",
                defaults: new { controller = "My", action = "MyAction" }
            );


Но тогда один Метод (MyAction) Контроллера (MyController) обрабатывает все события:
Код: plaintext
1.
2.
3.
 site.com/Menu1,
 site.com/Menu1/bla1,
 site.com/Menu1/bla1/bla2/...,

Как-то не очень, теряется суть MVC ...
Или я что-то не так делаю?
...
Рейтинг: 0 / 0
18.04.2015, 00:13
    #38939721
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
Все-все события (адреса):
Код: plaintext
1.
2.
3.
4.
5.
6.
 site.com/Menu2,
 site.com/XXX
 site.com/About
 site.com/YYY
 site.com/YYY/KKK/MMM
 ...
...
Рейтинг: 0 / 0
18.04.2015, 02:10
    #38939739
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkinКак-то не очень, теряется суть MVC ...
Или я что-то не так делаю?

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

Примеры:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
// вывести запись блога по id
routes.MapRoute(
   name: "BlogRoute",
   url: "blog/{id}",
   defaults: new { controller = "Blog", action = "ShowRecord" }
);

// вывести архив блога
routes.MapRoute(
   name: "BlogRoute",
   url: "blog/archive/{year}/{month}/{day}",
   defaults: new { 
       controller = "Blog", 
       action = "ShowArchive", 
       year = UrlParameter.Optional,
       month = UrlParameter.Optional,
       day = UrlParameter.Optional
   }
);

// вывести общий каталог товаров
routes.MapRoute(
   name: "CatalogRootRoute",
   url: "catalog",
   defaults: new { controller = "Catalog", action = "Index" }
);
// вывести содержимое каталога по {id}
routes.MapRoute(
   name: "CatalogShowRoute",
   url: "catalog/{id}",
   defaults: new { controller = "Catalog", action = "Show" }
);

...



Т.е. честный роутинг, который на 100% связывает контроллер и действие с адресом по его виду.

Для того, чтобы удовлетворить требованиям SEO, часто добавляют ЧПУ после ID:

http://www.sql.ru/forum/1152697 /mvc-i-marshruty

Выделенное жирным используется для определения ресурса. Выделенное красным нужно только для поисковиков и для отображения в адресной строке ЧПУ.

Если у тебя есть набор контроллеров и действий, но вид URL полностью от и до задаётся пользователями, тогда таблицу роутинга можешь строить динамически, вызывая routes.MapRoute с параметрами, полученными из базы.

В самом общем виде, например для фронта CMS, достаточно одного контроллера и действия:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
            routes.MapRoute(
                name: "MyRoute1",
                url: "{*slugs}",
                defaults: new { controller = "My", action = "Index" }
            );

...

public class MyController : Controller
{
...
   public ActionResult Index(string slugs)
   {
      var resource = MyDbRepository.GetResourceByUrl(slugs);
      if(resource == null) return NotFound();
      var model = MapResouceToModel(resource, model);
      return View(model);
   }
...
}



Вот и всё. Любые URL, хранятся в базе, обрабатываются одинаково, значит одного действия хватит. Но в реальном ПО конечно всё сложнее и требуется больше контроллеров. А чтобы жизнь себе не усложнять, не надо гнаться за "чистыми" URL, полностью повторяющими структуру сайта, можно обойтись ЧПУ-приставкой, как это делает sql.ru (часть ЧПУ адреса после ID).

Но можно и совмещать, если до роутинга url: "{*slugs}" ты вставишь более конкретные маршруты, то приоритет у них будет выше, например, редактирование ресурса, админка и т.д. И когда конкретного маршрута не найдено, будет обработан универсальный {*slugs} маршрут.

В общем, тут возможностей как всё выстроить миллион, никаких особых ограничений, делай как хочешь. Только пойми, что контроллер/действие != страница, как ASPX, это только логика обработки запросов.
...
Рейтинг: 0 / 0
18.04.2015, 02:18
    #38939740
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkin
Код: plaintext
1.
2.
3.
4.
5.
site.com/Menu2,
 site.com/XXX
 site.com/About
 site.com/YYY
 site.com/YYY/KKK/MMM
 ...



с адресами понятно. а с логикой? пользователи, которые задают структуру сайта, логику тоже сами пишут? для каждого адреса свою на C#? ))
...
Рейтинг: 0 / 0
19.04.2015, 12:00
    #38940031
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
1.
hVostt с адресами понятно. а с логикой? Пользователи, которые задают структуру сайта, логику тоже сами пишут? Для каждого адреса свою на C#? ))
Нет, конечно.
Есть админка, в ней и создают меню (I-го уровня), подменю (II-го уровня). А так же тип меню (что должно отображать меню):
1. Текст (статьи)
2. Список товара (типа интернет-магазина)
3. ...

2.
Но вообще логично же, если есть меню:
Код: plaintext
  site.com/Blog 
то, например текст (блог) будут иметь вид:
Код: plaintext
  site.com/Blog/123-nazvanie-stati-bloga 
И т.д.

3.
По поводу индексации поисковиками.
Если не ошибаюсь, то Гугл лучше будет индексировать такое:
Код: plaintext
  site.com/Blog 
чем такое:
Код: plaintext
  site.com/Home/Blog 
То есть чем меньше вложений в адресе, тем выше в поисковике будет статья.
...
Рейтинг: 0 / 0
19.04.2015, 12:41
    #38940036
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkinНет, конечно.
Есть админка, в ней и создают меню (I-го уровня), подменю (II-го уровня). А так же тип меню (что должно отображать меню):
1. Текст (статьи)
2. Список товара (типа интернет-магазина)
3. ...

Очевидно же, что статьи с текстами будет обрабатывать один контроллер, список товаров другой, что-то там ещё, третий и т.д.

Значит по адресу необходимо определить какой контроллер и действие должны обработать адрес.

Логично?

В ASP.NET MVC для этого служат специальные маршруты, которые могут это определить, буквально по адресу.

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

Тогда нужно либо таблицу маршрутов формировать динамически, самый жёсткий способ вот такой (при изменении любого URL-а а админке):

Код: c#
1.
2.
3.
4.
5.
6.
7.
public static void UpdateRouteRegistration() {
  RouteCollection routes = RouteTable.Routes;
  using (routes.GetWriteLock()) {
    routes.Clear();
    // вот здесь перестраиваем маршруты с нуля
  }
}



Мягкий способ состоит в написании своего маршрутизатора с кешированием и плюшками.

Реврайт самый тупой способ. В принципе он такой же тупой и для ASPX, но там деваться некуда (по крайне мере раньше так было, либо через задницу, либо никак).


potkinНо вообще логично же, если есть меню:
Код: plaintext
  site.com/Blog 
то, например текст (блог) будут иметь вид:
Код: plaintext
  site.com/Blog/123-nazvanie-stati-bloga 
И т.д.

Ну вот у тебя уже есть маршрут: "Blog/{id}-{alias}" -- пожалуйста.

potkinПо поводу индексации поисковиками.
Если не ошибаюсь, то Гугл лучше будет индексировать такое:
Код: plaintext
  site.com/Blog 
чем такое:
Код: plaintext
  site.com/Home/Blog 
То есть чем меньше вложений в адресе, тем выше в поисковике будет статья.

Я не СЕО-шник, но в целом на сколько мне известно, поисковику на это положить. Он смотрит не на URL, а на реальную структуру сайтов. Вообще весь сайт может иметь вот такие URL-ы:

site.com/id/1
site.com/id/100
site.com/id/123123
site.com/id/12

Но внутри иметь ветвистую структуру, отражаемую в sitemap.xml, как узлы с подчинёнными узлами, с крошками и прочим. Гугл и Яндекс отлично с этим справятся, и совершенно пофигу на вид URL-а. По сути ЧПУ в URL нужны только для людей, и раньше ключевики в URL тоже повышали рейтинг (сейчас тоже это имеет смысл, но совсем очень даже далеко не первичный, болтается где-то в самом конце). Могу ошибаться, в любом случае, реализовать можно любую логику. Я делал полное отражение структуры сайта в URL, такое было задание, писал свой обработчик маршрутов, который сопоставлял {*slugs} нужным контроллерам и действию. Примеров в сети полно, на StackOvefrlow.com тоже хватает примеров.
...
Рейтинг: 0 / 0
19.04.2015, 16:58
    #38940131
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
hVostt Таблицу маршрутов формировать динамически
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
public static void UpdateRouteRegistration() {
  RouteCollection routes = RouteTable.Routes;
  using (routes.GetWriteLock()) {
    routes.Clear();
    // вот здесь перестраиваем маршруты с нуля
    //Из Базы Данных
  }
}



Пишу туда данные их БД.
На Сервере, что бы добавить новый Маршрут надо Остановить и Стартануть Сервер.
На рабочей станции (в студии) Остановить отладку и сделать Run проекта .
Как-то не очень ...

hVostt Реврайт самый тупой способ. В принципе он такой же тупой и для ASPX
Получается придётся пользоваться Реврайт-ом ...
...
Рейтинг: 0 / 0
19.04.2015, 18:37
    #38940160
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkinКак-то не очень ...

Вот рабочий способ:

Таблица маршрутов:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
           
            // определяем универсальный маршрут с нашим констрейтом

            var pathRoute = routes.MapRoute("Path", "{*path}",
                defaults: new { controller = "Home", action = "Default", path = "index" },
                constraints: new { path = new EntryRouteConstraint() },
                namespaces: DefaultNamespaces);

            // который использует наш хендлер

            pathRoute.RouteHandler = new EntryRouteHandler();



констрейт:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
public class EntryRouteConstraint : IRouteConstraint
    {
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values,
                          RouteDirection routeDirection)
        {
            if (routeDirection == RouteDirection.UrlGeneration)
            {
                return true;
            }
            var path = values[parameterName] as string;
            if (path == null)
                return false;
            var manager = DependencyResolver.Current.GetService<MySomeRouteManager>();
            // пытаемся найти путь (ХЗ где, в базе данных, из параллельной вселенной, в подсознании спящего кайота...)
            var resolve = manager.Resolve(path);
            if (resolve == null)
                return false; // не нашли? тогда путь не разрешается этим роутом
            // нашли? ок
            // засовываем данные в контекст, чтобы два раза за ними не ходить
            httpContext.Items["resolvedContext"] = resolve;
            return true;
        }
    }



теперь хендлер, который получает управления, если констрейт дал добро:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
    public class EntryRouteHandler : MvcRouteHandler // на базе MVC-шного
    {
        protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            // достём из контекста сохраннную инфоу
            var resolveContext = requestContext.HttpContext.Items["resolvedContext"] as ResolveContext;
            // тип ResolveContext -- это наш какой-то тип, там хранится всё, что надо для хендлера
            // вот здесь уже определяем контроллер и действие
            // например так:
            var routeValues = requestContext.RouteData.Values;
            routeValues["controller"] = resolveContext.GetControllerName();
            routeValues["action"] = resolveContext.GetActionName();
            // ну и всё...
            return base.GetHttpHandler(requestContext);
        }
   }




potkinПолучается придётся пользоваться Реврайт-ом ...

реврайтер нужен как кобыле пятое копыто.
...
Рейтинг: 0 / 0
20.04.2015, 23:42
    #38941141
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
Спасибо за помощь, но ...

Не очень понятно что такое MySomeRouteManager и ResolveContext

И про маршруты из БД.
автор // пытаемся найти путь (ХЗ где, в базе данных, из параллельной вселенной, в подсознании спящего кайота...)
Допустим пользователь внёс новый маршрут в БД (name, url, defaults {Controller, Action}).
Я сделал выборку, получил эти данные.
Раньше я делал так:
Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
using (Models.DbConnection con = new Models.DbConnection("..."))
 {
     var SysRoutes = con.SysRoutes.SqlQuery("SELECT * FROM SysRoutes").ToList(); //Name, Url, Controller, Action
     foreach (var item in SysRoutes)
     {
               //Вот тут "строю" новые маршруты
               routes.MapRoute(
                    name: item.Name,
                    url: item.Url,
                    defaults: new { controller = item.Controller, action = item.Action } //, id = UrlParameter.Optional
               );
          }
     }


А теперь куда полученное данные из БД "вставить"?
...
Рейтинг: 0 / 0
21.04.2015, 00:06
    #38941154
hVostt
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
potkinА теперь куда полученное данные из БД "вставить"?

судя по твоему коду, вот MySomeRouteManager и ResolveContext:

Код: c#
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
public class ResolveContext
{
   public string Name {get;set;}
   public string Url {get;set;}
   public string Controller {get;set;}
   public string Action {get;set;}
}

// ...


    public class MySomeRouteManager
    {
        public ResolveContext Resolve(string path)
        {
            using (Models.DbConnection con = new Models.DbConnection("..."))
            {
                var findRoute = con.SysRoutes
                   .SqlQuery("SELECT * FROM SysRoutes WHERE Url = @p0", new SqlParameter("p0", path))
                   .ToList(); //Name, Url, Controller, Action
                if(findRoute.Count == 0)
                {
                   return null;
                }
                var route = findRoute[0];
                return new ResolveContext 
                {
                    Name = route.Name,
                    Url = route.Url,
                    Controller = route.Controller,
                    Action = route.Action
                }
            }
        }

    }
...
Рейтинг: 0 / 0
21.04.2015, 21:04
    #38942015
potkin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
MVC и маршруты
Работает, спасибо!
Простые маршруты легко "строятся", но вот динамические с БД, меня удивили ...
...
Рейтинг: 0 / 0
Форумы / ASP.NET [игнор отключен] [закрыт для гостей] / MVC и маршруты / 19 сообщений из 19, страница 1 из 1
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]