October 19, 2011 - 12:01, by Steven Van de Craen
Categories: SharePoint 2007, SharePoint 2010, Content Types
Ever enabled Content Types on a library, removed the default “Document” Content Type and then added your own document Content Type ? If you do it in that order it will set “Folder” as the Content Type for uploaded files.
There’s no apparent way in the user interface to change the default Content Type, since “Folder” is not visible in the list:
If you don’t have a lot of lists already or you can only access SharePoint through the browser, the quickest way to fix this is to add the default “Document” Content Type to the list and immediately remove it again.
If (like in my case) you already have a lot of lists, you can script the Content Type Ordering:
using (SPSite site = new SPSite(url)) { foreach (SPWeb web in site.AllWebs) { foreach (SPList list in web.GetListsOfType(SPBaseType.DocumentLibrary)) { if (list.ContentTypes["Main Document"] != null) { SPFolder folder = list.RootFolder; List<SPContentType> lstCT = new List<SPContentType>(); lstCT.Add(list.ContentTypes["Main Document"]); folder.UniqueContentTypeOrder = lstCT; folder.Update(); } } web.Close(); } }
The above code loops all libraries on all sites in a Site Collection and sets my “Main Document” Content Type as the only (and default) Content Type. If you have different needs feel free to adapt as required.
March 5, 2011 - 12:40, by Steven Van de Craen
Categories: Content Types, SharePoint 2010
In my post yesterday I raised the question about Content Type syndication using the Content Type Hub mechanism, and how this would work together with Lookup Fields, since they don’t support crossing Site Collection boundaries.
Another question is in regard to the “challenges” of using OOXML (docx, dotx, …) templates with Content Types: Office 2007 document templates and Content Types in SharePoint – lessons learned. The main question was whether or not the Content Type Hub would improve the situation.
Configuration
Configure Content Type Syndication
You can follow this quick rundown on the Content Type Hub by Wictor Wilén:
Plan your SharePoint 2010 Content Type Hub carefully
I like the idea of creating a dedicated Site Collection for managing your Content Types.
The Hub: define Content Types and Publishing Settings
I’ve created a Content Type called “Specific Document X” with the following fields:
- a Lookup to the Tasks list
- an Enterprise Keywords field
- a Person field
- a text field called “Simple Field” with a default value CTHUB for the Hub
Next, go into the “Manage publishing for this content type” option of the Content Type settings and Publish the Content Type. See the aforementioned guide on how to make run the Content Type Subscriber Job immediately so you don’t have to wait for results.
The syndication occurs for all Site Collections in all Web Applications configured with the specific Managed Metadata Service.
The Subscriber
In the subscribing Site Collection the Content Type is added after the Subscriber Job has run. Most of the settings are locked down because they’re maintained in the Hub.
You can however go to Site Columns and modify the columns there. Not sure if this is supported
Experiences
Lookup Fields
Lookup Fields are copied if the Subscriber has the Lookup List defined as well. The fields are connected to the list on the Subscriber as expected, since the Site Collection boundary on Lookup Fields still exists.
If the Lookup List does not exist the Field will not be present on the Subscriber. The error log on the Hub will mention this:
Field default values
The “Simple Field” had a default value, which is of course pushed to all Subscribers. You can change the value on the Subscriber if you want, but if the Content Type is Republished in the Hub, the changes will be overwritten.
Document template “challenges”
Once a document is added to SharePoint, a ‘snapshot’ of the Content Type info is inserted as Custom XML Part (OOXML). This XML updates when the Content Type is changed, but it doesn’t when a referenced field changes (like the default value).
I had little hopes for improvement, as this is not really an issue of Content Types but more of the field update mechanism and/or OOXML inner workings.
A quick test with the “Simple Field” proved that this issue still exists in SharePoint 2010, even when changing the default value in the Hub itself, those changes aren’t pushed to the template. So it would definitely not be pushed to the Subscribers. The test with dotx rather than docx didn’t change the outcome.
So in these scenario’s a custom fix up script is still required to force the document template to resync it’s information from SharePoint.
Finally
I’m glad I got an answer to some questions I’ve been having with SharePoint 2010 and the Content Type Hub. I didn’t know what it would bring extra to the table in a SharePoint 2010 environment, but now I have a much clearer image. There’s a lot of potential in the Hub, but as always requires good planning and troubleshooting skills :)
January 6, 2011 - 17:47, by Steven Van de Craen
Categories: Content Types, SharePoint 2007, WSS 3.0, MOSS 2007
Today is trouble solving day at a customer. One of the issues was a SharePoint Library on their Intranet having a required field, even though Require that this column contains information was set to “No”.
So I opened up SharePoint Manager 2007 to inspect the SchemaXml:
Required="FALSE" NumLines="6" Sortable="FALSE" ID="{36cc12a9-811f-4348-9494-45fdb6c561a2}" Version="12" StaticName="Attached_x0020_to" SourceID="{70650B4E-B343-42B9-AF4E-7BE6245FCC4B}" ColName="ntext2" RowOrdinal="0" RichText="FALSE" AllowHyperlink="TRUE" RichTextMode="Compatible" IsolateStyles="FALSE" AppendOnly="FALSE" UnlimitedLengthInDocumentLibrary="FALSE" />
Seems fine by me.
The field was a standard “Multiple lines of text” field, in a standard Document Library. It didn’t have Multiple Content Types enabled or anything or anything fancy was used. No JavaScript on the Edit Form was causing this nor was the Edit Form tampered with in SharePoint Designer 2007.
I tried switching the required field on and off through UI and code, but to no avail.
SPList list = web.GetList(listUrl);
SPField field = list.Fields["Attached to"];
field.Required = false;
field.Update();
So I decided to duplicate the problematic field in code, to see if any combination of properties was causing this; no luck.
SPList list = web.GetList(listUrl);
list.Fields.AddFieldAsXml("");
Deleting the field and recreating it fixed the issue, but I didn’t want to go there because there were a lot of documents with version history already using the field.
Switching Multiple Content Types on and off didn’t seem to do much. When enabled my field wasn’t used by the default Document Content Type. This was awkward because it should have. Investigating further on this showed that SharePoint Manager 2007 did link the Content Type and Field together, and that the FieldRef was set as “Required”.
http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">DocumentLibraryForm
DocumentLibraryFormDocumentLibraryForm
So there was my issue and I could start working on a fix. No configuration or coding seemed to work however. I tried export and import using Chris O’Brien’s Content Deployment Wizard. My plan was to export the individual files, recreate the bugged field manually and then import again, hoping the metadata would be mapped correctly. But that didn’t work.
In the end I was so desperate I turned to modifying the record in the Content Database directly, something that’s totally unsupported and shouldn’t be done. If you do, thread careful, or better yet, don’t thread there at all…
UPDATE AllLists
SET tp_ContentTypes = 'http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">DocumentLibraryForm
DocumentLibraryFormDocumentLibraryForm
'
WHERE tp_ID = '70650B4E-B343-42B9-AF4E-7BE6245FCC4B'
Probably with more time it would have worked with a combination of Import/Export and some coding.
Problem was solved, but can’t help feeling a bit dirty…
March 10, 2010 - 20:13, by Steven Van de Craen
Categories: Content Types, InfoPath, MOSS 2007, Search Server 2008, SharePoint 2007, WSS 3.0
When you have multiple Form Content Types with each their respective form templates assigned to the same Form Library by some magic it will automatically save a new form in the correct Content Type. How it does this ?
The new form’s XML contains an InfoPath processing instruction with a “href” attribute set to the XSN template URL. At save time the Content Types configured in the Form Library are iterated and a match is made based on Template URL. If no match is found it will use the default Content Type.
Even works in code if you do a SPFileCollection.Add() so no need to specify the Content Type explicitly during saves !
It doesn’t seem to take Alternate Access Mappings into account so that’s a bit of a downer, but still powerful.
January 29, 2010 - 15:09, by Steven Van de Craen
Categories: .NET, Content Types, Debugging, MOSS 2007, Office 2003, Office 2007, Search Server 2008, SharePoint 2007, WSS 3.0
A while ago I stumbled upon a serious design limitation regarding Content Types and centralized document templates. What then followed was a series of testing, phone calls with Microsoft, finding alternative solutions and deep dive into Office Open XML.
Request from the customer
“We want to use MOSS 2007 to create a collaboration site per project for our 400+ projects. These collaboration sites all use the same Content Types and document templates. We want to centrally manage those document templates so that we don’t need to make the same change 400+ times.”
Approach
Due to sizing we architected a solution with a dozen of Site Collections that would each hold a collection of project sites. We ‘Feature’-ized our Content Types and Site Columns so that they could quickly be activated on all Site Collections and used by the child sites. Document templates would be stored in a central document library and we would link to them in the Content Types on the project sites.
First issue
Linking to document templates really doesn’t play well with the Document Information Panel (DIP). I have blogged about this here:
Centralizing Document Templates in a library- Document Information Panel shows incorrect properties
We proposed a solution where the document templates in the central library would be pushed to the Content Type resource folder on site level. The code to perform the push would have to connect to the Site Collections, copy the template to the resource folder (http://sitecollectionurl/_cts/contenttypename) and link template and Content Type together.
When a Site Content Type is associated with a List it will be a List Content Type inheriting from the Site Content Type and the document template will be copied to the List Content Type resource folder (http://sitecollectionurl/listurl/Forms/contenttypename).
Second issue
Did I tell you that the column values (metadata) have different values based on the project site ? So when a project site is created we automatically update the List Content Type Column default value with the values for that specific project site. Unfortunately this is not supported when working with Office 2007 file formats because they only react on changes to the Site Column.
Consider the following scenario:
1) Set up a document library with a Content Type that has a text column with a default value
2) Upload a new .doc or .docx as Content Type template
TEST 1) Create a new document:
.DOC: the DIP will contain the text column with the default value
.DOCX: the DIP will contain the text column with the default value
3) In SharePoint, modify the default value of the text column
TEST 2) Create a new document:
.DOC: the DIP will contain the text column with the updated default value
.DOCX: the DIP will contain the text column with the original default value
Microsoft confirmed that this is by design.
Third issue
When designing our document templates with Content Controls mapped to our SharePoint fields we didn’t know that internally in the DOCX file it uses a GUID for mapping the Content Control with the SharePoint Metadata XML. For fields (Site Columns) created in the UI or through API this is the SPWeb.ID of where they were created. For fields created declaratively through Features this is the SPList.ID of where their Content Type is associated to.
So some things to notice
- Creating a single document template with Content Controls mapped to your declaratively added Fields cannot be used in two different Document Libraries because the Content Controls lose the connection with Field (because the ID of the List is different and not updated in the Content Control)
- The solution here is to create your fields in the UI or through the API (this could be in a Feature Activating event)
- Copying a document template across Site Collections means different Web ID’s so it also affects fields created in the UI or the API
Finally
In the end we wrote some wrapper classes for Office 2007 file formats using System.IO.Packaging that would manipulate our document templates once they were copied over to a different Site Collection. We also rewrote our Features to create our Fields through the API (SPWeb.Fields.AddFieldAsXml()).
- Remove the SharePoint Metadata XML so that association of the Content Type to a List it would be regenerated automagically
- Loop through every Content Control and find to which Field they were mapped using information in it’s XPath. Then we would update the GUID’s in the Content Control to match the SPWeb.ID
Next time I’ll definitely take these design limitations into account. Lessons learned I’d say !
August 20, 2009 - 09:56, by Steven Van de Craen
Categories: Content Types, MOSS 2007, Office 2007, Search Server 2008, SharePoint 2007, WSS 3.0
Every once in a while I get the request to manage all document templates centrally in a Document Library. This can easily be done by configuring your Content Types to ‘link’ to the document template by location and then applying those Content Types to lists on several locations.
However there’s a gotcha in Word 2007 with the Document Information Panel.
Consider the following scenario:
- You have a “MyTemplates” Document Library for storing the Word templates (.doc, .docx)
- You have a “Documents” Document Library configured with Content Types linking to your templates as noted above. These Content Types have custom metadata (text fields, date fields, lookup fields, etc.)
- You create a new document with a given Content Type
When the new document opens in Word 2007 the Document Information Panel is showing properties from the “MyTemplates” Document Library instead of your Content Type. Once you save the document it will refresh and show the correct set of properties. If you have required metadata it will prompt you to fill that in before actually saving.
I believe this to be a bug in Word 2007. It has been confirmed by Microsoft that this is a design limitation.
A workaround An alternative solution for some scenario’s could be to set the Content Type of your templates to the target Content Type.
This would of course still not work when you want to use the same template for multiple Content Types.
Definitely something to keep in mind when planning your setup…
June 30, 2009 - 11:05, by Steven Van de Craen
Categories: Content Types, Event Receivers, MOSS 2007, Search Server 2008, SharePoint 2007, WSS 3.0
I recently declared an Event Receiver through a SharePoint Feature: Event Registrations
Some of the samples online had surprising elements such as and . I have never seen them used before and didn’t know their purpose. Perhaps they are not to be messed with ? Perhaps great power lies within ?
-
Data – Specifies a string that will be passed as a parameter to the receiver method when handling the event
This one is commonly found in the documentation. It can be used to declare additional information and then the Event Receiver code behind can use this information. Better than hardcoding although I haven’t had the need for it (yet ?).
-
Filter – Reserved. Filter MUST be NULL
According to the official docs it is reserved: Event Receivers Result Set
Thank you Thomas for helping me on this one !
Also here’s a good reference: SharePoint 2007 Deployment: Event Registration Features
May 7, 2009 - 17:06, by Steven Van de Craen
Categories: SharePoint 2007, Search Server 2008, Content Types, Event Receivers, MOSS 2007, WSS 3.0
I'm currently doing quite some research on Event Receivers (ERs) on Content Types (CTs) and activating those CTs on a document library in SharePoint 2007 (WSS 3.0 to be exact, but same applies for MOSS 2007 and MSS(X) 2008).
The setup is a single document library with
- the out of the box Document Content Type (no event receivers defined)
- a custom ContentType1 having an EventReceiver1 for any possible event (ItemAdding, ItemUpdating, ItemAdded, …)
- a custom ContentType2 having an EventReceiver2 for any possible event
In the scenario’s situation ‘A’ has Document as default Content Type, while situation ‘B’ has ContentType1 as default.
Some scenarios
1. Create a new document of type ‘Document’ (New button)
A. No events are fired because there are none defined for this Content Type
None
B. (same as A)
2. Create a new document of type ‘ContentType1’ (New button)
A. The Office client application “knows” the Content Type and will save directly as that and fire the defined events
EventReceiver1.ItemAdding, EventReceiver1.ItemAdded
B. (same as A)
3. Create a new document and save it to the document library (starting from Word)
A. The Office client application will ask the Content Type before saving and fire the events defined for that Content Type
None
B. (same as A)
4. Upload a document using the Single File page
A. All ItemAdding events fire. The default CT is assumed. Afterwards the user is presented with the option to change the Content Type which will trigger ItemUpdating and ItemUpdated for the destination Content Type
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding
B. All ItemAdding events fire. The default CT is assumed. Other events defined for that Content Type also trigger
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding, EventReceiver1.ItemAdded
5. Upload a document using the Multiple Files page
A. All ItemAdding events fire. The default CT is assumed
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding
B. All ItemAdding events fire. The default CT is assumed
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding, EventReceiver1.ItemAdded
6. Copy and paste a document of type ‘Document’
A. All ItemAdding events fire. The Content Type of the source file is assumed
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding
B. (same as A)
7. Copy and paste a document of type ‘ContentType1’
A. All ItemAdding events fire. The Content Type of the source file is assumed. Other events defined for that Content Type also trigger (only Update, not Add)
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding, EventReceiver1.ItemUpdating, EventReceiver1.ItemUpdated
B. (same as A)
8. Restore a document of type ‘Document’ from the Recycle Bin
A. All ItemAdding and ItemAdded events fire
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding, EventReceiver1.Added, EventReceiver2.ItemAdded
B. (same as A)
9. Restore a document of type ‘ContentType1’ from the Recycle Bin
A. All ItemAdding and ItemAdded events fire
EventReceiver1.ItemAdding, EventReceiver2.ItemAdding, EventReceiver1.Added, EventReceiver2.ItemAdded
B. (same as A)
10. Restore a previous version of a document of type ‘Document’
A. No events fire
None
B. (same as A)
11. Restore a previous version of a document of type ‘ContentType1’
A. The ItemUpdating and ItemUpdated events defined for the Content Type fire
EventReceiver1.ItemUpdating, EventReceiver1.Updated
B. (same as A)
Lessons learned
- All ItemAdding events trigger in case of file upload via WebDAV or the Upload page
- Copying a file triggers the ItemAdding and ItemUpdating events, but not the ItemAdded event
- Restoring from the Recycle Bin triggers all ItemAdding and ItemAdded events regardless of Content Type
- Restoring a previous version is seen as an update (makes sense)
I’m starting to see the light although I do think that the Recycle Bin thing is a design flaw. Be careful on how you implement Event Receivers. Currently I’m thinking an additional check on Content Type in your code might be the safest way to ensure your code doesn’t run accidentally for a different Content Type ? What do you think ?