104 votes

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

Dans le passé, je bloquais des 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 me limiter au partage global de ces données.

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

263voto

Mirak Points 164

La meilleure façon consiste à utiliser ActionFilterAttribute et à enregistrer votre classe personnalisée dans votre global. asax (Application_Start)

 public class UserProfilePictureActionFilter : ActionFilterAttribute
{

    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;
        }
    }

}
 

inscrivez 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
 

39voto

Brandon Linton Points 2306

Comme les propriétés ViewBag sont, par définition, liées à la présentation de la vue et à toute logique de vue claire qui pourrait être nécessaire, je créerais un WebViewPage de base et définirais les propriétés lors de l'initialisation de la page. C'est très similaire au concept d'un contrôleur de base pour la logique répétée et les fonctionnalités communes, mais pour vos vues:

     public abstract class ApplicationViewPage<T> : WebViewPage<T>
    {
        protected override void InitializePage()
        {
            SetViewBagDefaultProperties();
            base.InitializePage();
        }

        private void SetViewBagDefaultProperties()
        {
            ViewBag.GlobalProperty = "MyValue";
        }
    }
 

Et ensuite, en \Views\Web.config , définissez la propriété pageBaseType :

 <system.web.webPages.razor>
    <host factoryType="System.Web.Mvc.MvcWebRazorHostFactory, System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <pages pageBaseType="MyNamespace.ApplicationViewPage">
      <namespaces>
        <add namespace="System.Web.Mvc" />
        <add namespace="System.Web.Mvc.Ajax" />
        <add namespace="System.Web.Mvc.Html" />
        <add namespace="System.Web.Routing" />
      </namespaces>
    </pages>
  </system.web.webPages.razor>
 

21voto

Nicholas Blumhardt Points 9208

L'onu a essayé par moi-même, mais vous pouvez regarder l'enregistrement de votre point de vue et puis paramétrage de l'affichage des données pendant le processus d'activation.

Parce que les vues sont enregistrées à la volée, l'enregistrement de la syntaxe ne permet pas de vous connecter à l' Activated de l'événement, vous aurez besoin de définir 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 l'un de ces "seul outil est un marteau"de type suggestions de moi; il y a peut être plus simple MVC-permis de façons d'obtenir à elle.

Edit: Alternes, moins de code à l'approche juste l'attacher à la manette

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<Config>();
                viewBag.Identity = e.Context.Resolve<IIdentity>();
            };
        }
    }
}

Edit 2: une Autre approche qui fonctionne directement à partir du contrôleur de code d'enregistrement:

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

17voto

Michael Gagne Points 151

Le message de Brandon est juste sur l'argent. En fait, je voudrais aller un peu plus loin et dire que vous devez simplement ajouter vos objets communs en tant que propriétés de la base WebViewPage afin que vous n'ayez pas à convertir les éléments du ViewBag dans chaque vue. Je fais ma configuration CurrentUser de cette façon.

9voto

jfar Points 19380

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 : ActionFilterAttribute 
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        filterContext.Result = new ViewResult() {ViewData = new ViewDataDictionary()};

        base.OnActionExecuting(filterContext);
    }
}
 

Un projet MVC 2 était-il ouvert, mais les deux techniques s'appliquent toujours avec des modifications mineures.

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