none
Como usar Routing en MVC 4 con parametros requeridos RRS feed

  • Pregunta

  • Hola

    routes.MapRoute(
                  name: "Nombre",
                  url: "{controller}/{action}/{id}/{title}/{opc}",
                  defaults: new { controller = "Controlador", action = "Index"}

    Como puedo hacer para que los parametros id y title sean obligatorios y el parametro opc opcional? Si no me equivoco en el cas odel opcional seria:

    defaults: new { controller = "Controlador", action = "Index", opc= UrlParameter.Optional }

    Gracias

    lunes, 4 de noviembre de 2013 16:23

Respuestas

  • Por defecto, todos los parámetros son obligatorios. Los que no hayas marcado como UrlParameter.Optional tienen que aparecer forzosamente en la Url, y sino no se reconoce esa ruta y se pasa a analizar la siguiente ruta que hayas definido. Si es necesario restringirlos a un formato concreto (por ejemplo, una o más letras, o sólo números), puedes añadir el parámetro "constraints" con expresiones regulares en la llamada a MapRoute:

    routes.MapRoute(
                   name: "Nombre",
                   url: "{controller}/{action}/{id}/{title}/{opc}",
                   defaults: new { controller = "Controlador", action = "Index", opc= UrlParameter.Optional},
                   constraints: new { id="[0-9]+", title="\\w+" } );

    • Propuesto como respuesta Sergio ParraModerator lunes, 4 de noviembre de 2013 22:33
    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    lunes, 4 de noviembre de 2013 21:17
  • routes.MapRoute(
                    "Categorias",     // Route name
                    "{controller}/{action}/{id}/{categoria}",                           // URL with parameters
                    new { controller = "Publicaciones", action = "Categorias", id = "", categoria = "" }  // Parameter defaults
                );

    [...] Es decir, quiero que sean ambos parametros "id y categoria" obligatorio...

    Entonces no pongas en los defaults id="", categoria="". Cuando pones un default el campo deja de ser obligatorio.

    Pero cuando renderea el enlace lo hace de la siguiente manera: http://localhost/Controlador/Categorias/5?categoria=nombre

    Esto tiene toda la pinta de ser un problema de orden de definición de las rutas. Has debido definir la ruta estándar (contolador/accion/id) ANTES que la ruta controlador/accion/id/categoria.

    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    miércoles, 6 de noviembre de 2013 19:53
  • Segun lo que veo y me dices esta linea "{controller}/{action}/{id}/{categoria}", no se puede repetir parte de una que ya forma un rout completo?

    No es eso. Sí que se puede repetir. Lo que pasa es que el ORDEN en que las defines es importante, ya que el sistema las procesa por orden y se queda con la primera que le sirva, aunque más abajo hayas definido otra más detallada.

    Por eso si primero defines una ruta para controlador/accion/id y después más abajo defines otra para controlador/accion/id/categoria, y pides un actionlink con id y categoria, como lo primero que encuentra es controlador/accion/id y eso ya le sirve para construir el actionlink (poniendo ...?categoria=...), entonces no llega a examinar la siguiente opción. Por eso tienes que tener cuidado y definirlas al revés (primero controlador/accion/id/categoria y después controlador/accion/id).

    Lo mismo tienes que tener en cuenta con todas tus otras rutas: piensa que cuando llegue una URL, se va a comparar una por una con todas las rutas que hayas definido, y que en cuanto una de ellas sea aplicable (teniendo en cuenta que puede tener parámetros opcionales), entonces ya se aplica esa ruta y no se tienen en cuenta las siguientes alternativas, incluso aunque entre dichas alternativas hubiera alguna más detallada para esa URL.

    Por ejemplo, piensa en tu caso 2 y caso 4:

    localhost/articulos/search/<titulo>

    localhost/servicios/search/<titulo>

    Si intentas capturarlos poniendo para el caso 2 una ruta del tipo

    {controller}/{action}/{titulo}

    y para el 4 una así:

    servicios/{action}/{titulo}

    Entonces la 4 no se cumpliría nunca, porque se procesaría la 2 reemplazando "{controller}" por "servicios". El remedio sería definir primero la 4 y más abajo la 2.

    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    jueves, 7 de noviembre de 2013 7:07
  • No debería fallar por culpa de "{controller}/{action}/{id}/{categoria}", pero en cambio el problema que veo es que /ajax/webservice.asmx/mimetodo "encaja" dentro de la otra ruta, "{controller}/{action}/{id}", por lo que intentará llamarte a un controlador llamado "ajax" y un método "webservice.asmx" con el id="mimetodo". Normalmente cuando llamas a un aspx o un asmx, lo distingue por la extensión del archivo, pero en este caso al ponerle una "/" detrás para indicar "/mimetodo" sospecho que debe estar confundiendo al enrutador. Seguro que debe existir alguna forma de hacerlo funcionar, puede que sea jugando con el IgnoreRoute, pero la verdad es que así a bote pronto no conozco cuál es la forma de configurarlo. Sugiero que vuelvas a abrir la pregunta en el foro poniendo un título que exprese este problema concreto, para que llame la atención de otros usuarios que posiblemente conozcan la solución.

    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    viernes, 8 de noviembre de 2013 6:37

Todas las respuestas

  • Por defecto, todos los parámetros son obligatorios. Los que no hayas marcado como UrlParameter.Optional tienen que aparecer forzosamente en la Url, y sino no se reconoce esa ruta y se pasa a analizar la siguiente ruta que hayas definido. Si es necesario restringirlos a un formato concreto (por ejemplo, una o más letras, o sólo números), puedes añadir el parámetro "constraints" con expresiones regulares en la llamada a MapRoute:

    routes.MapRoute(
                   name: "Nombre",
                   url: "{controller}/{action}/{id}/{title}/{opc}",
                   defaults: new { controller = "Controlador", action = "Index", opc= UrlParameter.Optional},
                   constraints: new { id="[0-9]+", title="\\w+" } );

    • Propuesto como respuesta Sergio ParraModerator lunes, 4 de noviembre de 2013 22:33
    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    lunes, 4 de noviembre de 2013 21:17
  • Por defecto, todos los parámetros son obligatorios. Los que no hayas marcado como UrlParameter.Optional tienen que aparecer forzosamente en la Url, y sino no se reconoce esa ruta y se pasa a analizar la siguiente ruta que hayas definido. Si es necesario restringirlos a un formato concreto (por ejemplo, una o más letras, o sólo números), puedes añadir el parámetro "constraints" con expresiones regulares en la llamada a MapRoute:

    routes.MapRoute(
                   name: "Nombre",
                   url: "{controller}/{action}/{id}/{title}/{opc}",
                   defaults: new { controller = "Controlador", action = "Index", opc= UrlParameter.Optional},
                   constraints: new { id="[0-9]+", title="\\w+" } );

    Hola

    A mi no me los marca por defecto como obligatorios, tengo el siguiente route:

    routes.MapRoute(
                    "Categorias",     // Route name
                    "{controller}/{action}/{id}/{categoria}",                           // URL with parameters
                    new { controller = "Publicaciones", action = "Categorias", id = "", categoria = "" }  // Parameter defaults
                );

    Lo ideal es que mi url sea algo asi: www.dominio.com/controlador/action/5/categoria

    Es decir, quiero que sean ambos parametros "id y categoria" obligatorio... Si escribo en el browser www.dominio.com/controlador/action, efectivamente me da error porque el id lo toma como obligatorio, pero si escribo www.dominio.com/controlador/action/5/ "sin el nombre de la categoria", lo aprueba y me llega la categoria al controlador igual a "".

    Como puedo evitar esto? Nota: En este eje puedo obviar el 2do parametro ya que tengo el id de la categoria que es lo importante, pero es solo para mostrar un ejemplo ya que tengo otros casos donde no puedo obivar el 2do parametro.

    Otra pregunta que tengo... Desde la pagina html cargo el siguiente link:

    @Html.ActionLink("Ejemplo",
                    "Categorias", 
                    "Controlador",
                    new { id = 5, categoria = "nombre" },
                    null )

    Pero cuando renderea el enlace lo hace de la siguiente manera:

    http://localhost/Controlador/Categorias/5?categoria=nombre

    Y necesito que sea asi: 

    http://localhost/Controlador/Categorias/5/nombre

    Gracias

    • Editado Zr-.- miércoles, 6 de noviembre de 2013 16:23
    miércoles, 6 de noviembre de 2013 16:21
  • routes.MapRoute(
                    "Categorias",     // Route name
                    "{controller}/{action}/{id}/{categoria}",                           // URL with parameters
                    new { controller = "Publicaciones", action = "Categorias", id = "", categoria = "" }  // Parameter defaults
                );

    [...] Es decir, quiero que sean ambos parametros "id y categoria" obligatorio...

    Entonces no pongas en los defaults id="", categoria="". Cuando pones un default el campo deja de ser obligatorio.

    Pero cuando renderea el enlace lo hace de la siguiente manera: http://localhost/Controlador/Categorias/5?categoria=nombre

    Esto tiene toda la pinta de ser un problema de orden de definición de las rutas. Has debido definir la ruta estándar (contolador/accion/id) ANTES que la ruta controlador/accion/id/categoria.

    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    miércoles, 6 de noviembre de 2013 19:53
  • routes.MapRoute(
                    "Categorias",     // Route name
                    "{controller}/{action}/{id}/{categoria}",                           // URL with parameters
                    new { controller = "Publicaciones", action = "Categorias", id = "", categoria = "" }  // Parameter defaults
                );

    [...] Es decir, quiero que sean ambos parametros "id y categoria" obligatorio...

    Entonces no pongas en los defaults id="", categoria="". Cuando pones un default el campo deja de ser obligatorio.

    Pero cuando renderea el enlace lo hace de la siguiente manera: http://localhost/Controlador/Categorias/5?categoria=nombre

    Esto tiene toda la pinta de ser un problema de orden de definición de las rutas. Has debido definir la ruta estándar (contolador/accion/id) ANTES que la ruta controlador/accion/id/categoria.

    Hola, de hecho si. Ya con esto me enrede, crei que habia entendido lo de los controladores... Pense que el identificador o lo que determina cada rout era el nombre, controlador y accion mas no la url.

    Supongo que estos son los que chocan:

    routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
    );
    routes.MapRoute(
    "Categorias",     // Route name
    "{controller}/{action}/{id}/{categoria}",
    new { controller = "Publicaciones", action = "Categorias", id = "", categoria = "" }
    );

    Segun lo que veo y me dices esta linea "{controller}/{action}/{id}/{categoria}", no se puede repetir parte de una que ya forma un rout completo? Entonces como puedo hacer para tener multiples rout? Sera que me ayudas al menos para crear estos basicos y tomarle la idea...

    Caso 1
    Url deseada: localhost/home/index o localhost | Controlador: Home | Action: public ActionResult Index()

    Caso 2
    Url deseada: localhost/articulos/search/<titulo> | Controlador: Articulos | Action: public ActionResult Search(string titulo)

    Caso 3
    Url deseada: localhost/articulos/categorias/<id>/<categoria> | Controlador: Articulos | Action: public ActionResult Categorias(int id, string categoria)

    Caso 4
    Url deseada: localhost/servicios/search/<titulo> | Controlador: Servicios | Action: public ActionResult Search(string titulo)

    Caso 5
    Url deseada: localhost/servicios/categorias/<id>/<categoria> | Controlador: Servicios | Action: public ActionResult Categorias(int id, string categoria)

    Gracias por ayudarme
    jueves, 7 de noviembre de 2013 2:58
  • Segun lo que veo y me dices esta linea "{controller}/{action}/{id}/{categoria}", no se puede repetir parte de una que ya forma un rout completo?

    No es eso. Sí que se puede repetir. Lo que pasa es que el ORDEN en que las defines es importante, ya que el sistema las procesa por orden y se queda con la primera que le sirva, aunque más abajo hayas definido otra más detallada.

    Por eso si primero defines una ruta para controlador/accion/id y después más abajo defines otra para controlador/accion/id/categoria, y pides un actionlink con id y categoria, como lo primero que encuentra es controlador/accion/id y eso ya le sirve para construir el actionlink (poniendo ...?categoria=...), entonces no llega a examinar la siguiente opción. Por eso tienes que tener cuidado y definirlas al revés (primero controlador/accion/id/categoria y después controlador/accion/id).

    Lo mismo tienes que tener en cuenta con todas tus otras rutas: piensa que cuando llegue una URL, se va a comparar una por una con todas las rutas que hayas definido, y que en cuanto una de ellas sea aplicable (teniendo en cuenta que puede tener parámetros opcionales), entonces ya se aplica esa ruta y no se tienen en cuenta las siguientes alternativas, incluso aunque entre dichas alternativas hubiera alguna más detallada para esa URL.

    Por ejemplo, piensa en tu caso 2 y caso 4:

    localhost/articulos/search/<titulo>

    localhost/servicios/search/<titulo>

    Si intentas capturarlos poniendo para el caso 2 una ruta del tipo

    {controller}/{action}/{titulo}

    y para el 4 una así:

    servicios/{action}/{titulo}

    Entonces la 4 no se cumpliría nunca, porque se procesaría la 2 reemplazando "{controller}" por "servicios". El remedio sería definir primero la 4 y más abajo la 2.

    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    jueves, 7 de noviembre de 2013 7:07
  • Segun lo que veo y me dices esta linea "{controller}/{action}/{id}/{categoria}", no se puede repetir parte de una que ya forma un rout completo?

    No es eso. Sí que se puede repetir. Lo que pasa es que el ORDEN en que las defines es importante, ya que el sistema las procesa por orden y se queda con la primera que le sirva, aunque más abajo hayas definido otra más detallada.

    Por eso si primero defines una ruta para controlador/accion/id y después más abajo defines otra para controlador/accion/id/categoria, y pides un actionlink con id y categoria, como lo primero que encuentra es controlador/accion/id y eso ya le sirve para construir el actionlink (poniendo ...?categoria=...), entonces no llega a examinar la siguiente opción. Por eso tienes que tener cuidado y definirlas al revés (primero controlador/accion/id/categoria y después controlador/accion/id).

    Lo mismo tienes que tener en cuenta con todas tus otras rutas: piensa que cuando llegue una URL, se va a comparar una por una con todas las rutas que hayas definido, y que en cuanto una de ellas sea aplicable (teniendo en cuenta que puede tener parámetros opcionales), entonces ya se aplica esa ruta y no se tienen en cuenta las siguientes alternativas, incluso aunque entre dichas alternativas hubiera alguna más detallada para esa URL.

    Por ejemplo, piensa en tu caso 2 y caso 4:

    localhost/articulos/search/<titulo>

    localhost/servicios/search/<titulo>

    Si intentas capturarlos poniendo para el caso 2 una ruta del tipo

    {controller}/{action}/{titulo}

    y para el 4 una así:

    servicios/{action}/{titulo}

    Entonces la 4 no se cumpliría nunca, porque se procesaría la 2 reemplazando "{controller}" por "servicios". El remedio sería definir primero la 4 y más abajo la 2.

    Hola de nuevo

    Aun no logro configurar mi router... Tengo hasta ahorita los siguientes:

    public static void RegisterRoutes(RouteCollection routes)
            {
                routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
                routes.MapRoute(
                   name: "Articulos",
                   url: "{controller}/{parameter}"
                ); //ruta deseada: dominio.com/articulos/celulares-modelo
                routes.MapRoute(
                    "Categorias",
                    "{controller}/{action}/{id}/{categoria}"
                ); //ruta deseada: dominio.com/articulos/categorias/1/celulares
                routes.MapRoute(
                    name: "Default",
                    url: "{controller}/{action}/{id}",
                    defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
                ); ///dominio.com
            }

    Pero por alguna extraña razón esta me esta perjudicando con la invocación de un web service desde ajax... Tengo una carpeta llamada Ajax y en ella tengo un web service... Por lo que desde Javascript ejecuto un metodo del WebService sin ningun problema:

    url: /ajax/webservice.asmx/mimetodo

    No entiendo porque, al agregar este router

     routes.MapRoute(
                    "Categorias",
                    "{controller}/{action}/{id}/{categoria}"
                ); 

    Hace al web service incontrable desde el javascript

    Sera que sabes porque pasa esto?

    viernes, 8 de noviembre de 2013 4:07
  • No debería fallar por culpa de "{controller}/{action}/{id}/{categoria}", pero en cambio el problema que veo es que /ajax/webservice.asmx/mimetodo "encaja" dentro de la otra ruta, "{controller}/{action}/{id}", por lo que intentará llamarte a un controlador llamado "ajax" y un método "webservice.asmx" con el id="mimetodo". Normalmente cuando llamas a un aspx o un asmx, lo distingue por la extensión del archivo, pero en este caso al ponerle una "/" detrás para indicar "/mimetodo" sospecho que debe estar confundiendo al enrutador. Seguro que debe existir alguna forma de hacerlo funcionar, puede que sea jugando con el IgnoreRoute, pero la verdad es que así a bote pronto no conozco cuál es la forma de configurarlo. Sugiero que vuelvas a abrir la pregunta en el foro poniendo un título que exprese este problema concreto, para que llame la atención de otros usuarios que posiblemente conozcan la solución.

    • Marcado como respuesta Zr-.- viernes, 8 de noviembre de 2013 14:42
    viernes, 8 de noviembre de 2013 6:37
  • No debería fallar por culpa de "{controller}/{action}/{id}/{categoria}", pero en cambio el problema que veo es que /ajax/webservice.asmx/mimetodo "encaja" dentro de la otra ruta, "{controller}/{action}/{id}", por lo que intentará llamarte a un controlador llamado "ajax" y un método "webservice.asmx" con el id="mimetodo". Normalmente cuando llamas a un aspx o un asmx, lo distingue por la extensión del archivo, pero en este caso al ponerle una "/" detrás para indicar "/mimetodo" sospecho que debe estar confundiendo al enrutador. Seguro que debe existir alguna forma de hacerlo funcionar, puede que sea jugando con el IgnoreRoute, pero la verdad es que así a bote pronto no conozco cuál es la forma de configurarlo. Sugiero que vuelvas a abrir la pregunta en el foro poniendo un título que exprese este problema concreto, para que llame la atención de otros usuarios que posiblemente conozcan la solución.

    Hola de nuevo, estoy realmente agradecido por toda la ayuda brindada, hare como me indicas... Y me habia equivocado al poner la ruta en la pregunta, la ruta real del web service es:

    url: /ajax/common/webservice.asmx/mimetodo

    Voy abrir otra pregunta con ese tema en concreto...

    viernes, 8 de noviembre de 2013 13:48