Dans ASP.NET MVC, vous pouvez renvoyer un ActionResult de redirection assez facilement:
return RedirectToAction("Index");
or
return RedirectToRoute(new { controller = "home", version = Math.Random() * 10 });
Cela donnera en fait une redirection HTTP, ce qui est normalement bien. Cependant, lorsque vous utilisez Google Analytics, cela pose de gros problèmes car le référent d'origine est perdu et Google ne sait donc pas d'où vous venez. Cela perd des informations utiles telles que les termes des moteurs de recherche.
En passant, cette méthode a l'avantage de supprimer tous les paramètres pouvant provenir de campagnes mais me permet quand même de les capturer côté serveur. Les laisser dans la chaîne de requête amène les gens à mettre en favori ou à twitter ou à bloguer un lien qu'ils ne devraient pas. J'ai vu cela plusieurs fois où des gens ont envoyé des liens Twitter vers notre site contenant des identifiants de campagne.
Quoi qu'il en soit, j'écris un contrôleur de «passerelle» pour toutes les visites entrantes sur le site que je peux rediriger vers différents endroits ou des versions alternatives.
Pour l'instant, je me soucie plus de Google pour le moment (que de la mise en signet accidentelle), et je veux pouvoir envoyer quelqu'un qui visite /
la page qu'il obtiendrait s'il allait /home/7
, qui est la version 7 d'une page d'accueil.
Comme je l'ai déjà dit, si je fais cela, je perds la possibilité pour Google d'analyser le référent:
return RedirectToAction(new { controller = "home", version = 7 });
Ce que je veux vraiment, c'est un
return ServerTransferAction(new { controller = "home", version = 7 });
ce qui me donnera cette vue sans redirection côté client. Je ne pense pas qu'une telle chose existe cependant.
Actuellement, la meilleure chose que je puisse proposer est de dupliquer toute la logique du contrôleur HomeController.Index(..)
dans mon GatewayController.Index
action. Cela signifie que je devais passer 'Views/Home'
en 'Shared'
sorte qu'il était accessible. Il doit y avoir un meilleur moyen ?? ..
la source
ServerTransferAction
que vous essayez de reproduire exactement ? Est-ce une chose réelle? (jeif
déclaration est une solution trop tentante.RouteBase
pour que vous puissiez y mettre votreif
déclaration au lieu de tout plier en arrière pour passer d'un contrôleur à un autre?Réponses:
Que diriez-vous d'une classe TransferResult? (basé sur la réponse de Stans )
Mise à jour: fonctionne maintenant avec MVC3 (en utilisant le code de l'article de Simon ). Il devrait (n'a pas pu le tester) également fonctionner dans MVC2 en vérifiant s'il s'exécute ou non dans le pipeline intégré d'IIS7 +.
Pour une transparence totale; Dans notre environnement de production, nous n'utilisons jamais directement TransferResult. Nous utilisons un TransferToRouteResult qui à son tour appelle exécute le TransferResult. Voici ce qui fonctionne réellement sur mes serveurs de production.
Et si vous utilisez T4MVC (sinon ... faites!), Cette extension peut être utile.
En utilisant ce petit bijou, vous pouvez faire
la source
Edit: mis à jour pour être compatible avec ASP.NET MVC 3
Si vous utilisez IIS7, la modification suivante semble fonctionner pour ASP.NET MVC 3. Merci à @nitin et @andy d'avoir signalé que le code d'origine ne fonctionnait pas.
Edit 4/11/2011: TempData rompt avec Server.TransferRequest à partir de MVC 3 RTM
Modification du code ci-dessous pour lever une exception - mais aucune autre solution pour le moment.
Voici ma modification basée sur la version modifiée par Markus du message original de Stan. J'ai ajouté un constructeur supplémentaire pour prendre un dictionnaire de valeurs de route - et je l'ai renommé MVCTransferResult pour éviter toute confusion selon laquelle il pourrait s'agir simplement d'une redirection.
Je peux maintenant faire ce qui suit pour une redirection:
Ma classe modifiée:
la source
Vous pouvez utiliser Server.TransferRequest sur IIS7 + à la place.
la source
J'ai découvert récemment qu'ASP.NET MVC ne prend pas en charge Server.Transfer (), j'ai donc créé une méthode stub (inspirée de Default.aspx.cs).
la source
Ne pourriez-vous pas simplement créer une instance du contrôleur vers lequel vous souhaitez rediriger, invoquer la méthode d'action souhaitée, puis renvoyer le résultat? Quelque chose comme:
la source
otherController.ControllerContext = this.ControllerContext;
Je voulais réacheminer la demande actuelle vers un autre contrôleur / action, tout en gardant le chemin d'exécution exactement le même que si ce deuxième contrôleur / action était demandé. Dans mon cas, Server.Request ne fonctionnerait pas car je voulais ajouter plus de données. C'est en fait l'équivalent du gestionnaire actuel exécutant un autre HTTP GET / POST, puis diffusant les résultats vers le client. Je suis sûr qu'il y aura de meilleures façons d'y parvenir, mais voici ce qui fonctionne pour moi:
Votre hypothèse est juste: j'ai mis ce code dans
et je l'utilise pour afficher les erreurs aux développeurs, alors qu'il utilisera une redirection régulière en production. Notez que je ne voulais pas utiliser la session ASP.NET, la base de données ou d'autres moyens de transmettre des données d'exception entre les demandes.
la source
Plutôt que de simuler un transfert de serveur, MVC est toujours capable de faire un Server.TransferRequest :
la source
Instancez simplement l'autre contrôleur et exécutez sa méthode d'action.
la source
Vous pouvez mettre à jour l'autre contrôleur et appeler la méthode d'action renvoyant le résultat. Cela vous obligera cependant à placer votre vue dans le dossier partagé.
Je ne sais pas si c'est ce que vous entendez par dupliquer mais:
Éditer
Une autre option pourrait être de créer votre propre ControllerFactory, de cette façon vous pouvez déterminer quel contrôleur créer.
la source
Le routage ne s'occupe-t-il pas uniquement de ce scénario pour vous? c'est-à-dire que pour le scénario décrit ci-dessus, vous pouvez simplement créer un gestionnaire d'itinéraire qui implémente cette logique.
la source
Pour toute personne utilisant le routage basé sur une expression, utilisant uniquement la classe TransferResult ci-dessus, voici une méthode d'extension de contrôleur qui fait l'affaire et préserve TempData. Pas besoin de TransferToRouteResult.
la source
Server.TransferRequest
est complètement inutile dans MVC . Il s'agit d'une fonctionnalité obsolète qui n'était nécessaire que dans ASP.NET car la demande arrivait directement à une page et il devait y avoir un moyen de transférer une demande vers une autre page. Les versions modernes d'ASP.NET (y compris MVC) ont une infrastructure de routage qui peut être personnalisée pour acheminer directement vers la ressource souhaitée. Il ne sert à rien de laisser la demande atteindre un contrôleur uniquement pour la transférer vers un autre contrôleur lorsque vous pouvez simplement faire la demande aller directement au contrôleur et à l'action que vous souhaitez.De plus, puisque vous répondez à la demande d' origine , il n'est pas nécessaire de rentrer quoi que ce soit dans
TempData
ou autre stockage juste pour le plaisir d'acheminer la demande au bon endroit. Au lieu de cela, vous arrivez à l'action du contrôleur avec la demande d'origine intacte. Vous pouvez également être assuré que Google approuvera cette approche car elle se déroule entièrement du côté serveur.Bien que vous puissiez faire pas mal des deux
IRouteConstraint
etIRouteHandler
, le point d'extension le plus puissant pour le routage est laRouteBase
sous - classe. Cette classe peut être étendue pour fournir à la fois des routes entrantes et la génération d'URL sortantes, ce qui en fait un guichet unique pour tout ce qui a à voir avec l'URL et l'action exécutée par l'URL.Donc, pour suivre votre deuxième exemple, pour aller de
/
à/home/7
, vous avez simplement besoin d'un itinéraire qui ajoute les valeurs d'itinéraire appropriées.Mais pour revenir à votre exemple d'origine où vous avez une page aléatoire, c'est plus complexe car les paramètres d'itinéraire ne peuvent pas changer au moment de l'exécution. Ainsi, cela pourrait être fait avec une
RouteBase
sous - classe comme suit.Qui peut être enregistré dans le routage comme:
Notez que dans l'exemple ci-dessus, il peut être judicieux de stocker également un cookie enregistrant la version de la page d'accueil sur laquelle l'utilisateur est entré, de sorte qu'à son retour, il reçoive la même version de la page d'accueil.
Notez également qu'en utilisant cette approche, vous pouvez personnaliser le routage pour prendre en compte les paramètres de la chaîne de requête (il les ignore complètement par défaut) et acheminer vers une action de contrôleur appropriée en conséquence.
Exemples supplémentaires
la source
Server.TransferRequest
n'est pas, après tout, "complètement inutile dans MVC".Ce n'est pas une réponse en soi, mais il est clair que l'exigence serait non seulement que la navigation réelle "fasse" la fonctionnalité équivalente de Webforms Server.Transfer (), mais aussi que tout cela soit entièrement pris en charge dans les tests unitaires.
Par conséquent, le ServerTransferResult doit «ressembler» à un RedirectToRouteResult et être aussi similaire que possible en termes de hiérarchie de classes.
Je pense faire cela en regardant Reflector, et en faisant ce que font la classe RedirectToRouteResult et aussi les différentes méthodes de la classe de base Controller, puis en "ajoutant" ce dernier au Controller via des méthodes d'extension. Peut-être que cela pourrait être des méthodes statiques au sein de la même classe, pour faciliter / paresser le téléchargement?
Si j'arrive à le faire, je le posterai, sinon peut-être que quelqu'un d'autre pourrait me battre!
la source
J'ai réalisé cela en exploitant l'
Html.RenderAction
assistant dans une vue:Et dans mon contrôleur:
la source