OdeToCode IC Logo

Hacking Up A Glimpse Plugin

Friday, March 15, 2013

Glimpse is highly extensible. If there is something you want to know about on the server, it's relatively easy to write a plugin that will feed data to the Glimpse dashboard. There is some documentation in the Glimpse GitHub wiki on writing an extension. This post provides a slightly more complex example to show how a Glimpse dashboard tab can interact with data collectors using a message broker.

The Scenario

Let's say you are adding additional IDisplayMode objects into the global ASP.NET MVC DisplayModeProvider. These display modes will select device specific views (an iPhone view, a Kindle Fire view, etc). Now, you want to look in the Glimpse dashboard to easily see what providers are registered, the order of evaluation, and which of the providers the runtime selected for a particular request.

The Filter

There are various extension points in ASP.NET MVC that will let you tap into the processing pipeline. Quite a bit of the core Glimpse.Mvc3 package relies on proxy objects that wrap runtime components (like the view engines) and feed data to Glimpse when interesting things happen (how a view is selected, for example). Once you find a way to tap into the runtime, feeding data to Glimpse is the easy part.

One way to tap into the runtime is to use a global filter (perhaps not the best approach, but it is simple for this demonstration). Here is a result filter that will find the current display mode being used and send the mode to Glimpse as part of a message.

public class GlimpseDisplayModeDump : IResultFilter
{
    private readonly IMessageBroker _broker;

    public GlimpseDisplayModeDump(IMessageBroker broker)
    {
        _broker = broker;
    }

    public void OnResultExecuting(ResultExecutingContext filterContext)
    {

    }

    public void OnResultExecuted(ResultExecutedContext filterContext)
    {
        var mode = filterContext.DisplayMode;
        if (_broker != null)
        {
            _broker.Publish(new DisplayModeMessage(mode));
        }
    }
}

The key to the Glimpse <-> IResultFilter interaction is the Glimpse message broker. The message broker allows us to publish messages of any type, and an interested party can subscribe to these messages and aggregate or summarize information from the messages. When the filter executes, it will look at the display mode for the request (passed by MVC as part of the filter context), and pass the mode as part of a message via the message broker.

The Message

The message itself is a simple object that encapsulates the display mode and provides a simple property to retrieve the name (ModeId) of the display mode.

public class DisplayModeMessage
{
    public DisplayModeMessage(IDisplayMode mode)
    {
        Mode = mode;
    }

    public IDisplayMode Mode { get; set; }

    public string ModeId
    {
        get { return Mode.GetName(); }
    }
}

In the above code, GetName is an extension method to compute the name of a display mode. In MVC, the IDisplayMode interface doesn't provide a lot of information, so we'll check to see if the object is actually a DefaultDisplayMode object.

public static class DisplayModeExtensions
{
    public static string GetName(this IDisplayMode mode)
    {
        var asDefault = mode as DefaultDisplayMode;
        if (asDefault != null)
        {
            if (!String.IsNullOrEmpty(asDefault.DisplayModeId))
            {
                return asDefault.DisplayModeId;
            }
            return "Default DefaultDisplayMode";
        }
        if(mode != null)
        {
            return mode.GetType().Name;    
        }
        return "None";
    }
}

The Tab

An object implementing the Glimpse ITab interface has a 1:1 correlation with tabs that appear in the client-side dashboard. It is the job of the tab to provide a name that appears in the dashboard, and to provide data to display in the tab when Glimpse is ready. Here's a tab to show the display mode data.

public class DisplayModeTab : TabBase, ITabSetup
{
    public void Setup(ITabSetupContext context)
    {
        GlobalFilters.Filters.Add(new GlimpseDisplayModeDump(context.MessageBroker));
        context.PersistMessages<DisplayModeMessage>();
    }

    public override object GetData(ITabContext context)
    {
        var result = new List<object[]>();
        var message = context.GetMessages<DisplayModeMessage>().FirstOrDefault();
        var id = message != null ? message.ModeId : "<none>";

        result.Add(new object[] { "Key", "Value" });
        result.Add(new object[] { "Selected Display Mode", id });
        result.Add(new object[] { "All Display Modes",                                 
                          DisplayModeProvider.Instance
                                             .Modes
                                             .Select(mode => mode.GetName()).ToArray()
                                });
        return result;
    }

    public override string Name
    {
        get { return "DisplayMode"; }
    }
}

The GetData method is the key to producing data for a request. In this sample the code will find the DisplayModeMessage for the request, as well as look at all of the registered display modes, and produce a loose collection of what is essentially key/value pairs of data for display. 

The Result

All of the above code can go directly into your MVC project, or into a separate assembly with a reference to Glimpe.Core (the preferred approach). Once the assembly is in the web app's bin directory, Glimpse will pick it up and start interacting with the tab to show data in the browser dashboard. More advanced formatting is possible, too.

image