Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Gavin Williams 48 posts 221 karma points
    Mar 07, 2023 @ 14:54
    Gavin Williams
    0

    Umbraco 11 surface controllers / OnActionExecuting

    I'm in the process of migrating the code base from a v8 site to v11. Under v8 I could declare a surface controller that implemented OnActionExecuting so I could add whatever code needed to be run on every page request. e.g.

    public abstract class SomeController : SurfaceController
    {    
        protected override void OnActionExecuting(ActionExecutingContext filterContext)   
        {
            if (filterContext.RouteData.DataTokens.TryGetValue("ParentActionViewContext", out var val))
            {
                if (val is ViewContext ctx)
                {
                    if (ctx.Controller is RenderMvcController)
                    {
                        // if it gets here we have an umbraco page, so CurrentPage is available for use
                        var noCache = CurrentPage.GetCustomPropertyValue<bool>("noBrowserCache");
                        if (noCache)
                        {
                            Response.Cache.SetCacheability(HttpCacheability.NoCache); // HTTP 1.1.
                            Response.Cache.AppendCacheExtension("no-store, must-revalidate");
                            Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
                            Response.AppendHeader("Expires", "0"); // Proxies.
                        }
                    }
                }
            }
        }
    }
    

    I've transferred the controller over but it's behaviour is different in v11, it no longer fires on every request. Although I've managed to implement a custom filter to achieve the same thing I no longer have access to any umbraco objects e.g. in my custom filter:

    public void OnActionExecuting(ActionExecutingContext context)
    {
        if (context.RouteData.DataTokens.TryGetValue("umbraco-current-view-context", out var val))
        {
            if (val is ViewContext ctx)
            {
                if (context.Controller is RenderController ctrlr)
                {
                    // how do I get access to the page properties/values?
                    //var noCache = ctrlr.CurrentPage.GetCustomPropertyValue<bool>("noBrowserCache");
                    //    if (noCache)
                    //    {
                    //        Response.Cache.SetCacheability(HttpCacheability.NoCache); // HTTP 1.1.
                    //        Response.Cache.AppendCacheExtension("no-store, must-revalidate");
                    //        Response.AppendHeader("Pragma", "no-cache"); // HTTP 1.0.
                    //        Response.AppendHeader("Expires", "0"); // Proxies.
                    //    }
                }
            }
        }
    }
    

    Although ctrlr does have a CurrentPage object, its private. Is there a better way to achieve this or will I have to use reflection to get it? Wondering if anyone has implemented anything similar/better?

  • Gavin Williams 48 posts 221 karma points
    Mar 07, 2023 @ 16:07
    Gavin Williams
    100

    Found a solution with help from a bit of deconstructing the Umbraco objects, so putting this here in case anyone else finds it useful. So the above OnActionExecuting code is as follows (to ensure this only runs from the page request):

    if (context.RouteData.DataTokens.TryGetValue("umbraco-current-view-context", out var val))
    {
        if (val is ViewContext)
        {
            if (context.Controller is RenderController)
            {
                var routeValues = context.HttpContext.Features.Get<UmbracoRouteValues>(); // this is what the private CurrentPage property is really doing
                if (routeValues != null)
                {
                    var page = routeValues.PublishedRequest.PublishedContent;
                    var noCache = page.GetCustomPropertyValue<bool>("noBrowserCache");
                    if (noCache)
                    {
                        // do stuff
                    }
                }
            }
        }
    }
    

    Just for reference GetCustomPropertyValue

    public static T GetCustomPropertyValue<T>(this IPublishedContent content, string propertyAlias)
    {
        var prop = content?.Properties.FirstOrDefault(x => x.Alias == propertyAlias);
        if (prop == null || !prop.HasValue()) return default;
        var val = prop.GetValue();
        if (val is T) return (T) val;
        try
        {
            return (T)Convert.ChangeType(val, typeof(T));
        }
        catch (InvalidCastException)
        {
            return default;
        }
    }
    
Please Sign in or register to post replies

Write your reply to:

Draft