Page View Event

Vote:
 

Is there a way to register an event to a page view ?

For an example when an CMS content page is displayed/loaded i wanna trigger an event, is this possible.

I have already tried the DataFactory.Instance.LoadedContent event, but this is triggered to often. The page i view, and all other content that page is somehow using (blocks, images, etc.).

I just want to trigger this event once each time a page is loaded.

#151559
Edited, Jul 28, 2016 15:39
Vote:
 

It's kind of tricky for the underlaying API to know when you actually View a page. As you probably notice "Loaded Content" might also mean that you load the content to list it, or just get property values from it.

Most of the time when this is done, we usually do that in the aspx or controller (depending on WebForms or MVC).
To simplify the implementation, make sure that you have a separate class with the stuff you want to do.

Such as

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    ContentView.ContentIsViewed(this.CurrentPage);
}

or

public override ActionResult Index(MyPage currentPage)
{
    ContentView.ContentIsViewed(currentPage);
}

and in your class something like

public static class ContentView
{
    public static void ContentIsViewed(PageData page)
    {
        // ... do something
    }
}

Also look at how base classes of your templates and controllers can help you. Keep in mind that only because all of your pages want to do this, a base class might not be the best solution.

#151561
Jul 28, 2016 16:37
Vote:
 

The thing is i want this to be like a plugin, added through nuget and it automaticly begins hooking up as events.

I dont want to have to manually need to change the code or add code to every possible page controller etc.

#151566
Jul 28, 2016 20:23
Vote:
 

Hi Mattias,

Can you give us more details? What exactly are you trying to achieve? Can you use global filters?

#151568
Jul 29, 2016 0:24
Vote:
 

We want to devolop a plugin where you log things on each page view. The thought is you install this plugin and configure it and it works out of the box. There shouldent be any need to rebuild or change the code for each page controller to get it working.

Global filters ? are this some base MVC thing ?

#151570
Jul 29, 2016 7:03
Vote:
 

I was looking for a MVC solution but couldent think of the actionfilters that you could register them globaly. With an global action filter and resolving the url to a content and comparing the actionfilter context controller type agains the controller type of the current page i could managed to filter out other results like blocks and souch that are executed in the same page view.

Thanks for the tip about action filters.

Here is my code if anyone needs something similar.

public class PageViewActionFilterAttribute : ActionFilterAttribute
    {
        public override void OnActionExecuted(ActionExecutedContext filterContext)
        {
            base.OnActionExecuted(filterContext);

            var content = UrlResolver.Current.Route(new UrlBuilder(filterContext.RequestContext.HttpContext.Request.Url.PathAndQuery));
            if (content != null)
            {
                var contentTypeRepository = ServiceLocator.Current.GetInstance<IContentTypeRepository>();
                var templateResolver = ServiceLocator.Current.GetInstance<TemplateResolver>();
                var type = contentTypeRepository.Load(content.ContentTypeID);

                var template = templateResolver.ResolveMvcTemplate(filterContext.HttpContext, type);
                if (filterContext.Controller.GetType().Equals(template.TemplateType))
                {
                    Debug.WriteLine($"ACTION Executed: {filterContext.RequestContext.HttpContext.Request.Url.PathAndQuery}");
                }
            }
        }
    }
#151571
Jul 29, 2016 8:02
Vote:
 

You can also check if the current controller is PageController<T>.

public class PageViewActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);

        if (IsPageController(filterContext.Controller.GetType()))
        {
            Debug.WriteLine($"ACTION Executed: {filterContext.RequestContext.HttpContext.Request.Url.PathAndQuery}");
        }
    }

    private bool IsPageController(Type type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(PageController<>))
        {
            return true;
        }

        return type.BaseType != null && IsPageController(type.BaseType);
    }
}
#151572
Edited, Jul 29, 2016 8:40
Vote:
 

Yes, that might have been a quicker aproach, but if there is somehow a link on the current page to another page causing this to be rendered to i might get duplicate page view logs.

But i just want to log the actual page being viewed, so i think my aproach of checking the filter context controller against the content controller is a more precise aproach.

#151573
Jul 29, 2016 9:09
Vote:
 

I'm not sure what you mean. Debug.WriteLine will execute only once. Do you have an example where it executes more than once (in Alloy perhaps)?

#151574
Edited, Jul 29, 2016 9:18
Vote:
 

What i mean is if a page is viewed and that page has linked content like a link to another page and on this page it is rendered as an action like @Html.Action(). Then that could result in a log hit for the original page and the linked page eg. Html.Action() if this page could be resolved as PageController<>.

#151576
Jul 29, 2016 11:16
Vote:
 

Ok, I get what you mean now :)

@Html.Action on Index action is not that common, at least not on PageController<>.

In your approach, Debug.WriteLine can also be executed several times as nothing prevents a developer from calling @Html.Action on the same controller (doesn't even have to be index action).

To make sure Debug.WriteLine is called only once (for Index action, and no child actions), the following code can be used:

public class PageViewActionFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        base.OnActionExecuted(filterContext);

        if (IsPageController(filterContext.Controller.GetType()) &&
            !filterContext.IsChildAction &&
            filterContext.ActionDescriptor.ActionName.Equals("index", StringComparison.InvariantCultureIgnoreCase))
        {
            Debug.WriteLine($"ACTION Executed: {filterContext.RequestContext.HttpContext.Request.Url.PathAndQuery}");
        }
    }

    private bool IsPageController(Type type)
    {
        if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(PageController<>))
        {
            return true;
        }

        return type.BaseType != null && IsPageController(type.BaseType);
    }
}

Hope this helps.

#151577
Jul 29, 2016 12:06
Vote:
 

Yes that might be true, i will experiment some on this.

#151579
Jul 29, 2016 12:38
* You are NOT allowed to include any hyperlinks in the post because your account hasn't associated to your company. User profile should be updated.