Thursday, 4 July 2013

A simple Orchard module to inject a diagnostics shape into every page of your Orchard site

Orchard has some great extensibility hooks. This post will show you how to very quickly use one to add a diagnostic section (like below) to the top of each page.


This uses:
  • A feature in a module: to toggle on/off the ability
  • A class implementing Orchards FilterProvider
  • A view file to be used as a shape

First thing to do is create a new module, with a feature inside. If you need a primer, try the Orchard Walkthrough and the Hello World Module example. This article assumes that you create a module called "MyModule", and that you make a feature called "MyModule.SessionChecker"

To write output to every page we can hook into the FilterProvider class provided by the Orchard framework. Orchard.Mvc.Filters.FilterProvider is an abstract class that implements IDependency. This means that if your feature implements the class, it will automatically be wired up by Orchard at run time. All you need to do is fill in the methods of the class in your own inherited version, like below.


Code:
    [OrchardFeature("MyModule.SessionChecker")]
    public class SessionCheckerFilter : FilterProvider, IResultFilter
    {
        private readonly IWorkContextAccessor _workContextAccessor;
        private readonly IShapeFactory _shapeFactory;

        public SessionCheckerFilter(IWorkContextAccessor workContextAccessor, IShapeFactory shapeFactory)
        {
            _workContextAccessor = workContextAccessor;
            _shapeFactory = shapeFactory;
        }

        public void OnResultExecuting(ResultExecutingContext filterContext)
        {
            if (filterContext.Result as ViewResult == null) {
                return;
            }

            _workContextAccessor.GetContext(filterContext).Layout.Zones["Body"].Add(_shapeFactory.Create("diagnosticview"), ":before");
        }

        public void OnResultExecuted(ResultExecutedContext filterContext) { }
    }

The key things we are doing here are

  • Using the OnResultExecuting method to ensure we hook in as the result is being formed
  • Creating a new shape and returning it inside the body zone of the page 
The use of shapes is a massive topic in Orchard, and there are others out there better suited to talking about them. For this purpose it is enough to say that we use the IShapeFactory to create an arbitrary shape. The name of this shape is the name of a razor view that we need to create in our views folder in the module.

Add the file diagnosticsview.cshtml to the "views" folder in your module. The shape factory will find and use this shape. I've made my example as follows:

 <style> 
   .SessionChecker {  
     position:absolute;  
     left:0px;  
     top:0px;  
     z-index:100;  
     border:solid 1pt #AAAAAA;  
     background-color: #EEEEEE;  
     padding: 5px;  
     font-family: consolas, arial;  
     font-size: 10pt;  
   }  
   .SessionChecker b {  
     font-weight: bold;  
   }  
 </style>
 <div class="SessionChecker">  
   Current Value for Session["TestSessionManagement"]: @Session["TestSessionManagement"]  
 </div>  

And all this does is show the value of a particular session setting I'm interested in, but you could make yours much more interesting. Any loigic more complex than that shown should be done within the FilterProvider class you implemented, and be passed to the view as a model

Lastly, make sure to enable your module/feature to see the results. When you don't want them appearing any more, disable the module! Excellent for temporary diagnostic scenarios. For added bonus - only show it when the current user is an admin!

2 comments:

  1. Great article! Btw - the described technique of injecting scripts/styles via filters can be also useful in lots of other scenarios, not necessarily diagnostics;)

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete