My SharePoint feature receiver activates a list definition feature, but my code cannot see the list template until the "second pass"

Andrew Vevers picture Andrew Vevers · Jan 21, 2010 · Viewed 7.7k times · Source

I am into my sixth hour battling with what hopefully should have a simple solution, so I thought I would post here.

I have an feature with a feature receiver whose sole purpose is to activate a deployed list definition feature and then create an instance of that new list definition.

The list definition feature, called "Custom Access List", is scoped at web.

So my feature receiver activates this list definition feature, having GUID "1E503BDA-803B-4a1a-A042-019FA1A70C4C":

...
string featureGuid = "1E503BDA-803B-4a1a-A042-019FA1A70C4C";        // my 'Custom     try
{
    SPFeatureCollection featureCollection = web.Features;
    featureCollection.Add(new Guid(featureGUID), true); // activat the 'Custom Access List' feature
}
catch (Exception e)
{
    // log exception
}

This code executes fine, and the list definition feature is activated, and the new list definition appears in the "Create" site menu option in the UI.

However, this is where my issue starts. The next line of my feature receiver code then tries to create an instance of this newly-available list:

SPListTemplate listTemplate = web.ListTemplates["Custom Access List"];            // exception! Value does not fall within the expected range
web.Lists.Add("My new custom access list","", listTemplate);

But the line SPListTemplate listTemplate = web.ListTemplates["Custom Access List"]; throws an exception with "Value does not fall within the expected range." - the list template, despite being deployed, visible and available in the UI under the "Create" site menu action, cannot be found in the receiver code.

Debugging the code confirms that the web.ListTemplates SPListTemplateCollection does not contain a entry for this new "Custom Access List", despite the UI suggesting otherwise.

And here is the weird thing. An exception is thrown, but if I then re-run the code i.e. reactivate the feature in the UI, to re-execute that feature receiver, the list template is then found -

SPListTemplate listTemplate = web.ListTemplates["Custom Access List"];            // found this time. It sees it the second time around
web.Lists.Add("My new custom access list","", listTemplate);      // works fine

So, in a nutshell - initially, after activating a feature which, through receiver code, activates a list definition feature, that list definition is not visible until after a "postback" or some form of "SPWeb refresh". Then it is visible.

Am I missing something here? A call of web.Update() here:

try
{
    SPFeatureCollection featureCollection = web.Features;
    featureCollection.Add(new Guid(featureGUID), true); // true to force activation
    web.Update();
}
...

does nothing. Is there some way I can "refresh" the SPWeb object so that the new list template can be seen and used?

The workaround I have found, for now, is to add the "Custom Access List" list template feature as an activation dependency in the "parent" feature receiver itself, and to make the "Custom Access List" list template feature hidden. That way, to my knowledge, the custom list definition feature is forcibly activated and I find that web.ListTemplates["Custom Access List"]; is found.

But I would much rather the former approach work - to activate, in my receiver code, the list definition feature and then to find it so that an instance of the list can then be created.

Answer

AndrewWoody picture AndrewWoody · Jan 22, 2010

Andrew,

The problem is to do with internal async events and the timing of the activity. As you say if you go away and come back it works - i.e. the async event has completed. You are treating the featureCollection.Add as a synchronus method.

What you really should be doing if you need a template and a list instance created at the same time is using the XML framework for this.

Add a to your feature that has the list template, or alternatively add a new feature for the list instance and reference the FeatureID of the list template.

Andrew