Pre-set common viewmodel properties before action result

0
103

So, I defined a master model that is shared by every view in my MVC site. This model defines a bunch of properties that are always used on every page, such as a page title, page description, the google tag manager code, etc.

I need this model to be filled before the action result, so that I can use those properties on the view.

In order to do this, I created a custom Action Filter Attribute that is used by every action:


    public class SetupMasterModelActionFilter : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            ViewResultBase result = filterContext.Result as ViewResultBase;
            if (result == null)
            {
                return;
            }

            MasterModel model = result.Model as MasterModel;
            if (model == null)
            {
                return;
            }

            SetupMasterModel(model);
            SetupViewBag(result, model);
        }

        private void SetupMasterModel(MasterModel model)
        {
            ...
        }

        private void SetupViewBag(ViewResultBase result, MasterModel model)
        {
            ...
        }
   }

In order to execute this filter before every action I had to register it in the GlobalFilters at the Global.asax.cs file:


        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            GlobalFilters.Filters.Add(new SetupMasterModelActionFilter());

            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }

There are, however, some pages that don’t use this master model, so I need to exclude the use of this filter on certain actions. In order to do this, I created a new Filter Provider that looks for an exclude filter and filters out the one targeted:


    public class ExcludeFilterProvider : IFilterProvider
    {
        private FilterProviderCollection filterProviders;

        public ExcludeFilterProvider(IFilterProvider[] filters)
        {
            this.filterProviders = new FilterProviderCollection(filters);
        }

        public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
        {
            Filter[] filters = this.filterProviders.GetFilters(controllerContext, actionDescriptor).ToArray();

            IEnumerable<ExcludeFilterAttribute> excludeFilters = (from f in filters where f.Instance is ExcludeFilterAttribute select f.Instance as ExcludeFilterAttribute);

            List<Type> filterTypesToRemove = new List<Type>();
            foreach (ExcludeFilterAttribute excludeFilter in excludeFilters)
            {
                filterTypesToRemove.Add(excludeFilter.FilterType);
            }

            IEnumerable<Filter> res = (from filter in filters where !filterTypesToRemove.Contains(filter.Instance.GetType()) select filter);
            return res;
        }
    }

The exclude filter attribute that will decorate the excluded actions:


    public class ExcludeFilterAttribute : FilterAttribute
    {
        private Type filterType;

        public ExcludeFilterAttribute(Type filterType)
        {
            this.filterType = filterType;
        }

        public Type FilterType
        {
            get
            {
                return this.filterType;
            }
        }
    } 

And we add the new provider at the start of the application and remove the old ones:


        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            GlobalFilters.Filters.Add(new SetupMasterModelActionFilter());

            IFilterProvider[] providers = FilterProviders.Providers.ToArray();
            FilterProviders.Providers.Clear();
            FilterProviders.Providers.Add(new ExcludeFilterProvider(providers));

            RouteConfig.RegisterRoutes(RouteTable.Routes);
        }

With this, every action will setup the master model properties except the ones that implement the exclude filter:


    public class HomeController : Controller
    {
        [ExcludeFilter(typeof(SetupMasterModelActionFilter))]
        public ActionResult Index()
        {
            HomeModel model = new HomeModel();

            return View(model);
        }
    }

LEAVE A REPLY

Please enter your comment!
Please enter your name here