Unravel the SharePoint Threaded Discussion


The SharePoint Threaded Discussion is a forum type of post.  Underneath, like all things SharePoint, it is a list.  By default that list is made up of two content types, Discussion and Message.  The content types have IDs of 0x012002 and 0x0107 respectively.  Following the content type inheritance chain this means that the Discussion content type inherits from folder and the Message content type from Item.  This gives us some clue about the structure of the list.

If you enter a top level item in a threaded discussion list it will be created as a folder.  In order to navigate each top level thread using the object model we use code similar to that shown below.

using ( SPSite siteCollection = new SPSite( "http://moss.litwareinc.com/" ) ) {
    using ( SPWeb web = siteCollection.OpenWeb( "/SiteDirectory/mktg" ) ) {
        SPList list = web.Lists["Team Discussion"];

        foreach ( SPListItem folder in list.Folders ) {
            Console.WriteLine( "-- Folder --" );
            Console.WriteLine( folder.Title );
            Console.WriteLine( folder.UniqueId.ToString() );
            Console.WriteLine( folder.ID.ToString() );
            Console.WriteLine( folder.Xml );
            Console.WriteLine( "-- End Folder --" );
        }
    }
}

You can also iterate over the list items themselves using the typical foreach convention.  When you do this take a look at the Xml property for the List Item and you will see various items that we can use to find the context of our item within the threaded discussion.

<?xml version="1.0" encoding="utf-8" ?>
<z:row xmlns:z='#RowsetSchema' 
       ows_ContentTypeId='0x010700135BC7419F95B04C8EA15325163C1444' 
       ows_Body='&lt;div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;br&gt;&lt;hr&gt;&lt;b&gt;From: &lt;/b&gt;System Account&lt;br&gt;&lt;b&gt;Posted: &lt;/b&gt;Wednesday, June 04, 2008 5:14 PM&lt;br&gt;&lt;b&gt;Subject: &lt;/b&gt;sample item one&lt;br&gt;&lt;br&gt;&lt;div class=ExternalClassF19C451E2C284124AB09D103E8A70A18&gt;&lt;div&gt;first sample item&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;' 
       ows_TrimmedBody='&lt;div class=ExternalClass4D66DF23C3C649C4985CFE81A1E2E0E2&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;/div&gt;&lt;/div&gt;' 
       ows_ParentFolderId='1' 
       ows_ID='2' 
       ows_ContentType='Message' 
       ows_Modified='2008-06-04 17:14:33' 
       ows_Created='2008-06-04 17:14:33' 
       ows_Author='1073741823;#System Account' 
       ows_Editor='1073741823;#System Account' 
       ows_owshiddenversion='1' 
       ows_WorkflowVersion='1'
       ows__UIVersion='512' 
       ows__UIVersionString='1.0' 
       ows_Attachments='0' 
       ows__ModerationStatus='0' 
       ows_SelectTitle='2' 
       ows_Order='200.000000000000' 
       ows_GUID='{8FAC9A20-6343-48A3-8BE3-CD7E17E45894}' 
       ows_FileRef='2;#SiteDirectory/mktg/Lists/TeamDiscussion/sample item one/2_.000' 
       ows_FileDirRef='2;#SiteDirectory/mktg/Lists/Team Discussion/sample item one' 
       ows_Last_x0020_Modified='2;#2008-06-04 17:14:33'
       ows_Created_x0020_Date='2;#2008-06-04 17:14:33' 
       ows_FSObjType='2;#0' 
       ows_PermMask='0x7fffffffffffffff' 
       ows_FileLeafRef='2;#2_.000' 
       ows_UniqueId='2;#{87C5CD04-7D68-4B26-B00C-DD76AE7B96D8}' 
       ows_ProgId='2;#' 
       ows_ScopeId='2;#{6ED2F3B8-3D0A-4B4F-B092-C9A6D1942AE2}' 
       ows__EditMenuTableStart='2_.000' 
       ows__EditMenuTableEnd='2'
       ows_LinkFilenameNoMenu='2_.000' 
       ows_LinkFilename='2_.000' 
       ows_ServerUrl='/SiteDirectory/mktg/Lists/Team Discussion/sample item one/2_.000' 
       ows_EncodedAbsUrl='http://moss.litwareinc.com/SiteDirectory/mktg/Lists/Team%20Discussion/sample%20item%20one/2_.000' 
       ows_BaseName='2_' 
       ows_MetaInfo='2;#' 
       ows__Level='1' 
       ows__IsCurrentVersion='1' 
       ows_ThreadIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927' 
       ows_ShortestThreadIndexIdLookup='1;#' 
       ows_DiscussionTitleLookup='1;#sample item one' 
       ows_DiscussionTitle='sample item one' 
       ows_ReplyNoGif='SiteDirectory/mktg/Lists/Team Discussion/sample item one' 
       ows_ThreadingControls='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927' 
       ows_IndentLevel='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927' 
       ows_Indentation='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927' 
       ows_StatusBar='2008-06-05T00:14:33Z' 
       ows_BodyAndMore='&lt;div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;br&gt;&lt;hr&gt;&lt;b&gt;From: &lt;/b&gt;System Account&lt;br&gt;&lt;b&gt;Posted: &lt;/b&gt;Wednesday, June 04, 2008 5:14 PM&lt;br&gt;&lt;b&gt;Subject: &lt;/b&gt;sample item one&lt;br&gt;&lt;br&gt;&lt;div class=ExternalClassF19C451E2C284124AB09D103E8A70A18&gt;&lt;div&gt;first sample item&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;' 
       ows_MessageBody='&lt;div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;br&gt;&lt;hr&gt;&lt;b&gt;From: &lt;/b&gt;System Account&lt;br&gt;&lt;b&gt;Posted: &lt;/b&gt;Wednesday, June 04, 2008 5:14 PM&lt;br&gt;&lt;b&gt;Subject: &lt;/b&gt;sample item one&lt;br&gt;&lt;br&gt;&lt;div class=ExternalClassF19C451E2C284124AB09D103E8A70A18&gt;&lt;div&gt;first sample item&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;' 
       ows_BodyWasExpanded='{8FAC9A20-6343-48A3-8BE3-CD7E17E45894}' 
       ows_QuotedTextWasExpanded='{8FAC9A20-6343-48A3-8BE3-CD7E17E45894}' 
       ows_CorrectBodyToShow='&lt;div class=ExternalClass4D66DF23C3C649C4985CFE81A1E2E0E2&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;/div&gt;&lt;/div&gt;' ows_FullBody='&lt;div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;br&gt;&lt;hr&gt;&lt;b&gt;From: &lt;/b&gt;System Account&lt;br&gt;&lt;b&gt;Posted: &lt;/b&gt;Wednesday, June 04, 2008 5:14 PM&lt;br&gt;&lt;b&gt;Subject: &lt;/b&gt;sample item one&lt;br&gt;&lt;br&gt;&lt;div class=ExternalClassF19C451E2C284124AB09D103E8A70A18&gt;&lt;div&gt;first sample item&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;' 
       ows_LimitedBody='&lt;div class=ExternalClassAAF51B42E3834F8D90CA3A8DA7739064&gt;&lt;div&gt;second sample item&lt;br&gt;&lt;br&gt;&lt;hr&gt;&lt;b&gt;From: &lt;/b&gt;System Account&lt;br&gt;&lt;b&gt;Posted: &lt;/b&gt;Wednesday, June 04, 2008 5:14 PM&lt;br&gt;&lt;b&gt;Subject: &lt;/b&gt;sample item one&lt;br&gt;&lt;br&gt;&lt;div class=ExternalClassF19C451E2C284124AB09D103E8A70A18&gt;&lt;div&gt;first sample item&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;' 
       ows_MoreLink='2' 
       ows_LessLink='2' 
       ows_ToggleQuotedText='2' 
       ows_Threading='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927' 
       ows_PersonImage='System Account' 
       ows_PersonViewMinimal='System Account' 
       ows_IsRootPost='0' 
       ows_ItemChildCount='2;#0' 
       ows_ServerRedirected='0'/>

One of the more important properties is the ows_ParentFolderId.  By leveraging this property we can establish the parent thread or discussion, in this case the folder, that is the host for the item.  This will always be the top level folder item, not the item that was responded to originally.  While this does allow you to figure out which items go with which folder, it does not provide order or hierarchy.

If you examine the default 'Threaded' view that comes with an instance of the Team Discussion you will notice that it contains one column, 'Threading (threaded)'.  This column is used for display and also used to sort the items.  There is a group of properties that provide a structure that enabling you to figure out he thread hierarchy.  Notice the ows_ThreadIndex, ows_Threading, ows_ThreadingControls, ows_IndentLevel, etc.  These properties all have the same value for an item, but as you navigate from item to item notice that a hierarchy of sorts is formed.  The base item has a thread value and then the children have this same thread value, but with some additional random text after the base item.  This begins to form a hierarchy. 

ows_ThreadingIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB’

|_ows_ThreadingIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B927'

                |_ows_ThreadingIndex='0x01CA94B8313E972C16929A454ACFA141B2588F7291DB000004B9270000026E29'

When reviewing the Xml attributes another item looks promising, ows_Order.  It has a format of xxx.xxxxxx.  This leads one to believe that this would control the order of the items in the thread.  I was hoping to find a pattern that was parent.childorder or something to that affect, but that is not the case.  Upon further examination this is simply the item id.  It is probably reserved for some future use.

Comments (13)

  1. Richard Draut says:

    Does this discussion in which we are currently participating use the WSS discussion feature, or is some other enabling technology providing the discussion thread engine?

  2. Richard Draut says:

    …nevermind. I see in teh source code that it is usng CommunityServer 2.1 SP1.

    thanks, R

  3. ItsMeSri says:

    How to iterate item (message) level?. Now I am working on finding all posts for particular user in the web. CAML query returning only Top level post only (Discussion), not replies (Messages). Give me some clue to get them too.

  4. You could do a CAML query that is limited to the Content Type of folder.  the content type id is mentioned in the first paragraph.  

  5. Fraz says:

    Cliff can you demonstrate how to post a reply against a reply programitacly  using "AddDiscussionBoardItem" method of list web service. Able to create discussion and post replies. But unable to find any solution to post a reply against a reply.

  6. Mitch says:

    OK, given an understanding of the interals of the default Sharepoint discussion forum, has anyone figured out how to re-do the UI so that it’s actually usable?

    I’ll take a discussion forum that’s up to just basic ‘Internet 101’ standards – multi-level thread expand/collapse, decent editing tools, tagging, etc.  ANYTHING has to be better than the POS that comes out of the box with SP.

    Extra credit if anyone can figure out how to do Notes-style custom root forms that can be associated with discussion threads and incorporate mulit-value columns that can be used in views.  I don’t see how that can even work at all with SP, given that the underlying data model doesn’t appear to include a multi-value data type.

    If anyone knows of someone who’s done this, or wants to do it and knows how, please post a response here.  I’ve got budget to build it.

  7. John says:

    Franz, did you find an answer to your question about AddDiscussionBoardItem? I am having the same problem!

  8. Fraz and John, I’ll look into this, but here is an example of the 64encoding and how to post an item.  I will look at posting a reply if I can, and it may be that it requires the ChangeListitem method with some knowledge of the internals.

    http://social.technet.microsoft.com/Forums/en-US/sharepointdevelopment/thread/25d55767-71f1-4e1a-a62e-8a22f9de58a8

  9. John says:

    Looks like I have all but one of my issues solved…how can I pass my encoded value to WSS via JavaScript?

    Since the 2nd param of AddDiscussionBoardItem wants a Base64Binary how should I handle that?

  10. Excellent.  There are third party and open source libraries for doing base64 encoding, so you can look into those.

  11. John says:

    Hey Cliff,

    Just looking at the new post now, but heck I think it’s going to be a HUGE help!

    Thanks VERY much!

    John

Skip to main content