asp.net-mvc
Wytyczanie
Szukaj…
Wprowadzenie
Routing to sposób, w jaki ASP.NET MVC dopasowuje identyfikator URI do akcji. Moduł routingu jest odpowiedzialny za mapowanie przychodzących żądań przeglądarki na określone działania kontrolera MVC.
MVC 5 obsługuje nowy typ routingu, zwany routingiem atrybutów. Jak sama nazwa wskazuje, routing atrybutów używa atrybutów do definiowania tras. Routing atrybutów zapewnia większą kontrolę nad identyfikatorami URI w aplikacji internetowej.
Niestandardowe trasy
Niestandardowe routing zapewnia specjalną potrzebę routingu w celu obsługi określonych żądań przychodzących.
Aby zdefiniować trasy niestandardowe, należy pamiętać, że kolejność tras dodawanych do tabeli tras jest ważna.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// this is an advanced custom route
// you can define custom URL with custom parameter(s) point to certain action method
routes.MapRoute(
"CustomEntry", // Route name
"Custom/{entryId}", // Route pattern
new { controller = "Custom", action = "Entry" } // Default values for defined parameters above
);
// this is a basic custom route
// any custom routes take place on top before default route
routes.MapRoute(
"CustomRoute", // Route name
"Custom/{controller}/{action}/{id}", // Route pattern
new { controller = "Custom", action = "Index", id = UrlParameter.Optional } // Default values for defined parameters above
);
routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // Route pattern
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Default values for defined parameters above
);
}
nazwy controller
i action
są zastrzeżone. Domyślnie MVC mapuje {controller}
część adresu URL do klasy <controller>Controller
, a następnie szuka metody o nazwie <action>
bez dodawania żadnych przyrostków.
Chociaż tworzenie rodziny tras przy użyciu szablonu {controller}/{action}/{parameter}
może być kuszące, pamiętaj, że robiąc to, ujawniasz strukturę swojej aplikacji i sprawiasz, że adresy URL są nieco kruche, ponieważ zmiana nazwy kontrolera zmienia trasy i zrywa linki zapisane przez użytkownika.
Preferuj wyraźne ustawienie trasy:
routes.MapRoute(
"CustomRoute", // Route name
"Custom/Index/{id}", // Route pattern
new { controller = "Custom", action = nameof(CustomController.Index), id = UrlParameter.Optional }
);
(nie można użyć operatora nameof
do nazwy kontrolera, ponieważ będzie miał on dodatkowy przyrostek Controller
), którego należy pominąć przy ustawianiu nazwy kontrolera na trasie.
Dodawanie niestandardowej trasy w Mvc
Użytkownik może dodać niestandardową trasę, mapując adres URL do określonej akcji w kontrolerze. Służy to do optymalizacji pod kątem wyszukiwarek i sprawia, że adresy URL są czytelne.
routes.MapRoute(
name: "AboutUsAspx", // Route name
url: "AboutUs.aspx", // URL with parameters
defaults: new { controller = "Home", action = "AboutUs", id = UrlParameter.Optional } // Parameter defaults
);
Routing atrybutów w MVC
Wraz z klasycznym sposobem definiowania trasy MVC WEB API 2, a następnie frameworki MVC 5 wprowadziły Attribute routing
:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// This enables attribute routing and must go before other routes are added to the routing table.
// This makes attribute routes have higher priority
routes.MapMvcAttributeRoutes();
}
}
W przypadku tras z tym samym prefiksem w kontrolerze można ustawić wspólny prefiks dla całych metod akcji w kontrolerze za pomocą atrybutu RoutePrefix
.
[RoutePrefix("Custom")]
public class CustomController : Controller
{
[Route("Index")]
public ActionResult Index()
{
...
}
}
RoutePrefix
jest opcjonalny i definiuje część adresu URL, która jest poprzedzona wszystkimi działaniami kontrolera.
Jeśli masz wiele tras, możesz ustawić domyślną trasę przechwytując akcję jako parametr, a następnie zastosować ją do całego kontrolera, chyba że określony atrybut Route
zdefiniowany w niektórych metodach działania zastępuje trasę domyślną.
[RoutePrefix("Custom")]
[Route("{action=index}")]
public class CustomController : Controller
{
public ActionResult Index()
{
...
}
public ActionResult Detail()
{
...
}
}
Podstawy routingu
Kiedy żądać url yourSite/Home/Index
za pośrednictwem przeglądarki, moduł routingu skieruje wniosek do Index
metody działaniem HomeController
klasie. Skąd wiadomo, że wysyła żądanie do metody określonej klasy? nadchodzi tabela tras.
Każda aplikacja ma tablicę tras, w której przechowuje wzorzec trasy i informacje o tym, dokąd skierować żądanie. Dlatego podczas tworzenia aplikacji mvc istnieje już domyślna trasa zarejestrowana w tabeli routingu. Możesz to zobaczyć w klasie RouteConfig.cs
.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
Widać, że wpis ma nazwę i szablon. Szablon to wzorzec trasy, który należy sprawdzić, gdy nadejdzie żądanie. Domyślny szablon ma wartość Home
jako wartość segmentu adresu URL kontrolera i Index
jako wartość dla segmentu akcji. Oznacza to, że jeśli nie podasz jawnie nazwy kontrolera i akcji w swoim żądaniu, użyje tych wartości domyślnych. Jest to powód, dla którego uzyskujesz ten sam wynik, kiedy uzyskujesz dostęp do yourSite/Home/Index
i yourSite
Być może zauważyłeś, że mamy parametr o nazwie id jako ostatni segment naszego wzorca trasy. Ale domyślnie określamy, że jest opcjonalny. To dlatego nie musieliśmy określać wartości identyfikatora w adresie URL, którego próbowaliśmy.
Teraz wróć do metody akcji Indeks w HomeController i dodaj do niej parametr
public ActionResult Index(int id)
{
return View();
}
Teraz w tej metodzie umieść punkt przerwania studia wizualnego. Uruchom swój projekt i yourSite/Home/Index/999
dostęp do yourSite/Home/Index/999
w przeglądarce. Punkt przerwania zostanie trafiony i powinieneś zobaczyć, że wartość 999 jest teraz dostępna w parametrze id
.
Tworzenie drugiego wzorca trasy
Powiedzmy, że chcielibyśmy ustawić go tak, aby ta sama metoda akcji została wywołana dla innego wzorca trasy. Możemy to zrobić, dodając nową definicję trasy do tabeli tras.
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
// New custom route definition added
routes.MapRoute("MySpecificRoute",
"Important/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
//Default catch all normal route definition
routes.MapRoute("Default", "{controller}/{action}/{id}",
new { controller = "Home", action = "Index", id = UrlParameter.Optional });
}
Nowa definicja, którą dodałem, ma wzór Important/{id}
gdzie id jest ponownie opcjonalny. Oznacza to, że kiedy yourSiteName\Important
o yourSiteName\Important
lub yourSiteName\Important\888
, zostanie ona wysłana do akcji indeksu HomeController.
Kolejność rejestracji definicji trasy
Ważna jest kolejność rejestracji trasy. Zawsze należy zarejestrować określone wzorce tras przed ogólną domyślną trasą.
Trasa catch-all
Załóżmy, że chcemy mieć trasę, która pozwala na nieograniczoną liczbę segmentów:
- http://example.com/Produkty/ (zobacz wszystkie produkty)
- http://example.com/Products/IT
- http://example.com/Products/IT/Laptops
- http://example.com/Products/IT/Laptops/Ultrabook
- http://example.com/Products/IT/Laptops/Ultrabook/Asus
- itp.
Musielibyśmy dodać trasę, zwykle na końcu tabeli tras, ponieważ prawdopodobnie przechwyciłaby ona wszystkie żądania, w ten sposób:
routes.MapRoute("Final", "Route/{*segments}",
new { controller = "Product", action = "View" });
W kontrolerze działaniem, które mogłoby to obsłużyć, może być:
public void ActionResult View(string[] segments /* <- the name of the parameter must match the name of the route parameter */)
{
// use the segments to obtain information about the product or category and produce data to the user
// ...
}
Trasa typu catch-all umożliwiająca routing po stronie klienta
Dobrą praktyką jest kodowanie stanu aplikacji pojedynczej strony (SPA) w adresie URL:
my-app.com/admin-spa/users/edit/id123
Umożliwia to zapisywanie i udostępnianie stanu aplikacji.
Gdy użytkownik umieści adres URL w pasku adresu przeglądarki i trafi, wejdź na serwer, musisz zignorować część żądanego adresu URL po stronie klienta. Jeśli podasz swój SPA jako renderowany widok Razor (wynik działania kontrolera wywołującego) zamiast statycznego pliku HTML, możesz użyć trasy catch-all:
public class AdminSpaController
{
[Route("~/admin-spa/{clienSidePart*}")]
ActionResult AdminSpa()
{
...
}
}
W tym przypadku serwer zwraca tylko SPA, a następnie inicjuje się zgodnie z trasą. To podejście jest bardziej elastyczne, ponieważ nie zależy od modułu przepisywania adresu URL .
Trasowanie atrybutów w obszarach
Aby korzystać z routingu atrybutów w obszarach, wymagana jest rejestracja obszarów i [RouteArea(...)]
.
W RouteConfig.cs
:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapMvcAttributeRoutes();
AreaRegistration.RegisterAllAreas();
}
}
W przykładowej definicji routingu atrybutów kontrolera obszaru:
[RouteArea("AreaName", AreaPrefix = "AreaName")]
[RoutePrefix("SampleAreaController")]
public class SampleAreaController : Controller
{
[Route("Index")]
public ActionResult Index()
{
return View();
}
}
Aby użyć linków Url.Action
w obszarach:
@Url.Action("Index", "SampleAreaController", new { area = "AreaName" })