Friday, 10 August 2012

Using Reflection to Force Evaluation of Parameterized Static Methods on Controls without requiring an Instance to be Loaded

At my current Telecommunications client, we have been using EpiServer CMS and associated frameworks (essentially ASP.NET webforms) to develop their website.

We have the concept of "Accordion" controls which are essentially a group of user controls sitting inside an ASP.NET repeater that are loaded based on CMS configuration settings. The user controls are only loaded when the user clicks to expand one of these accordions.

This presented a problem because we wanted to access settings and properties of those user controls to determine whether to display the title outside the user control or not (before any of those user controls were loaded).

I initially thought of using events and delegates - but that wouldn't work because they would require us to spin up instances the controls to get those to fire (not ideal).

Instead of this, we used a nice trick (thanks Marcus for the idea) with reflection which calls a static method on each of those user controls. Any instance objects we needed to use in the static class, we just passed in as a parameter to our User control's method.

This meant that we could use reflection on the static method for each of our user controls - and it would return to use whether we should hide or show the title for that control. We put the type name in the CMS so it would know what user control type and method it should Invoke (without even loading the control). To easly allow instances our dependency-injected controllers to be called from this static method, we just passed them in as parameters to the static method as below:

A code snippet of the meat of the method is as below:

        public static bool GetIsAccordionAndTitleVisible(string typeName, IServiceController serviceController)
        {
            var type = Type.GetType(typeName);

            if (type != null)
            {
                var result = true;
                System.Reflection.MethodInfo mi = type.GetMethod("GetIsControlTitleVisible");
                if (mi != null)
                {
                    var p = new object[1]; //Invoke requires object array for parameters
                    p[0] = serviceController;
                    result = (bool) mi.Invoke(null, p);
                }
                return result;
            }
            return true; //Default=true.
        }

In this way, we can defer logic to user controls that haven't even been loaded yet. We could have also used our Registry to access our dependency-injected service controller as an alternative to the IServiceController parameter on GetIsControlTitleVisible()

2 comments:

Marcus and Eliza said...
This comment has been removed by the author.
Marcus Babajews said...

Hey David,

The solution seems to be working well and hasn't created any problems so far.

I will write back if we find any issues relating to this solution.

Thanks again,
Marcus Babajews