WSS 3.0 Web Services : Some issues and Workarounds Part 1
Here, I write about few interesting scenarios, findings and workarounds while using SharePoint v3 webservices over the last couple of months.
UpdateListItems and ContentTypes : Its about an Issue when using UpdateListItems to create a new Item in a Document Library having more than one content type.
Scenario: We use the "UpdateListItems" method from the Lists.asmx service in order to update a list item located in a list created from a custom list definition.The list definition is made up from 3 different content types. We need to update the content type on the list item and a few other fields.
- First Off, I created a custom Document Library definition (named it 'MyDocumentLibrary') with another extra Content Type (in this test I added - Dublin Core Columns) and EnableContentTypes="TRUE" in the <List> element in schema.xml (Its same as OOB Document Library in all other aspects).
<ContentTypes> <ContentTypeRef ID="0x0101"> <Folder TargetName="Forms/Document" /> </ContentTypeRef> <ContentTypeRef ID="0x0120" /> <ContentTypeRef ID="0x01010B"> </ContentTypeRef> </ContentTypes>
- Made necessary changes to provision this as a Feature. (See How to: Create a Custom List Definition)
Then, I used below code which calls UpdateListItems from Lists webservice, to create a new Item in the new Doc Lib I just created (For more Info :How to: Update List Items )
string xml = "<Batch OnError='Continue'><Method ID='1' Cmd='New'><Field Name='ID'/><Field Name='Title'>whatsup3</Field><Field Name='ContentType'><![CDATA[Dublin Core Columns]]>
</Field></Method></Batch>";
XmlDocument doc = new XmlDocument();
doc.LoadXml(xml);
XmlNode batchNode = doc.SelectSingleNode("//Batch");
listProxy.Url = "https://<server:port>/_vti_bin/Lists.asmx";
listProxy.UseDefaultCredentials = true;
XmlNode resultNode = listProxy.UpdateListItems("MyDocumentLibrary", batchNode);
Although I specified ‘Dublin Core Columns’ as the ContentType, the if I inspect the 'ContentType' field of the Item just added it still shows as ‘Document’ . But I want this one to be a ‘Dublin Core Columns’ type!!
There is a way to get it working - For the Library we just created , If you observe the “ContentType” field’s schema using code , it is defined this way :
<Field ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}"
RowOrdinal="0" Type="Text" DisplayName="Content Type"
ReadOnly="TRUE"
Name="ContentType" DisplaceOnUpgrade="TRUE"
SourceID="https://schemas.microsoft.com/sharepoint/v3"
StaticName="ContentType" ColName="tp_ContentType"
Group="_Hidden" PITarget="MicrosoftWindowsSharePointServices"
PIAttribute="ContentTypeID" FromBaseType="TRUE" />
However, If I go to Library Settings page and change the ContentType order (DocumentLibrary Settings -> 'Change New button order and Default Content Type')the ‘Content Type’ field is changed to a ‘Choice’ type field :
<Field RowOrdinal="0" Type="Choice" Format="Dropdown"
FillInChoice="FALSE" Sealed="FALSE" Name="ContentType"
ColName="tp_ContentType"
SourceID="https://schemas.microsoft.com/sharepoint/v3"
ID="{c042a256-787d-4a6f-8a8a-cf6ab767f12d}"
DisplayName="Content Type"
StaticName="ContentType" Group="_Hidden"
PITarget="MicrosoftWindowsSharePointServices" PIAttribute="ContentTypeID">
<Default>Document</Default>
<CHOICES>
<CHOICE>Document</CHOICE>
<CHOICE>Mail Item</CHOICE>
<CHOICE>Folder</CHOICE>
</CHOICES>
</Field>
and above UpdateListItems code will work while adding an item with a non-default Content Type (in this case ‘Dublin Core Columns’) . Now, my customer’s requirement was to fully automate the process of :
- Deploying custom List Definition with custom Content Types (more than one)
- Distributing an Outlook add-in to end-users which will use OOB Webservices to :
a)Create document libraries based on the custom List Definition. b)Then create few default items in them based on various content types.
However, the finding above that by default , for a newly created Library – although it contains multiple content types - the schema of ‘ContentType’ field in the Library is set as Type=’Text’ and ReadOnly="TRUE", it prevents OOB UpdateListItems to work as intended in step b) above.
The manual workaround of going to “Change New button order and Default Content Type” and changing the order (it just has to be done once – and order is immaterial- can be changed back to original) was the road-block to this kind of automation.
Interestingly, if we use OM code to upload a File & create an item in a Library -and specify a non-default ContentType - it worked. That is why I believe its something wrong with UpdateListItems that it cannot convert the “ContentType” from ‘TEXT’ to ‘CHOICE’.
Phew...hours went in researching & trying a lot of things including UpdateList method of Lists.asmx, but no go....
Ultimately, We had to settle with the workaround of packaging below OM code as a custom SharePoint webservice to achieve the transition of the internal ‘ContentType’ field from ‘Text’ and ‘ReadONLY’ to a ‘Choice’ and write-able Schema :
Below code snippet will achieve what we did on the 'Change New button order and Default Content Type' page (ChangeContentTypeOrder.aspx)
SPSite ss = new SPSite("https://moss/sites/Test/");
SPWeb ww = ss.OpenWeb();
SPList list4 = ww.Lists["MyDocumentLibrary"];
SPContentType type5 = list4.ContentTypes["Document"];
SPContentType type6 = list4.ContentTypes["Dublin Core Columns"];
SPContentType[] typeArray2 = new SPContentType[] { type5, type6 };
list4.RootFolder.UniqueContentTypeOrder = typeArray2;
list4.RootFolder.Update()[] { type5, type6 };
It also shows how to change ContentType Order programmatically.
Comments
Anonymous
November 04, 2009
The comment has been removedAnonymous
November 26, 2009
I've got the same error when trying to change DisplayName of the field within SPContentType, to be more precisely I changed DisplayName and called spContentType.Update(true) - and this thrown the error...Anonymous
January 11, 2010
I had the same problem. Thanks for the solution. It saved me lots of time.Anonymous
February 15, 2010
Thank you very much. If you are not changing the order of the content types, you can try this: list4.RootFolder.UniqueContentTypeOrder = list4.RootFolder.ContentTypeOrder; list4.RootFolder.Update();Anonymous
February 25, 2010
Thankx...I was facing the same issue for quite some time. Really helpful article!!!