asp.net-mvcasp.net-mvc-3autofacviewdata

How to set ViewBag properties for all Views without using a base class for Controllers?


In the past I've stuck common properties, such as the current user, onto ViewData/ViewBag in a global fashion by having all Controllers inherit from a common base controller.

This allowed my to use IoC on the base controller and not just reach out into global shared for such data.

I'm wondering if there is an alternate way of inserting this kind of code into the MVC pipeline?


Solution

  • Un-tried by me, but you might look at registering your views and then setting the view data during the activation process.

    Because views are registered on-the-fly, the registration syntax doesn't help you with connecting to the Activated event, so you'd need to set it up in a 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";
                };
            }
        }
    }
    

    This might be one of those "only tool's a hammer"-type suggestions from me; there may be simpler MVC-enabled ways to get at it.

    Edit: Alternate, less code approach - just attach to the Controller

    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: Another approach that works directly from the controller registration code:

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