MVC Routing

Gdzie ja jestem czyli Routing.
W świecie ASP.NET URL odpowiadał namacalnemu plikowi.
W świecie MVC w którym posługujemy się pojęciami akcji i routingu URL nie ma nic wspólnego z plikiem, za to oczywiście ma wiele wspólnego z akcjami i kontrolerami.


A oto droga jaką pokonuje URL
Routing URL zapewnia nam niezależność adresów od plików jest bardziej powiązany z logiką aplikacji, dobrze jest więc go prawidłowo zaprojektować. Warto zwrócić uwagę na takie zagadanienia:
  1. utrzymywanie prostych i krótkich adresów URL - łatwiejsze korzystanie z witryny dla użytkownika końcowego
  2. wprowadzenie wzorców umożliwiających pomijanie parametrów no events/< rok>/< miesiac>/< data>
  3. unikanie ujawniania ID z bazy a jeśli to jest konieczne - dodawanie zbędnych informacji w celu zwiększenia czytelności adresu
Przykładowe wzorce i pasujące do nich adresy zostały przedstawione w tabelce poniżej.
Wzorc Routingu Przykładowy URL
{controller}/{action}/{id}
/Products/Show/All
{controller}/{action}/{id}.aspx/Products/Show/All.aspx
archive/{year}-{month}/{title}.aspx/archive/2008-07/BlogPost.aspx
{language}-{country}/{controller}/ {action}/{id}/en-us/Products/Show/All
{department}/{title}.aspx/Sales/Overview.aspx

Definiowanie Routingu
Routes są definiowane na starcie aplikacji czyli w Global.asax w metodzie Application_Start

Używany jest zawsze pierwszy pasujący routing!
Jeśli nie pasuje - brany(sprawdzany) jest kolejny
Oprócz mapowania możemy użyć też Ignore aby pewne wzorce były pomijane - co przydaje się przy wykorzystywaniu równocześnie klasycznych stron ASP.NET.
Mapowanie przyjmuje do 4 parametrów (opisane w przykładowym kodzie).
Oto przykład pliku Global.asax
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcApplication1
{
    public class GlobalApplication : System.Web.HttpApplication
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            /* == 
            routes.Add(
            new Route("{resource}.axd/{*pathInfo}",
            new StopRouteHandler())
            );*/

            /*Force routing handler to process all of the .aspx requests 
              for the directory /Classsic int the regular ASP.NET way */
            routes.Add(
            new Route("Classic/{resource}.aspx?{*requestUrl}",
            new StopRoutingHandler())
            );
            routes.Add(
            new Route("Classic/{resource}.aspx",
            new StopRoutingHandler())
            );

            //---------- add route
            routes.MapRoute(
            "ProductShow", // Route name
            "Product/{id}-{title}.asp", // URL with parameters
            new
            { // Parameter defaults
                controller = "Product",
                action = "Show",
                id = "",
                title = ""
            },
            new { id = @"[\d.*]" } // Parameter constraints
            );
            routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new
            { // Parameter defaults
                controller = "Home",
                action = "Index",
                id = ""
            }
            );
        }
        protected void Application_Start()
        {
            RegisterRoutes(RouteTable.Routes);
        }
    }
}
Jeśli mamy określony parametr id w routingu w funkcji będącej akcją musi nazywać się on tak samo.
        public ActionResult Index()
        {
            //widok generowany z automatu       
            return View(edul.Risks.ToList());
        }

        public ActionResult IndexPaged(int? id) //parametr musi sie nazywac tak jak w routingu!!
        {
            int pageSize = 10;

            return View(edul.Risks.Skip(pageSize * (id.HasValue ? id.Value : 0)).Take(pageSize).ToList());
        }
Ostatni z parametrów wymusza restrykcje parametrów. Możliwe jest napisanie własnej funkcji definiujące takie restrykcje. Funkcja taka musi implementować interface IRouteConstraint:
public class AuthenticatedRouteConstraint : IRouteConstraint
{
    #region IRouteConstraint Members
    public bool Match(HttpContextBase httpContext, Route route,
    string parameterName, RouteValueDictionary values,
    RouteDirection routeDirection)
    {
        // Match only when user is authenticated
        return httpContext.Request.IsAuthenticated;
    }
    #endregion
}
Odpowiedni kawałek kodu w Global.asax
routes.MapRoute(
        "Secret",
        "Secret/{action}",
        new { controller = "Secret", action = "Index" },
        new { authenticated = new AuthenticatedRouteConstraint() }
);

Komentarze

Popularne posty