Programatically listing delegate controls
UPDATE: If you are using this code and can’t load user controls, then check out my update that explains the issue and how to resolve it
Delegate Controls are in my opinion one of the cooler things you can use when putting together a UI in SharePoint (and have previously talked about rolling out web parts as delegate controls). I’ve recently come up with a need to be able to read what delegate controls are stored against a specific controlID programatically though, which can be done but you need to get a little tricky to do it.
If you pull out reflector and have a look through the DelegateControl code, you will see that in it’s CreateChildControls method it refers to a class called SPElementProvider. This is the class that provides the mechanism for retrieving the delegate controls and returning them to the DelegateControl object to render on the page. Since this is an internal class we can’t call to it directly to do what we need to, so I took to it a different way. I created an instance of a DelegateControl, set the properties and then used reflection to call the “CreateChildControls” method, which will call to the SPElementProvider to go and get the objects, and then will add them to the Controls collection of the DelegateControl.
The last bit required to make this work is adding some HttpContext if you are running your code outside of SharePoint itself (I originally wrote this as a console app to test that it would work so had to do it). Once you create the context and run the code you can easily get to the controls – speaking of the code, here it is:
using (SPSite site = new SPSite("http://serverUrl"))
{
using (SPWeb web = site.OpenWeb())
{
bool contextCreated = false;
if (HttpContext.Current == null)
{
contextCreated = true;
HttpRequest request = new HttpRequest(string.Empty, web.Url, string.Empty);
HttpContext.Current = new HttpContext(request, new HttpResponse(new StringWriter()));
HttpContext.Current.Items["HttpHandlerSPWeb"] = web;
}
DelegateControl dc = new DelegateControl
{
AllowMultipleControls = true,
ControlId = "AdditionalPageHead" //This can be whatever control Id you are looking for
};
MethodInfo method = dc.GetType().GetMethod("CreateChildControls", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(dc, null);
foreach (Control control in dc.Controls)
{
// Do something with control, it is returned as a System.Web.UI.Control here
}
if (contextCreated) HttpContext.Current = null;
}
}
So this code will work both within SharePoint and in a console app, as it will create the context only if it is needed. Outside of that you can do whatever you need to with those delegate controls once you have them!


