none
MVC 2.0 Routing RRS feed

  • Pregunta

  • Hola,

    En nuestra aplicación MVC tenemos un area con un par de rutas del siguiente estilo:

    Presencia/Horarios/{horarioCI}/PeriodosHorarios/{periodoCI}/{controller}/{action}/{ci}
    
    Presencia/Incidencias/{incidenciaCI}/PeriodosIncidencias/{periodoCI}/{controller}/{action}/{ci}
    

    En realidad esto sería correcto ya que tanto PeriodosHorarios como PeriodosIncidencias son controladores diferentes y hacen cosas diferentes, pero en nuestro caso deseariamos que nuestra API tubiera las sifuientes rutas:

    Presencia/Horarios/{horarioCI}/Periodos/{periodoCI}/{controller}/{action}/{ci}
    
    Presencia/Incidencias/{incidenciaCI}/Periodos/{periodoCI}/{controller}/{action}/{ci}
    

    Sería posible realizar este proceso de routing?

    Gracias,

    JA Reyes.


    Please remember to Vote & "Mark As Answer" if this post is helpful to you.
    Por favor, recuerda Votar y "Marcar como respuesta" si la solucion de esta pregunta te ha sido útil.
    miércoles, 11 de mayo de 2011 9:09

Respuestas

  • Buenas!

    Si no entiendo mal quieres que el nombre del controlador no se ponga directamente en la URL, sino que se construya a partir de esta. Es decir que

    • /Presencia/Horarios/[ci]/Periodos/accion te invoque al controlador llamado PeriodosHorarios no?
    • /Presencia/Incidencias/[ci]/Periodos/accion te invoque al controlador llamado PeriodosIncidencias no?

    Bueno, eso lo puedes hacer con dos rutas, o bien si tiene que ser más genérico con una sola ruta y un route handler :)

    1. Con dos rutas

    Muy simple:

    1. mapeas /Presencia/Horarios/{ci}/Periodos/{action} y como defaults le pones new {controller="PeriodosHorarios"}
    2. mapeas /Presencia/Incidencias/{ci}/Periodos/{action} y como defaults le pones new {controller="PeriodosIncidencias"}

    Fíjate que no defines el parámetro de ruta {controller} en la URL, sino que lo defines en los defaults (porque tu sabes a que controlador correspopnde cada ruta).

    Eso te funcionará por las URLs /Presencia/Horarios/xxx/Periodos/accion y por /Presencia/Incidencias/xxx/Periodos/accion y por ninguna más. Si quieres hacer más veces esta conversión, deberás añadir rutas.

    2. Una sola ruta y un route handler

    Esa es la versión "flexible". Los route hanlders son clases que se ejecutan cuando una ruta ha sido seleccionada y tienen la opción de realizar conversiones sobre los route values de dicha ruta. En tu caso, podrías definir un route handler como el siguiente:

      public class PresenciaRouteHandler : MvcRouteHandler
      {
        protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
        {
          requestContext.RouteData.Values.Add("controller", 
            string.Concat("Periodos", requestContext.RouteData.Values["rc"].ToString()));
          return base.GetHttpHandler(requestContext);
        }
      }
    

    Es muy simplón: simplemente recoje un parámetro de ruta (rc), le añade "Periodos" delante y crea el parámetro de ruta controller con dicho nombre.

    Ahora defines la ruta que use este route handler. No puedes usar MapRoute(), sinó que debes usar el método Add:

          routes.Add("Periodos",
            new Route("Presencia/{rc}/{ci}/Periodos/{action}/{id}", new PresenciaRouteHandler())
            {
              Defaults = new RouteValueDictionary(new { id = UrlParameter.Optional })
            });
    

    Añades una ruta que mapeará cualquier URL del tipo:

    /Presencia/[xxx]/[yyy]/Periodos/[accion]/[id] y dicha ruta usa el RouteHandler que hemos creado. Ahora la URL:

    • /Presencia/Horarios/3/Periodos/Index

    Es mapeada a esta ruta con los route values siguientes:

    • rc = Horarios
    • ci = 3
    • action = Index
    • id = [No se crea, porque la ruta indica que es opcional]

    Ahora esta ruta pasa por el route handler y este crea el parámetro de ruta "controller" cuyo valor es Periodos seguido del valor de ruta "rc", es decir PeriodosHorarios. El parámetro de ruta controller es uno de los dos obligatorios (junto con action) y indica el controlador a usar.

    Listos! ya está: ya tienes el controlador PeriodosHorarios creado y este será el que se usará. Ya puedes añadir la acción que quieras. Si la acción tiene un parámetro llamado ci, este se "bindeará" al valor de ruta {ci} (en este caso 3).

    Por supuesto ahora una URL tipo:

    • /Presencia/Pepitos/3/Periodos/Index

    Intentará llamar al controlador PeriodosPepitos que no se encontrará (devolverá un 404). Si quieres evitar esto, puedes añadir constraints a la ruta (que actuen sobre el valor de rc) o bien tratarlo en el route handler.

    Espero que te haya aclarado algo! ;-)


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Propuesto como respuesta José M. AguilarMVP viernes, 13 de mayo de 2011 8:29
    • Marcado como respuesta JA Reyes viernes, 13 de mayo de 2011 8:39
    viernes, 13 de mayo de 2011 7:07

Todas las respuestas

  • No veo ningún inconveniente. Al fin y al cabo, las dos rutas son disjuntas, siempre se distinguen por el segundo fragmento (Horarios frente a Incidencias). Por lo tanto deberían funcionar perfectamente si ambas las añades al mapa de rutas. La única pega que veo es que tienen parámetros con distinto nombre, por lo que no podrás fácilmente usar un mismo {controller} con un mismo {action} a través de ambas rutas, pero si van a ser diferentes valores no hay dificultad.
    jueves, 12 de mayo de 2011 7:30
  • Ok,

    Gracias Alberto. Quizás formulé mal la pregunta. El caso que planteaba sería extensible a esta otra situación...

    En caso de tener las rutas:

    Presencia/Horarios/{horarioCI}/{controller}/{action}/{ci}
    
    Presencia/Incidencias/{incidenciaCI}/{controller}/{action}/{ci}
    

    Como podría redirigir las llamadas:

    Presencia/Horarios/3/Periodos/{action}/{ci}
    
    Presencia/Incidencias/5/Periodos/{action}/{ci}
    

    De manera quer ealmente se llamara a PeriodosHorariosController y a PeriodosIncidenciasController respectivamente.

    Sería esto posible?

    Gracias.

     


    Please remember to Vote & "Mark As Answer" if this post is helpful to you.
    Por favor, recuerda Votar y "Marcar como respuesta" si la solucion de esta pregunta te ha sido útil.
    jueves, 12 de mayo de 2011 8:02
  • Buenas!

    Si no entiendo mal quieres que el nombre del controlador no se ponga directamente en la URL, sino que se construya a partir de esta. Es decir que

    • /Presencia/Horarios/[ci]/Periodos/accion te invoque al controlador llamado PeriodosHorarios no?
    • /Presencia/Incidencias/[ci]/Periodos/accion te invoque al controlador llamado PeriodosIncidencias no?

    Bueno, eso lo puedes hacer con dos rutas, o bien si tiene que ser más genérico con una sola ruta y un route handler :)

    1. Con dos rutas

    Muy simple:

    1. mapeas /Presencia/Horarios/{ci}/Periodos/{action} y como defaults le pones new {controller="PeriodosHorarios"}
    2. mapeas /Presencia/Incidencias/{ci}/Periodos/{action} y como defaults le pones new {controller="PeriodosIncidencias"}

    Fíjate que no defines el parámetro de ruta {controller} en la URL, sino que lo defines en los defaults (porque tu sabes a que controlador correspopnde cada ruta).

    Eso te funcionará por las URLs /Presencia/Horarios/xxx/Periodos/accion y por /Presencia/Incidencias/xxx/Periodos/accion y por ninguna más. Si quieres hacer más veces esta conversión, deberás añadir rutas.

    2. Una sola ruta y un route handler

    Esa es la versión "flexible". Los route hanlders son clases que se ejecutan cuando una ruta ha sido seleccionada y tienen la opción de realizar conversiones sobre los route values de dicha ruta. En tu caso, podrías definir un route handler como el siguiente:

      public class PresenciaRouteHandler : MvcRouteHandler
      {
        protected override IHttpHandler GetHttpHandler(System.Web.Routing.RequestContext requestContext)
        {
          requestContext.RouteData.Values.Add("controller", 
            string.Concat("Periodos", requestContext.RouteData.Values["rc"].ToString()));
          return base.GetHttpHandler(requestContext);
        }
      }
    

    Es muy simplón: simplemente recoje un parámetro de ruta (rc), le añade "Periodos" delante y crea el parámetro de ruta controller con dicho nombre.

    Ahora defines la ruta que use este route handler. No puedes usar MapRoute(), sinó que debes usar el método Add:

          routes.Add("Periodos",
            new Route("Presencia/{rc}/{ci}/Periodos/{action}/{id}", new PresenciaRouteHandler())
            {
              Defaults = new RouteValueDictionary(new { id = UrlParameter.Optional })
            });
    

    Añades una ruta que mapeará cualquier URL del tipo:

    /Presencia/[xxx]/[yyy]/Periodos/[accion]/[id] y dicha ruta usa el RouteHandler que hemos creado. Ahora la URL:

    • /Presencia/Horarios/3/Periodos/Index

    Es mapeada a esta ruta con los route values siguientes:

    • rc = Horarios
    • ci = 3
    • action = Index
    • id = [No se crea, porque la ruta indica que es opcional]

    Ahora esta ruta pasa por el route handler y este crea el parámetro de ruta "controller" cuyo valor es Periodos seguido del valor de ruta "rc", es decir PeriodosHorarios. El parámetro de ruta controller es uno de los dos obligatorios (junto con action) y indica el controlador a usar.

    Listos! ya está: ya tienes el controlador PeriodosHorarios creado y este será el que se usará. Ya puedes añadir la acción que quieras. Si la acción tiene un parámetro llamado ci, este se "bindeará" al valor de ruta {ci} (en este caso 3).

    Por supuesto ahora una URL tipo:

    • /Presencia/Pepitos/3/Periodos/Index

    Intentará llamar al controlador PeriodosPepitos que no se encontrará (devolverá un 404). Si quieres evitar esto, puedes añadir constraints a la ruta (que actuen sobre el valor de rc) o bien tratarlo en el route handler.

    Espero que te haya aclarado algo! ;-)


    Eduard Tomàs Blog: http://geeks.ms/blogs/etomas -- Twitter: eiximenis
    • Propuesto como respuesta José M. AguilarMVP viernes, 13 de mayo de 2011 8:29
    • Marcado como respuesta JA Reyes viernes, 13 de mayo de 2011 8:39
    viernes, 13 de mayo de 2011 7:07
  • Gracias Eduard,

    Creo que debe funcionar.


    Please remember to Vote & "Mark As Answer" if this post is helpful to you.
    Por favor, recuerda Votar y "Marcar como respuesta" si la solucion de esta pregunta te ha sido útil.
    viernes, 13 de mayo de 2011 8:39