views:

1220

answers:

3

Hi

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.

A long post, I know - but after six hours battling with this I thought I would be thorough in my explanation.

I hope those who can help made it this far, and thank you for reading.

Thoughts and comments would be very much appreciated.

Andrew

A: 

You need to call EnsureListsData on the SPListCollection that you just updated.

http://msdn.microsoft.com/en-us/library/microsoft.sharepoint.splistcollection.ensurelistsdata.aspx

JD
Thank you for your response but does this method not look for an existing list *instance*? I need to ensure that the list *template* can be found, so that I can subsequently create an instance of the list. (Also intellisense does not seem to offer this particular method after I have got the SPListCollection object.)Andrew
Andrew Vevers
+1  A: 

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

AndrewWoody
Excellent - thanks very much Andrew. I shall make those changes. Andrew
Andrew Vevers
A: 

Seems that the list template is not yet created. You can try to do a loop and wait to be created

        using(SPWeb web = site.OpenWeb())
        {
            SPListTemplate listTemplate = null;
            while (listTemplate == null)
            {
                Thread.Sleep(1000);
                try
                {
                    listTemplate = web.ListTemplates["Custom Access List"];
                    if (listTemplate != null)
                    {
                        // here your code 
                        web.Lists.Add("My new custom access list", "", listTemplate);
                    }
                }
                catch
                {
                    web = site.OpenWeb();
                }
            }
        }
Ciprian Grosu