Dependency Injection into Pages and UserControls using Unity

Edit (8 Nov 2008): Turns out… Not so much the async postbacks, and more to do with a FormView not having initialized it’s controls at the point in time in the page lifecycle (on PostBack only, after Page Init). This can be tested by using a quick watch on the protected Control.ChildControlsCreated property in the debugger. Additionally, by touching the Controls collection of the formview it actually causes the controls from within the template to not be loaded on the postback.

The solution (and new rule!): Do NOT touch FormView.Controls at all (to get either Count or iterate) instead test beforehand using Control.HasControls() before iterating. (Note: the case where user controls are inside a FormView template will means those controls won’t have their dependencies injected on PostBack)

From the original source code I replaced the original recursive control tree function with some additional functionality including the fix for HasControls() and to make it more reusable later:

// Build up each control in the page's control tree private void OnPageInitComplete(object sender, EventArgs e) { Page page = (Page)sender; IUnityContainer container = IocContainer; // Lambda delegate for controls to apply BuildUp on // and delegate for injection. Func<Control, bool> shouldApplyFunction = (c => (c is UserControl || c is Page || c is MasterPage)); Action<Control> injectIntoControl = (c => container.BuildUp(c.GetType(), c)); // Recurse tree RecurseControlTree(page.Controls, injectIntoControl, shouldApplyFunction); } private void RecurseControlTree(ControlCollection controls, Action<Control> actionToApply, Func<Control, bool> shouldApplyActionFunction) { foreach (Control child in controls) { // Iterate children first if (child.HasControls()) { RecurseControlTree(child.Controls, actionToApply, shouldApplyActionFunction); } // Apply function if (shouldApplyActionFunction(child)) { actionToApply(child); } } }

Hope that helps someone!!! (End edit)

Having recently started playing with using the Unity framework for dependency (but without going the whole hog and using the WCSF libraries), I was after a HttpModule or Handler of some kind that will deal with the injection of dependencies into my pages, user controls, and master pages.

I found a lovely little helper module and pattern by Espresso Fueled Agile Development that almost did the trick perfectly… With one exception… When doing an AJAX postback within an UpdatePanel, things went screwy.

Now, I’ve no idea why, but the problem actually lies with the attempt to traverse the Controls collection for all controls within the page. It turns out that spmething or other doesn’t like it’s ControlCollection to be scrutinized during an AJAX-intiated postback. So don’t! (As long as you don’t need any injected dependencies in your handlers!)

As far as I’m aware the only way to know if a postback is from an AJAX control this early in the pipeline you’ll have to call ScriptManager‘s IsInAsyncPostBack property. Thus in the UnityHttpModule, replace OnPageInitComplete with the following:

// Build up each control in the page's control tree private void OnPageInitComplete(object sender, EventArgs e) { Page page = (Page)sender; IUnityContainer container = IocContainer; var currentScriptManager = ScriptManager.GetCurrent(page); if (currentScriptManager == null || !currentScriptManager.IsInAsyncPostBack) { foreach (Control c in GetControlTree(page)) { container.BuildUp(c.GetType(), c); } } }

As a side, another thing to remember is that since it’s difficult to get a hook into the instantiation of pages, you need to use Dependency declarations on the public properties rather than Injection attributes on constructors.



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s