ASP.NET MVC | Obtener controlador actual desde una vista (Tips)

posterHoy os traigo un pequeño Tip que, a priori puede ser un poco tonto pero que a más de uno le puede salvar de horas de modificar código o de buscar la aguja en el pajar.

Escenario

Tenemos una aplicación ASP.NET MVC que tiene, dentro de las vistas, llamadas “Ajax” a acciones de la propia aplicación MVC, lo que implicará que tengamos puesto “a fuego” el controlador que queremos llamar.

Ejemplo:

$.ajax({
    url: "/MyController/MyAction",
    data: { id: myId },
    type: "GET"
}).done(function(){
    alert('DONE!!');
});
 

NOTA: Siempre hay otras formas de hacerlo más elegante.

 

Problema

Qué ocurriría si:

  • Cambiamos la acción a otro controlador
  • Cambiamos el nombre del controlador
  • Usamos la gran herramienta de todo developer “Copy/Paste” y ponemos este método en otras vistas de otros controladores

Bueno, para todas las opciones, lo que ocurre es que tendremos que estar atentos de cambiar el controlador en la “url” que estamos usando en la llamada “ajax” y esto a veces se nos puede pasar por alto y tenernos un buen rato buscando la solución al problema de que de repente no nos funcione nuestra llamada.

 

Solución

Puede haber muchas soluciones, unas más elegantes que otras como por ejemplo he visto el tener un fichero de recursos con las acciones y sus “url” correctas lo que nos permitiría tener centralizadas todas las posibles llamadas que hagamos y tan sólo tendríamos que pasarle desde el controller las acciones que va a llamar la vista. Pero no es eso lo que yo voy a exponer, sino que en este caso quiero explicar cómo hacer referencia al controlador actual desde la propia vista, con lo que nos ahorraríamos los problemas de un cambio en el controlador.

¿Y cómo conseguimos saber el controlador actual? Pues con una sencilla línea de código.

@HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()

 

Con esto, nuestra llamada Ajax podría quedar de la siguiente forma:

$.ajax({
    url: '/@HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString()/MyAction',
    data: { id: myId },
    type: "GET"
}).done(function(){
    alert('DONE!!');
});

 

NOTA: A algunos os podrá extrañar ver el código “razor” dentro de un bloque JavaScript… ¿funcionará? La respuesta es que sí, puesto que razor es capaz de identificar casi siempre el código de que le corresponde después de una @, lo que nos permite hacer cosas tan “fascinantes” y productivas como esta. Algo similar se expone en este artículo. Pero tened cuidado con no abusar de incluir código razor dentro del código JavaScript que al final puede ser peor el remedio que la enfermedad.

 

Update

Como bien apunta Javier Torrecilla, por buenas prácticas debería utilizar Url.Action para referir la url, con lo que para ser estrictamente correctos, deberíamos hacerlo de la siguiente forma.

$.ajax({
    url: '@Url.Action("MyAction", HttpContext.Current.Request.RequestContext.RouteData.Values["controller"].ToString())',
    data: { id: myId },
    type: "GET"
}).done(function(){
    alert('DONE!!');
});

 

Update 2

Un nuevo apunte de la mano de maese Eduard Tomàs que nos indica “intentar evitar la referencia binaria a HttpContext.Current siempre que se pueda y acceder a los route values a través de PageContext” con @PageContext.Page.Request.RequestContext.RouteData.Values["controller"].ToString() quedándonos de la siguiente forma nuestro código.

 

$.ajax({
    url: '@Url.Action("MyAction", PageContext.Page.Request.RequestContext.RouteData.Values["controller"].ToString())',
    data: { id: myId },
    type: "GET"
}).done(function(){
    alert('DONE!!');
});

2 Comentarios

  1. jtorrecilla

    Hola Santi,
    Lo primero buen post, pero te hago un apunte, en lugar de utilizar directamente la url, ya que podemos hacer uso de razor, aprovechemos la potencia y usemos el Helper Url.Action para que nos construya la ruta de forma correcta.

    Salu2

  2. etomas

    Evita la referencia binaria a HttpContext.Current siempre que puedas. Puedes acceder a los route values a través de PageContext:

    @PageContext.Page.Request.RequestContext.RouteData.Values[«controller»].ToString()

    Saludos!

Deja un comentario

Tema creado por Anders Norén