Comment définir les propriétés de ViewBag pour toutes les vues sans utiliser de classe de base pour les contrôleurs?

Dans le passé, j’ai bloqué les propriétés communes, telles que l’utilisateur actuel, sur ViewData / ViewBag de manière globale en faisant en sorte que tous les contrôleurs héritent d’un contrôleur de base commun.

Cela m’a permis d’utiliser IoC sur le contrôleur de base et de ne pas simplement atteindre le partage global pour de telles données.

Je me demande s’il existe une autre façon d’insérer ce type de code dans le pipeline MVC?

Non essayé par moi, mais vous pouvez envisager d’ enregistrer vos vues , puis de définir les données d’affichage pendant le processus d’activation.

Les vues étant enregistrées à la volée, la syntaxe d’enregistrement ne vous aide pas à vous connecter à l’événement Activated , vous devez donc le configurer dans un Module :

 class SetViewBagItemsModule : Module { protected override void AttachToComponentRegistration( IComponentRegistration registration, IComponentRegistry registry) { if (typeof(WebViewPage).IsAssignableFrom(registration.Activator.LimitType)) { registration.Activated += (s, e) => { ((WebViewPage)e.Instance).ViewBag.Global = "global"; }; } } } 

Cela pourrait être une de ces suggestions de type “seulement l’outil un marteau” de moi; il peut y avoir des moyens plus simples pour utiliser MVC.

Edit: Alterner, moins d’approche de code – attachez juste au contrôleur

 public class SetViewBagItemsModule: Module { protected override void AttachToComponentRegistration(IComponentRegistry cr, IComponentRegistration reg) { Type limitType = reg.Activator.LimitType; if (typeof(Controller).IsAssignableFrom(limitType)) { registration.Activated += (s, e) => { dynamic viewBag = ((Controller)e.Instance).ViewBag; viewBag.Config = e.Context.Resolve(); viewBag.Identity = e.Context.Resolve(); }; } } } 

Edit 2: une autre approche qui fonctionne directement à partir du code d’enregistrement du contrôleur:

 builder.RegisterControllers(asm) .OnActivated(e => { dynamic viewBag = ((Controller)e.Instance).ViewBag; viewBag.Config = e.Context.Resolve(); viewBag.Identity = e.Context.Resolve(); }); 

Le meilleur moyen consiste à utiliser ActionFilterAtsortingbute et à enregistrer votre classe personnalisée dans votre global. asax (Application_Start)

 public class UserProfilePictureActionFilter : ActionFilterAtsortingbute { public override void OnResultExecuting(ResultExecutingContext filterContext) { filterContext.Controller.ViewBag.IsAuthenticated = MembershipService.IsAuthenticated; filterContext.Controller.ViewBag.IsAdmin = MembershipService.IsAdmin; var userProfile = MembershipService.GetCurrentUserProfile(); if (userProfile != null) { filterContext.Controller.ViewBag.Avatar = userProfile.Picture; } } } 

enregistrer votre classe personnalisée dans votre global. asax (Application_Start)

 protected void Application_Start() { AreaRegistration.RegisterAllAreas(); GlobalFilters.Filters.Add(new UserProfilePictureActionFilter(), 0); } 

Ensuite, vous pouvez l’utiliser dans toutes les vues

 @ViewBag.IsAdmin @ViewBag.IsAuthenticated @ViewBag.Avatar 

Il y a aussi une autre façon

Créer une méthode d’extension sur HtmlHelper

 [Extension()] public ssortingng MyTest(System.Web.Mvc.HtmlHelper htmlHelper) { return "This is a test"; } 

Ensuite, vous pouvez l’utiliser dans toutes les vues

 @Html.MyTest() 

Étant donné que les propriétés ViewBag sont, par définition, liées à la présentation de la vue et à toute logique de visualisation de la lumière éventuellement nécessaire, je créerais une base WebViewPage et définirais les propriétés lors de l’initialisation de la page. C’est très similaire au concept de contrôleur de base pour la logique répétée et les fonctionnalités communes, mais pour votre sharepoint vue:

  public abstract class ApplicationViewPage : WebViewPage { protected override void InitializePage() { SetViewBagDefaultProperties(); base.InitializePage(); } private void SetViewBagDefaultProperties() { ViewBag.GlobalProperty = "MyValue"; } } 

Et puis, dans \Views\Web.config , définissez la propriété pageBaseType :

            

Le message de Brandon est juste sur l’argent. En fait, je voudrais aller plus loin et dire que vous devez simplement append vos objects communs en tant que propriétés de la base WebViewPage afin de ne pas avoir à transtyper les éléments de ViewBag dans chaque vue. Je fais ma configuration CurrentUser de cette façon.

Vous pouvez utiliser un ActionResult personnalisé:

 public class GlobalView : ActionResult { public override void ExecuteResult(ControllerContext context) { context.Controller.ViewData["Global"] = "global"; } } 

Ou même un ActionFilter:

 public class GlobalView : ActionFilterAtsortingbute { public override void OnActionExecuting(ActionExecutingContext filterContext) { filterContext.Result = new ViewResult() {ViewData = new ViewDataDictionary()}; base.OnActionExecuting(filterContext); } } 

Avait un projet MVC 2 ouvert mais les deux techniques s’appliquent toujours avec des modifications mineures.

Si vous voulez vérifier la compilation et intellisense pour les propriétés dans vos vues, alors ViewBag n’est pas la solution.

Considérons une classe BaseViewModel et que vos autres modèles de vue héritent de cette classe, par exemple:

Base ViewModel

 public class BaseViewModel { public bool IsAdmin { get; set; } public BaseViewModel(IUserService userService) { IsAdmin = userService.IsAdmin; } } 

Afficher le ViewModel spécifique

 public class WidgetViewModel : BaseViewModel { public ssortingng WidgetName { get; set;} } 

Maintenant, le code de vue peut accéder à la propriété directement dans la vue

 

Is Admin: @Model.IsAdmin

Vous n’avez pas à vous soucier des actions ou à modifier le modèle, utilisez simplement un contrôleur de base et lancez le contrôleur existant à partir du contexte de la présentation.

Créez un contrôleur de base avec les données communes souhaitées (titre / page / emplacement, etc.) et l’initialisation de l’action …

 public abstract class _BaseController:Controller { public Int32 MyCommonValue { get; private set; } protected override void OnActionExecuting(ActionExecutingContext filterContext) { MyCommonValue = 12345; base.OnActionExecuting(filterContext); } } 

Assurez-vous que chaque contrôleur utilise le contrôleur de base …

 public class UserController:_BaseController {... 

Convertissez le contrôleur de base existant à partir du contexte de vue dans votre page _Layout.cshml

 @{ var myController = (_BaseController)ViewContext.Controller; } 

Vous pouvez maintenant vous référer aux valeurs de votre contrôleur de base depuis votre page de disposition.

 @myController.MyCommonValue 

J’ai trouvé que l’approche suivante était la plus efficace et donnait un excellent contrôle en utilisant le fichier _ViewStart.chtml et les instructions conditionnelles si nécessaire:

_ ViewStart :

 @{ Layout = "~/Views/Shared/_Layout.cshtml"; var CurrentView = ViewContext.Controller.ValueProvider.GetValue("controller").RawValue.ToSsortingng(); if (CurrentView == "ViewA" || CurrentView == "ViewB" || CurrentView == "ViewC") { PageData["Profile"] = db.GetUserAccessProfile(); } } 

ViewA :

 @{ var UserProfile= PageData["Profile"] as List; } 

Note :

PageData fonctionnera parfaitement dans les vues; Cependant, dans le cas d’une vue partielle, il faudra passer de la vue à l’enfant partiel.