127 votes

Comment simuler Server.Transfer dans ASP.NET MVC ?

En ASP.NET MVC, vous pouvez retourner une redirection ActionResult 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 correct. 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 entraîne la perte d'informations utiles telles que les termes des moteurs de recherche.

Par ailleurs, cette méthode présente l'avantage de supprimer tous les paramètres qui peuvent provenir des campagnes, mais me permet tout de même de les capturer côté serveur. En les laissant dans la chaîne de requête, on risque de voir des gens mettre en signet, sur Twitter ou sur un blog, un lien qu'ils ne devraient pas. J'ai constaté à plusieurs reprises que des personnes ont envoyé sur Twitter des liens 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 des endroits différents ou des versions alternatives.

Pour l'instant, je me soucie davantage de Google (que de la mise en signet accidentelle), et je veux pouvoir envoyer à quelqu'un qui visite / à la page qu'ils obtiendraient s'ils allaient à /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 });

qui me permettra d'obtenir cette vue sans redirection côté client. Je ne pense pas qu'une telle chose existe, cependant.

Actuellement, la meilleure chose que je puisse faire est de dupliquer toute la logique du contrôleur pour HomeController.Index(..) dans mon GatewayController.Index Action. Cela signifie que j'ai dû déplacer 'Views/Home' en 'Shared' pour qu'il soit accessible. Il doit y avoir un meilleur moyen.

0 votes

Qu'est-ce qu'un ServerTransferAction que vous essayiez de reproduire ? Est-ce une chose réelle ? (je n'ai trouvé aucune information à ce sujet... merci pour la question, d'ailleurs, la réponse ci-dessous est superbe).

1 votes

Recherchez Server.Transfer(...). C'est un moyen de faire une 'redirection' du côté du serveur où le client reçoit la page redirigée sans redirection du côté du client. En général, ce n'est pas recommandé avec le routage moderne.

1 votes

Le "transfert" est une fonctionnalité ASP.NET désuète qui n'est plus nécessaire dans MVC en raison de la possibilité de aller directement à l'action correcte du contrôleur en utilisant le routage. Voir cette réponse pour les détails.

1voto

Richard Points 831

Le routage ne s'occupe-t-il pas simplement de ce scénario pour vous ? Par exemple, pour le scénario décrit ci-dessus, vous pourriez simplement créer un gestionnaire de route qui mettrait en œuvre cette logique.

0 votes

C'est basé sur les conditions programmatiques, c'est-à-dire que la campagne 100 pourrait aller à la vue 7 et la campagne 200 pourrait aller à la vue 8 etc. etc. trop compliqué pour le routage.

4 votes

Pourquoi est-ce trop compliqué pour le routage ? Qu'est-ce qui ne va pas avec les contraintes de routage personnalisées ? stephenwalther.com/blog/archive/2008/08/07/

1voto

Stephane Legay Points 18

Pour tous ceux qui utilisent le routage basé sur les expressions, en utilisant uniquement la classe TransferResult ci-dessus, voici une méthode d'extension du contrôleur qui fait l'affaire et préserve TempData. Pas besoin de TransferToRouteResult.

public static ActionResult TransferRequest<T>(this Controller controller, Expression<Action<T>> action)
    where T : Controller
{
     controller.TempData.Keep();
     controller.TempData.Save(controller.ControllerContext, controller.TempDataProvider);
     var url = LinkBuilder.BuildUrlFromExpression(controller.Request.RequestContext, RouteTable.Routes, action);
     return new TransferResult(url);
}

1 votes

Avertissement : cette opération semble provoquer une erreur "La classe SessionStateTempDataProvider exige que l'état de la session soit activé", bien qu'elle fonctionne toujours. Je ne vois cette erreur que dans mes journaux. J'utilise ELMAH pour la journalisation des erreurs et j'obtiens cette erreur pour InProc et AppFabric.

0voto

William Points 141

Il ne s'agit pas d'une réponse en soi, mais il est clair que l'exigence serait non seulement que la navigation actuelle "fasse" la fonctionnalité équivalente de Webforms Server.Transfer(), mais aussi que tout cela soit entièrement pris en charge par 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 faire tout ce que la classe RedirectToRouteResult et aussi les diverses méthodes de la classe de base du contrôleur font, et ensuite "ajouter" ces dernières au contrôleur via des méthodes d'extension. Peut-être que ces méthodes pourraient être des méthodes statiques au sein de la même classe, pour faciliter le téléchargement ?

Si j'arrive à le faire, je le posterai, sinon quelqu'un d'autre pourrait me devancer !

0voto

Colin Points 5006

J'y suis parvenu en exploitant le Html.RenderAction dans une vue :

@{
    string action = ViewBag.ActionName;
    string controller = ViewBag.ControllerName;
    object routeValues = ViewBag.RouteValues;
    Html.RenderAction(action, controller, routeValues);
}

Et dans mon contrôleur :

public ActionResult MyAction(....)
{
    var routeValues = HttpContext.Request.RequestContext.RouteData.Values;    
    ViewBag.ActionName = "myaction";
    ViewBag.ControllerName = "mycontroller";
    ViewBag.RouteValues = routeValues;    
    return PartialView("_AjaxRedirect");
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X