Szymon Kobalczyk's Blog

A Developer's Notebook

  Home  |   Contact  |   Syndication    |   Login
  82 Posts | 5 Stories | 152 Comments | 380 Trackbacks

News

View Szymon Kobalczyk's profile on LinkedIn

Twitter












Article Categories

Archives

Post Categories

Image Galleries

Blogs I Read

Tools I Use

In my previous post I wrote how you can access the contents of discussion boards using web services. For reading existing discussions threads the Lists web service was all that we needed. However there were problems when creating discussions using the same service. After whole day of trial and error I finally gave up this approach and decided to first try using SharePoint's object model instead.

On the side note, I was using our test server over Internet with was fine for working with web services. However to use object model I needed to have SharePoint locally so I could run the code directly on the server. For this I used Virtual PC machine with Windows 2003 Server and Windows SharePoint Services 3.0 installed. On this machine I've setup remote debugging so I could compile and debug the code in Visual Studio on my host machine while running it on the server.

So first I've tried to simply create new SPListItem with the Items.Add method on the corresponding SPList object. But although I tried setting several different properties I still got the same results as with Web Services. The only difference was that I somehow managed to get correct Content Type for messages.

While searching for some clue I also found an interesting benchmark from Michael Ekegren that compares various methods for inserting items to lists. Clearly using object model to add to Items collection has the worst performance.

After a bit more of searching I've finally found that in order to insert discussion items properly I must use two special methods on the SPUtility class. The CreateNewDiscussion static method creates a new discussion thread and the CreateNewDiscussionReply method creates a reply to existing thread. So I figure there has to be some magic involved for handling discussion if there are special methods just for this purpose. Later I found a blog post that shows how it could be done without using SPUtility.

With the help of these methods I could quickly construct an additional Discussions web service to add the missing functionality. It has two methods that simply wrap the calls to corresponding methods on SPUtility and map the parameters.

[WebMethod]
public XmlNode CreateNewDiscussion(string listName, string subject, string body)
{
    SPList list = FindList(listName); 
    if (list == null)
        throw new ArgumentException("List name is invalid.");

    SPListItem discussion = SPUtility.CreateNewDiscussion(list.Items, subject);
    discussion[SPBuiltInFieldId.Body] = body;
    discussion.Update();

    // this is only to ensure the Xml can be generated
    object t = discussion[SPBuiltInFieldId.ThreadIndex];

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(discussion.Xml);
    return doc.DocumentElement;
}

[WebMethod]
public XmlNode CreateNewDiscussionReply(string listName, int parentId, string body)
{
    SPList list = FindList(listName);
    if (list == null)
        throw new ArgumentException("List name is invalid.");

    SPListItem parent = list.GetItemById(parentId);

    SPListItem reply = SPUtility.CreateNewDiscussionReply(parent);
    reply[SPBuiltInFieldId.Body] = body;
    reply.Update();

    // this is only to ensure the Xml can be generated
    object t = reply[SPBuiltInFieldId.ThreadIndex];

    XmlDocument doc = new XmlDocument();
    doc.LoadXml(reply.Xml);
    return doc.DocumentElement;
}

First method CreateNewDiscussion requires name of the discussion list, subject and body for the new discussion thread. The CreateNewDiscussionReply also takes the name of the discussion list, the Id of the parent message (the one you reply to) and the body of the reply. Both methods return the XmlNode with the data from the new item to reproduce the behavior of the Lists service's UpdateListItem method. You might notice a small hack where I read some property of the new item before converting it to XmlNode. I found that this is required in order to regenerate the Xml property. Without this extra call this property would always return null.

I wanted to allow the list name to be either it's Title or ID just like in the methods of the Lists WebService so I'm using a helper FindList method to do the mapping.

private SPList FindList(string listName)
{
    if (String.IsNullOrEmpty(listName))
        throw new ArgumentNullException("listName");

    SPWeb site = SPContext.Current.Web;
    SPListCollection listCollection = site.Lists;
    try
    {
        Guid listID = new Guid(listName);
        foreach (SPList list in listCollection)
        {
            if (listID == list.ID)
                return list;
        }
        return null;
    }
    catch
    { }

    foreach (SPList list in listCollection)
    {
        if (String.Equals(listName, list.Title, StringComparison.InvariantCultureIgnoreCase))
            return list;
    }

    return null;
}

This method first tries to convert the list name to a Guid and find the list by it's ID. If the string is not a proper Guid it tries to find the list by it's name instead. Notice I've used the static String.Equals overload to do the comparison in invariant culture and ignoring case.

There are some additional steps that you need to perform to install this web service on SharePoint server. Follow the steps outlined in the nice walkthrough on creating custom web services in the documentation for WSS SDK .

So with the help of this additional service I finally managed to finish my first assigned task on the TSRI project. Below you can see a screenshot from the application showing the preview window for the discussion annotation.

Users can also reply to and edit individual discussion messages right in the application.

I will write more posts soon on the interface implementation (starting with the control templates for the glass toolbar).

posted on Friday, March 16, 2007 10:01 AM

Feedback

# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 3/21/2007 12:37 PM Hani
Hey Man,
I can title you as God.... i have been searching for the exact thing what you have done.Even i am supposed to use these Discussion Boards in my web application.

Jesus you saved my time :-) .... Thanks a ton. If possible please mail me the necessary source code.I need to complete my requirement in 3 more days. Thanks Again.


Thanks,
Hani
honey008@gmail.com

# Links (3/19/2007) 4/25/2007 9:45 PM Member Blogs
.NET C# regex email address Convert Array List to DataTable Describing Types in .NET Basic C# coding

# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 5/17/2007 6:21 AM Arun
Hey ...

Thanks a lot man ... you blog was really useful for me, otherwise it was supposed to be a big burden for me, for creating the Discussion in 2007.. actually I am working on migrating from 2003 to 2007..

Thanks a lot
May God Bless you ...


Regards
Arun.

# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 7/11/2007 11:21 AM AdamK
Thank you so much...

This is exactly what I was looking for. The threading problem was causing me a big pain in the backside!

AdamK

# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 8/21/2007 1:50 PM Kathir
Hi,

Great Post!!!...I was able to create a new discussion forum if not exists and able to create a discussion reply for the same. But i couldn't get to know about the CAML querying the discussion board to get all the items and want to render into the Tree view in my web application. How do you did for your application showing all the discussion items in the tree view (looks like exapand and collapse kind of).? Please help me in this regard. This is urgent!!.

Thanks,
Kathir

# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 11/30/2007 9:27 PM Gopi
I have a custom column named 'category' in the Discussion list
How can I provide the value to it using SPBuiltInFieldId?
trying like this
discussion[SPBuiltInFieldId.Category] = Category; but ending up with "Invalid field name. {6df9bd52-550e-4a30-bc31-a4366832a87d}" exceptions?
how to map the custom column value using SPBuiltInFieldId?
Thanks
Gopi


# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 12/31/2007 10:44 PM Vivek
hi,

Thanks for the great help !!
I'll greatly appreciate if you help me to solve this problem:
I have used your webservice to export dicussions from an access database to MOSS, for the first few times (around 374 items) the webservice works fine , after that it starts giving error
"operation is not valid due to the current state of the object"..plz help!!

# re: How to access SharePoint's Discussion Board using Web Services. Part 2. 8/18/2008 3:08 PM Jagdish
Hi,

Thanks a lot Szymon Kobalczyk.

I would like to know how did you do Tree View of discussion board items. I have struggled a lot but couldn't find any hint on this.

Appreciate your help.

Thanks in advance.

Post Feedback

Title:
Name:
Email: (never displayed)
Url:
Comments: 
Please add 7 and 6 and type the answer here: