2010-09-08 16 views
2

Contexte:Est-il possible de rendre les données d'une méthode d'action disponibles dans un filtre d'action?

Nous fournissions des fichiers html - « » - de wrappers notre client, dans lequel nous avons besoin pour injecter le contenu que nous produisons. Ils ont des wrappers différents pour différentes pages et nous devons injecter le contenu correspondant dans une étiquette spéciale qu'ils fournissent dans l'emballage.

Le nom du fichier d'emballage correspond au nom de la méthode d'action. Donc, pour l'exemple ci-dessous, un filtre d'action personnalisé est exécuté qui déterminera le nom de l'encapsuleur, puis appellera une méthode dans BaseController (que chaque contrôleur implémente) qui chargera l'encapsuleur et injectera notre contenu dans celui-ci.

[WrapperAction] 
    public ActionResult Home() 
    { 
     return View(); 
    } 

La raison pour laquelle je mets cela dans un ActionFilter est parce que je ne voulais pas être appeler la méthode de BaseController pour remplir l'emballage dans chaque méthode d'action qui avait besoin d'un emballage. Je pensais qu'il était beaucoup plus net pour décorer la méthode avec le ActionFilterAttribute

WrapperAction est défini comme suit:

public class WrapperAction : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext aec) 
    { 
     var baseController = (BaseController)filterContext.Controller; 

     string wrapper = aec.RequestContext.RouteData.Values["action"].ToString(); 

     baseController.PopulateWrapper(wrapper); 
    } 
} 

et PopulateWrapper est défini comme

public void PopulateWrapper(string wrapperName) 
    { 
     // get wrapper file from disk 
     Wrapper wrapper = _wrapperService.GetWrapper(Site.Id, wrapperName); 

     // populate the file with our CSS (it already has its own pre-populated CSS) 
     // our CSS file is determined by the id of a Site object. 
     AppHelper.PopulateWrapperCss(wrapper, this.Site.Id); 

     // make wrapper sections available to the Master page, 
     // split so that we can place our content around them 
     ViewData["WrapperTop"] = wrapper.WrapperTop; 
     ViewData["WrapperMiddle"] = wrapper.WrapperMiddle; 
     ViewData["WrapperBottom"] = wrapper.WrapperBottom; 
    } 

Le Dilema:

Maintenant, cependant, une nouvelle exigence est entrée. Il y a de nouveaux tags dans le wr apper que j'ai besoin de remplir, et je dois les peupler avec des données différentes en fonction de la méthode d'action qui appelle le wrapper. Ces données sont déterminées dans les méthodes d'action, mais les données doivent être utilisées dans la méthode PopulateWrapper qui est appelée par le WrapperAction.

J'ai besoin maintenant d'avoir une méthode similaire à

AppHelper.PopulateWrapperTags(wrapper, this.TagData);

et je dois avoir une certaine façon pour la propriété TagData de BaseController à être rempli avec des données. Je peux ASIGN la propriété dans la méthode d'action comme suit

[WrapperAction] 
    public ActionResult Home() 
    { 
     base.TagData = GetTagData(); 
     return View(); 
    } 

mais ce genre de défaites le point de me faire la WrapperAction en premier lieu parce que je ne veux pas avoir à se référer à la BaseController comme ça .

La question:

Est-il possible pour moi de fournir WrapperAction avec les données dont il a besoin pour remplir l'emballage avec? Ai-je besoin de prendre le coup et commencer à appeler

 var tagData = GetTagData(); 
     string wrapperName = RouteData.Values["action"].ToString(); 
     base.PopulateWrapper(wrapperName, tagData); 

dans chaque contrôleur? Y a-t-il un meilleur moyen pour moi de faire ça?

Répondre

1

Ce que vous avez déjà écrit est vraiment très bon et n'a besoin que d'un léger ajustement pour répondre à vos nouvelles exigences.

La clé est que votre filtre d'action est un type de OnActionExecuted qui fonctionne après votre code d'action est terminée, mais avant la vue est exécutée. Par conséquent, la méthode de filtrage peut s'appuyer sur tout ce qui a eu lieu dans la méthode d'action.

Pour répondre à vos besoins, créez la variable tagData dans votre contrôleur de base, afin que les contrôleurs qui en héritent puissent la remplir si nécessaire.

Ensuite, dans votre filtre d'action vous devez simplement quelque chose comme

if (tagData == null) 
    baseController.PopulateWrapper(wrapper) 
else 
    baseController.PopulateWrapper(wrapper, tagData) 

Je suis sûr que vous avez l'idée générale.

0

IMHO ce qui suit était juste, donc je ne vois pas comment le filtre d'action est plus net:

public ActionResult Home() 
{ 
    PopulateWrapper(); 
    return View(); 
} 

et dans la base de contrôleur:

public void PopulateWrapper(string wrapperName) 
{ 
    string wrapperName = RouteData.Values["action"].ToString(); 
    //... rest of populate wrapper 

vous allez:

public ActionResult Home() 
{ 
    PopulateWrapper(GetTagData()); // after defining an overload in base 
    return View(); 
} 

En supposant que vous avez toujours o La façon de filtrer l'action, je ne vois pas pourquoi vous forcer la dépendance avec la base du contrôleur avec c'est-à-dire pourquoi le PopulateWrapper est dans la base du contrôleur.

Notez que vous pouvez également transmettre les données dans ViewData, mais cela semble pire dans votre scénario - compte tenu en particulier de la dépendance dans la base du contrôleur.