En ASP.NET MVC puede devolver un ActionResult de redireccionamiento con bastante facilidad:
return RedirectToAction("Index");
or
return RedirectToRoute(new { controller = "home", version = Math.Random() * 10 });
Esto realmente dará una redirección HTTP, que normalmente está bien. Sin embargo, cuando se utiliza Google Analytics, esto causa grandes problemas porque el árbitro original se pierde, por lo que Google no sabe de dónde viene. Esto pierde información útil, como los términos de cualquier motor de búsqueda.
Como nota al margen, este método tiene la ventaja de eliminar cualquier parámetro que pueda haber provenido de campañas, pero aún así me permite capturarlos del lado del servidor. Dejarlos en la cadena de consulta lleva a las personas a marcadores o twitter o blog un enlace que no deberían. He visto esto varias veces donde las personas han twitteado enlaces a nuestro sitio que contienen ID de campaña.
De todos modos, estoy escribiendo un controlador 'gateway' para todas las visitas entrantes al sitio que puedo redirigir a diferentes lugares o versiones alternativas.
Por ahora me importa más acerca de Google por ahora (que los marcadores accidentales), y quiero poder enviar a alguien que visite /
la página que obtendrían si fueran /home/7
, que es la versión 7 de una página de inicio.
Como dije antes. Si hago esto, pierdo la capacidad de Google para analizar el referente:
return RedirectToAction(new { controller = "home", version = 7 });
Lo que realmente quiero es un
return ServerTransferAction(new { controller = "home", version = 7 });
lo que me dará esa vista sin una redirección del lado del cliente. Sin embargo, no creo que tal cosa exista.
Actualmente, lo mejor que se me ocurre es duplicar toda la lógica del controlador HomeController.Index(..)
en mi GatewayController.Index
Acción. Esto significa que tenía que mover 'Views/Home'
en 'Shared'
lo que era accesible. ¿¿Debe haber una mejor manera??..
fuente
ServerTransferAction
que intentabas replicar? ¿Eso es algo real? (no pude encontrar ninguna información al respecto ... gracias por la pregunta, por cierto, la respuesta a continuación es excelente)if
declaración es una solución demasiado tentadora.RouteBase
para que puedas poner tuif
declaración allí en lugar de doblar todo hacia atrás para saltar de un controlador a otro?Respuestas:
¿Qué tal una clase TransferResult? (basado en la respuesta de Stans )
Actualizado: ahora funciona con MVC3 (usando el código de la publicación de Simon ). se debe (no haber sido capaz de probarlo) también trabajan en MVC2 al observar si o no se está ejecutando dentro de la canalización integrada de IIS 7 +.
Para total transparencia; En nuestro entorno de producción, nunca hemos usado TransferResult directamente. Utilizamos un TransferToRouteResult que a su vez las llamadas ejecutan TransferResult. Esto es lo que realmente se está ejecutando en mis servidores de producción.
Y si estás usando T4MVC (si no ... ¡hazlo!), Esta extensión puede ser útil.
Usando esta pequeña gema puedes hacer
fuente
Editar: actualizado para ser compatible con ASP.NET MVC 3
Siempre que esté usando IIS7, la siguiente modificación parece funcionar para ASP.NET MVC 3. Gracias a @nitin y @andy por señalar que el código original no funcionó.
Edición 4/11/2011: TempData rompe con Server.TransferRequest a partir de MVC 3 RTM
Modificó el código a continuación para lanzar una excepción, pero no hay otra solución en este momento.
Aquí está mi modificación basada en la versión modificada de Markus de la publicación original de Stan. Agregué un constructor adicional para tomar un diccionario de valor de ruta y le cambié el nombre a MVCTransferResult para evitar la confusión de que podría ser solo una redirección.
Ahora puedo hacer lo siguiente para una redirección:
Mi clase modificada:
fuente
Puede usar Server.TransferRequest en IIS7 + en su lugar.
fuente
Descubrí recientemente que ASP.NET MVC no es compatible con Server.Transfer (), así que he creado un método de código auxiliar (inspirado en Default.aspx.cs).
fuente
¿No podría simplemente crear una instancia del controlador al que le gustaría redirigir, invocar el método de acción que desea y luego devolver el resultado? Algo como:
fuente
otherController.ControllerContext = this.ControllerContext;
Quería redirigir la solicitud actual a otro controlador / acción, manteniendo la ruta de ejecución exactamente igual que si se solicitara ese segundo controlador / acción. En mi caso, Server.Request no funcionaría porque quería agregar más datos. En realidad, esto es equivalente al controlador actual que ejecuta otro HTTP GET / POST y luego transmite los resultados al cliente. Estoy seguro de que habrá mejores formas de lograr esto, pero esto es lo que funciona para mí:
Su suposición es correcta: puse este código en
y lo estoy usando para mostrar errores a los desarrolladores, mientras que usará una redirección regular en producción. Tenga en cuenta que no quería usar la sesión ASP.NET, la base de datos u otras formas de pasar datos de excepción entre solicitudes.
fuente
En lugar de simular una transferencia de servidor, MVC todavía es capaz de hacer un servidor .
fuente
Simplemente instale el otro controlador y ejecute su método de acción.
fuente
Puede renovar el otro controlador e invocar el método de acción que devuelve el resultado. Sin embargo, esto requerirá que coloque su vista en la carpeta compartida.
No estoy seguro de si esto es lo que querías decir con duplicado, pero:
Editar
Otra opción podría ser crear su propia ControllerFactory, de esta manera puede determinar qué controlador crear.
fuente
¿El enrutamiento no solo se ocupa de este escenario por ti? es decir, para el escenario descrito anteriormente, podría crear un controlador de ruta que implementara esta lógica.
fuente
Para cualquiera que use enrutamiento basado en expresiones, usando solo la clase TransferResult anterior, aquí hay un método de extensión de controlador que hace el truco y preserva TempData. No hay necesidad de TransferToRouteResult.
fuente
Server.TransferRequest
es completamente innecesario en MVC . Esta es una característica anticuada que solo era necesaria en ASP.NET porque la solicitud llegó directamente a una página y tenía que haber una manera de transferir una solicitud a otra página. Las versiones modernas de ASP.NET (incluido MVC) tienen una infraestructura de enrutamiento que se puede personalizar para enrutar directamente al recurso que se desea. No tiene sentido dejar que la solicitud llegue a un controlador solo para transferirla a otro controlador cuando simplemente puede hacer que la solicitud vaya directamente al controlador y la acción que desee.Lo que es más, es que ya estás respondiendo a la solicitud original , no hay necesidad de meter nada en
TempData
u otro almacenamiento solo por el hecho de enrutar la solicitud al lugar correcto. En cambio, llega a la acción del controlador con la solicitud original intacta. También puede estar seguro de que Google aprobará este enfoque, ya que ocurre completamente en el lado del servidor.Si bien puedes hacer un poco de ambos
IRouteConstraint
yIRouteHandler
, el punto de extensión más poderoso para el enrutamiento es laRouteBase
subclase. Esta clase se puede ampliar para proporcionar rutas entrantes y generación de URL salientes, lo que lo convierte en una ventanilla única para todo lo que tenga que ver con la URL y la acción que ejecuta la URL.Entonces, para seguir su segundo ejemplo, para llegar
/
a/home/7
, simplemente necesita una ruta que agregue los valores de ruta apropiados.Pero volviendo a su ejemplo original donde tiene una página aleatoria, es más complejo porque los parámetros de ruta no pueden cambiar en tiempo de ejecución. Por lo tanto, podría hacerse con una
RouteBase
subclase de la siguiente manera.Que se puede registrar en rutas como:
Tenga en cuenta que en el ejemplo anterior, podría tener sentido almacenar también una cookie que registre la versión de la página de inicio en la que entró el usuario para que cuando regrese reciba la misma versión de la página de inicio.
Tenga en cuenta también que con este enfoque puede personalizar el enrutamiento para tener en cuenta los parámetros de la cadena de consulta (los ignora por completo de forma predeterminada) y enrutarlos a una acción de controlador adecuada en consecuencia.
Ejemplos adicionales
fuente
Server.TransferRequest
, después de todo, no es "completamente innecesario en MVC".No es una respuesta per se, pero claramente el requisito sería no solo para que la navegación real "haga" la funcionalidad equivalente de Webforms Server.Transfer (), sino también que todo esto sea totalmente compatible con las pruebas unitarias.
Por lo tanto, ServerTransferResult debería "verse" como un RedirectToRouteResult y ser lo más similar posible en términos de la jerarquía de clases.
Estoy pensando en hacer esto mirando Reflector, y haciendo cualquier clase de RedirectToRouteResult y también los diversos métodos de la clase base del Controlador, y luego "agregando" este último al Controlador a través de métodos de extensión. ¿Quizás estos podrían ser métodos estáticos dentro de la misma clase, para facilitar / hacer más lenta la descarga?
Si llego a hacerlo, lo publicaré, de lo contrario, ¡tal vez alguien más podría ganarme!
fuente
Logré esto aprovechando el
Html.RenderAction
ayudante en una Vista:Y en mi controlador:
fuente