Sandboxing – Declarative Object Provisioning and Threads
Declaratively adding list items to a new list is a pretty standard and useful feature of SharePoint. Here’s a basic sample, assuming a list definition with template type of 10101:
<?xml version="1.0" encoding="utf-8" ?>
Description=" Employee height in meters "
But enter Sandboxed Solutions. Try it out, and there is a pretty good chance that you’ll start running into issues with fields not being defined. “Of course it’s defined – I’m in the list instance feature itself!” Certainly you’ll want to make sure that you’re properly referencing the fields with their proper names, since that would usually be the most likely problem, but there’s a very good chance that you did everything right.
So what gives?
Sandboxed solutions only have access to a subset of the SharePoint API. When the code runs, it’s in a special sandboxed worker process with a separate proxy process that hosts the SharePoint API. If you think of it as one process looking at instructions and executing them, and when it comes across one that needs the SharePoint API it passes that along to the proxy process for execution, you’ll do just fine. For all practical purposes, this is more than enough understanding.
Well, why are we talking about this? Creating the list and populating it are both tasks that are implicitly handled by the proxy process. Some code interprets your XML and spawns threads to complete the required tasks. The execution path looks something like:
HEY I NEED TO MAKE A LIST -> Tell Proxy to make a list -> Execution thread gets spawned to make the list
HEY I NEED TO POPULATE THE LIST -> Tell Proxy to populate a list -> Execution thread gets spawned to populate it
This is by no means an exact roadmap, but definitely close enough for us to see the issue. Why is this a problem? There is a very good chance that the first thread isn’t done doing its thing when the second starts to populate it. And that’s why it can’t find the fields that it’s looking for. And that’s why you can’t reliably add data to a list declaratively from a sandboxed solution.
The first solution that I thought of (and if you have a better one please leave it in the comments) involved programmatically creating and then populating the list using the object model. Since your code is just going to be blocking while the other thread is doing its thing, the list will actually exist when you try to programmatically add items to it on subsequent lines. Here’s what that would generally look like:
Guid gList = web.Lists.Add("HeightList", "Employee height in meters", "Lists/HeightList", "GUID_OF_FEATURE", 10101, "", SPListTemplate.QuickLaunchOptions.Off);
SPList oList = web.Lists[gList];
prepop = oList.Items.Add();
prepop["Title"] = "Duke";
prepop["Height"] = 2.0;
prepop = oList.Items.Add();
prepop["Title"] = "Cindy";
prepop["Height"] = 1.67;
This works fine in a sandbox, though I don’t feel that it is very elegant. Since Sandboxed solutions will likely go the way of the dinosaur in light of the new App model in 2013, you may never need to care about this situation. That said, if you do run into this issue, it’s good to know a little about why it is happening and have a workaround – elegant or not.