28 October 2009

Using XML Web Services in SharePoint Designer

I noticed that I had promised better details on a previous post, so I have decided to include step by step instructions on building a solution that queries an XML web service for data and displays that information in SharePoint 2007. I apologize that it has taken me two years to get back to this, and I hope you will still find this information valuable.

In the post, I described how I used SharePoint Designer to query an XML web service to build a course roster system for our professors. This is a very simple solution that allows a faculty member to go to SharePoint and display their courses and view the students enrolled in that course from data in our ERP system.

Starting in SharePoint designer, I open the site where this solution would be placed. The site I’m using has a Pages document library, but any document library should work.

image

I need two pages: one to display the available courses and another to display the students enrolled in the course. A page can be created by right clicking on the window and choosing new aspx page. Following this process, I create these two pages: CourseRoster.aspx and StudentsInCourse.aspx.

image

Now, the web service data sources need to be created. I begin by opening Manage Data Sources from the Data View menu. This opens the Data Source Library task pane. I locate the XML Web Services node and expand it. Next, I click on Connect to a web service…

image

The data source properties window will open and show the Source Tab. To help identify this data source, I begin by going to the General Tab and providing a name that is more descriptive than the default one that will be created.

image

On the Source tab, I provide the details on how to contact the web service, connect to the web service by clicking on Connect Now and select the appropriate method. (Notice that you do have the ability to use web services to update data as well, but this is beyond the scope of this post.). Any parameters that are needed for the web service will be displayed in the parameters box at the bottom of the dialog.

image

So that I can customize the parameters sent to the web service, I need to make modifications to the parameters. I click on the parameters that will need to allow to be set dynamically and then click on Modify. In this case, the Login will need to be provided dynamically; However, for simplicity, I will only be using the default value for this data source.

When I click on Modify, the parameter properties dialog will open. I insure the checkbox for The value of this parameter can be set via a Web Part connection is checked and provide a default value to use for the initial query of the data source. When the values are set correctly, I click OK to close the dialog.

image

If the web service required authentication, I would change properties on the Login tab. Fortunately, the web service that I am using does not require authentication, so I click OK to create the new data source.

image

This data source will be used to get the list of courses for a specific professor. Since the same web service also has a method to get the students currently enrolled in the course, I can simply make a copy of this web service and modify the settings appropriately.

To do this, I right click on the web service I just created and choose Copy and Modify. Again, I change the name on the general tab to provide a better name for the data source. In my case, this one is called StudentsInCourseWebService. On the source tab, I click reconnect and choose the new method to use. Again, I need to modify the parameters. This web service method expects a parameter named SYN. This is the unique identifier of a course in our organization, so it will need to be provided dynamically.

image

Now I have both of my web service data sources ready, it’s time to use the data! First, I open the CourseRoster.aspx page in SharePoint designer. A blank ASP.NET page is displayed. With the page active, I open the data source library task pane and locate the data source that queries the courses for the current professor. I right click on it and choose Show Data.

image

This queries the web service using the default value and returns the results in the Data Source Details task pane. Now, I CTRL-Click on all the fields that will need to be displayed on the data source and then click on Insert Selected Fields as… > Multiple Item View

image

The CourseRoster.aspx page now displays a list of available courses using the default value provided to the web service.

image

I want the professor to be able to click on the course number to open the course and view currently enrolled students. To do this, I move the mouse cursor over one of the items in the CourseNumber row and look for the task widget (I’m not sure what the actual name of it is, but it’s a little gray arrow).

image

I click on the widget and the properties of this field are be displayed. I need this to be a hyperlink, so I choose Hyperlink in the Format As dropdown.

image

A message warning me hyperlinks should only be used in a trusted environment appears. I click Yes to confirm the creation of a hyperlink and the hyperlink properties window is displayed. I will leave the text to display as {CourseNumber}, but I need to change the Address to StudentsInCourse.aspx?SYN={SYN}. I confirm this by clicking on OK.

image

I now move to the StudentsInCourse.aspx page and make sure it is the active page in SharePoint designer. I reopen the Data Source Library task pane to locate the data source that gets the students in a specific course. Right clicking on it, as before, I choose to Show Data. Again, I choose the columns to display and click on Insert Selected Items As Multiple Item View. There is now a list of students for the default value provided in the data source. This is not the desired result, so I need to specify a source for the parameter. I locate the widget for the data source and click on Parameters.

image

The SYN parameter is available, I just need to specify the source. This is done be choosing Query String in the parameter source drop down and setting the Query String Variable to SYN.

image

Now, it’s time for testing. To insure that everything is working, I save everything and go back to the CourseRoster.aspx page and click on the preview button on the toolbar.

image

This opens Internet Explorer to the CourseRoster.aspx page with a list of courses. I can click on a specific course to view the students enrolled in the course.

image

Finally, I need to apply the SharePoint master pages to these pages. To do this I go back to SharePoint Designer and click on Format > Master Page > Attach Master Page. I choose to attach the Default Master and match any content regions that need to be setup.

image

When completed, the page is now wrapped in SharePoint. I do the same thing for the StudentsInCourse.aspx page and the solution is now complete.

image

22 October 2009

End-To-End Solution – Custom Document Library and Completed Feature Activated

Life has been interesting the past week or so. I have a co-worker that will be out for a few weeks and have been busy getting some things finished prior to his departure. During this time, I have taken on some additional responsibilities that have slowed my progress a bit. However, I’m still planning on finishing this series. The goal is to complete my feature this week and dive into using some of the SharePoint web services in an ASP.NET application.

In this post, I plan to cover the development of a custom document library to hold all of my KB articles. This custom document library is being used so I can create a custom action and application page to activate and deactivate an event receiver specific to this document library.

Custom Document Library Definition

In the last post, I described how I created a custom list for use in hosting the available categories for my KB articles. Using the same techniques, we will add a new custom document library template that will hold the KB articles for use in the final solution. Because I need block attempts to delete KB articles, I will need an event receiver to fire each time an attempt is made to remove an item from the library. However, I need to have the ability for site administrators to selectively turn this on and off as there may be times when an article needs to be removed.

The first attempt was to use a standard document library and attach the custom action to the library, but it can be difficult to find the proper library as you really need to know the GUID of the list. By creating a custom document library, the custom action can be bound to a specific type of list.

Here is the definition of the custom document library:

  1:   <ListTemplate Name="kbdoclib"
  2:                 Type="10801"
  3:                 BaseType="1"
  4:                 OnQuickLaunch="TRUE"
  5:                 SecurityBits="11"
  6:                 Sequence="1000"
  7:                 DisplayName="KB Document Library"
  8:                 Hidden="TRUE"
  9:                 Description="Document library containing documents for use in authoring KB Articles."
 10:                 Image="/_layouts/images/itdl.gif"
 11:                 Category="Libraries"/>

For the Type attribute – line 2 above – the next available integer above 10000 was chosen based on our organization’s requirements. Since the category list template type was 10800, the next available number for our organization is 10801.

In the category list template, the BaseType was set to 0 indicating that the template would be derived from the generic list. This time, the BaseType attribute for the list is 1. This indicates that this list template will be a document library. For those that are interested, here are the base types:

  1. BaseType=”0” - Generic List
  2. BaseType=”1” – Document Library
  3. BaseType=”3” – Discussion Forum
  4. BaseType=”4” – Vote or Survey
  5. BaseType=”5” – Issues List

Please notice there is no BaseType of 2. Todd Bleeker points out in his book Developer’s Guide to Windows SharePoint Services 3.0 that this was not implemented in WSS v2 or in the current version.

This XML fragment is part of the file named CustomListDefinitions.xml located in the root of the solution. Here is the entire contents of the file:

  1: <?xml version="1.0" encoding="utf-8" ?>
  2: <Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  3:   <ListTemplate Type="10800"
  4:                 BaseType="0"
  5:                 Name="CategoryList"
  6:                 DisplayName="Category List"
  7:                 Description="Contains a list of categories"
  8:                 SecurityBits="11"
  9:                 VersioningEnabled="false"
 10:                 Hidden="TRUE"
 11:                 DisableAttachments="true"
 12:                 Category="Custom Lists"
 13:                 Sequence="100"/>
 14:   <ListTemplate Name="kbdoclib"
 15:                 Type="10801"
 16:                 BaseType="1"
 17:                 OnQuickLaunch="TRUE"
 18:                 SecurityBits="11"
 19:                 Sequence="1000"
 20:                 DisplayName="KB Document Library"
 21:                 Hidden="TRUE"
 22:                 Description="Document library containing documents for use in authoring KB Articles."
 23:                 Image="/_layouts/images/itdl.gif"
 24:                 Category="Libraries"/>
 25: </Elements>
 26: 

Now a schema.xml file is needed. This file should be placed in a folder named kbdoclib under the root of the feature’s folder. To simplify this process, the default document library schema is copied from <12 hive>/TEMPLATES/FEATURES/DocLib/DocLib/schema.xml. Nothing will be changed in the schema of the template. Instead, it has been elected that the feature activated event will do the heavy lifting of adding the required content types and assigning new views.

Completing Feature Activated

Now, I’m going to post a lot of the code that is used by the feature activated and then explain how it all works in this solution.

First up is the FeatureActivated method:

  1:     Public Overrides Sub FeatureActivated(ByVal properties As Microsoft.SharePoint.SPFeatureReceiverProperties)
  2:         Using mSite As SPSite = CType(properties.Feature.Parent, SPSite)
  3:             Using mWeb As SPWeb = mSite.RootWeb
  4:                 CreateApproverRole(mWeb)
  5:                 CreateApproverGroup(mWeb)
  6:                 Dim list As SPList = CreateCategoryListInstance(mWeb)
  7:                 CreateCategoryLookupSiteColumn(mWeb, list)
  8:                 UpdateKBDocumentContentType(mWeb)
  9:                 Dim library As SPDocumentLibrary = CreateKBDocumentLibrary(mWeb)
 10:             End Using
 11:         End Using
 12:     End Sub

To help with readability, I have broken the code down into the steps I will be taking when this feature is activated.

  1. First, I need to get a reference to the current site and web (lines 2 and 3).
  2. Next, I will be creating a new role within SharePoint that will be used to handle approval of documents in the KB document library (line 4).
  3. The role will be assigned to a group. (line 5)
  4. A new category list will be created based on the list definition defined in a previous article. (line 6)
  5. A new site column will be created that will lookup information stored in the category list. (line 7)
  6. The KB Content type will be updated to use the new site column created in step 5. (line 8)
  7. A new document library will be created utilizing all of the features that have been provisioned.

Method: CreateApproverRole

  1:     Protected Sub CreateApproverRole(ByVal web As SPWeb)
  2:         ' Create a new role
  3:         Dim ApproveRole As SPRoleDefinition
  4:         Dim createRole As Boolean = False
  5:         Try
  6:             ApproveRole = web.RoleDefinitions("Approve")
  7:         Catch ex As Exception
  8:             createRole = True
  9:         End Try
 10: 
 11:         If createRole = True Then
 12:             ApproveRole = New SPRoleDefinition()
 13: 
 14:             ' Get the contribute role as a base
 15:             Dim ContributeRole As SPRoleDefinition = web.RoleDefinitions("Contribute")
 16: 
 17:             ' Add the approval rights to the role and set name and description
 18:             ApproveRole.BasePermissions = ContributeRole.BasePermissions Or SPBasePermissions.ApproveItems
 19:             ApproveRole.Description = "Allows add, edit, delete and approve rights to list items in a site."
 20:             ApproveRole.Name = "Approve"
 21: 
 22:             ' Add the new role to the web
 23:             web.RoleDefinitions.Add(ApproveRole)
 24: 
 25:             ' Update the web
 26:             web.Update()
 27:         End If
 28:     End Sub

So that a duplicate role is not created, an attempt to retrieve an existing role named “Approve” is made.

If the role does not exist, then an exception will be thrown that will indicate the role could not be found on the current site. If the role must be created, the Contribute role is used as the base (line 15). The role has approve rights added and a description and name set. This is then added to the SPWeb and the all important SPWeb.Update() method is called to apply these changes (line 26).

These role definitions are the permission settings that can be found in Permission Levels under Advanced Permissions > Permission Levels.

image

Method: CreateApproverGroup

Now that the role has been created, a new group will need to be added so users can be added/removed from this role easily.

  1:     Protected Sub CreateApproverGroup(ByVal web As SPWeb)
  2:         ' Get the owner group by finding the group with full permissions on the site.
  3:         Dim OwnerGroup As SPGroup = Nothing
  4:         OwnerGroup = web.AssociatedOwnerGroup 'web.ParentWeb.AssociatedOwnerGroup
  5: 
  6:         Dim Approvers As SPGroup
  7:         Dim createGroup As Boolean = False
  8:         Try
  9:             Approvers = web.SiteGroups("Approvers")
 10:         Catch ex As Exception
 11:             createGroup = True
 12:         End Try
 13: 
 14:         ' Create the approvers group
 15:         If createGroup = True Then
 16:             web.SiteGroups.Add("Approvers", OwnerGroup, web.CurrentUser, "Allows users to approve items in lists and libraries.")
 17:             Dim ApproverGroup As SPGroup = web.SiteGroups("Approvers")
 18: 
 19:             ' Set the permission via a role definition for the group.
 20:             Dim ApproverGroupAssignment As New SPRoleAssignment(ApproverGroup)
 21:             Dim ApproverGroupRoleDefinition As SPRoleDefinition = web.RoleDefinitions("Approve")
 22:             ApproverGroupAssignment.RoleDefinitionBindings.Add(ApproverGroupRoleDefinition)
 23:             web.RoleAssignments.Add(ApproverGroupAssignment)
 24: 
 25:             ' Apply the updates to the web site
 26:             web.Update()
 27:         End If
 28:     End Sub

Again, similar logic will be used to determine if the group needs to be added to this web site. One thing to point out, I struggled with how to get the current owner group since I determined I would prefer the owner of this new group to be the Site Owners group instead of the user activating the feature. After searching the MSDN documentation, I happened across a little property that I had not seen before on the SPWeb object – AssociatedOwnerGroup (line 4). Using this, the owner of the new group could easily be set to the owner group of the site.

If the group is not found, it is added to the site via the SPWeb object (line 16). After it is added, the Approver role needs to be assigned to the group.

  1. To do this the group is retrieved from the SiteGroups property of the SPWeb. (line 17)
  2. A new role assignment is created. (line 20)
  3. The role definition is retrieved. (line 21)
  4. Using the role assignment and role definition, a new binding is added to the existing bindings. (line 22)
  5. The new role assignment is added to the SPWeb. (line 23)
  6. Everything is updated in the SPWeb

Method: CreateCategoryListInstance

Now that the permissions and groups have been handled, it is time to begin creating and linking content that will be used by this feature.

  1:     Protected Function CreateCategoryListInstance(ByVal web As SPWeb) As SPList
  2:         ' Create a new list for the categories and store the GUID for use later.
  3:         Dim list As SPList
  4:         Dim listID As Guid
  5:         Try
  6:             list = web.Lists("Category List")
  7:             listID = list.ID
  8:         Catch ex As Exception
  9:             list = Nothing
 10:         End Try
 11: 
 12:         If list Is Nothing Then
 13:             listID = web.Lists.Add("Category List", "List containing categories used in KB Article Creation", "Lists/Cats", "386CF027-6AC7-460a-A7D6-4E503B2B6293", 10800, 100)
 14:         End If
 15: 
 16:         ' Store the GUID of the new list for clean-up later if needed.
 17:         If web.AllProperties.ContainsKey("KBCategoryList") = True Then
 18:             web.AllProperties("KBCategoryList") = listID.ToString()
 19:         Else
 20:             web.AllProperties.Add("KBCategoryList", listID.ToString())
 21:         End If
 22:         web.Update()
 23: 
 24:         ' Retrieve the new list and provide some updates.
 25:         If list Is Nothing Then
 26:             list = web.Lists(listID)
 27:         End If
 28:         list.ContentTypesEnabled = True ' Use the specified content type
 29:         list.EnableAttachments = False  ' No attachments
 30:         list.AllowDeletion = False      ' Don't want this one to accidentally get deleted
 31:         list.Hidden = True              ' Don't show this in the view all site content area
 32:         list.NoCrawl = True             ' Don't include items from this list in search results
 33:         list.OnQuickLaunch = False      ' Don't show a link to this list on the quick launch
 34:         list.Update()
 35: 
 36:         ' Return the list
 37:         Return list
 38:     End Function

Much of this code is already documented with comments. However, here are the raw steps being used.

  1. The existing list is found or a new list is created. (lines 3-14)
  2. The GUID of the list is stored in the web properties (lines 17-22)
    This is done to help other developers on the team quickly locate key lists within the SharePoint implementation. Utilities may be written to update the categories programatically or make changes to existing items.
  3. The properties of the list are updated (line 28-34)

Method: CreateCategoryLookupSiteColumn

Now that the category list has been created, a new site column can be created to perform lookups on the list.

  1:     Protected Function CreateCategoryLookupSiteColumn(ByVal web As SPWeb, ByVal list As SPList) As Boolean
  2:         Try
  3:             ' Define the format for this lookup field
  4:             Dim fieldXMLFormat As String = _
  5:                "<Field ID=""{{3324B767-6CB6-4789-A0ED-60FB39BAC648}}""" & _
  6:                " Name=""SWBTS_KBCategory"" StaticName=""SWBTS_KBCategory""" & _
  7:                " DisplayName=""Category"" Type=""Lookup"" List=""{0}""" & _
  8:                " ShowField=""Title"" LCID=""1033""" & _
  9:                " Group=""Knowledge Base Columns""" & _ 
 10:                " UnlimitedLengthInDocumentLibrary=""false"" />"
 11: 
 12:             ' Using the format and apply the category list GUID to the string
 13:             Dim fieldXML As String = String.Format(fieldXMLFormat, list.ID.ToString())
 14: 
 15:             ' Add the field to the site columns collection
 16:             web.Fields.AddFieldAsXml(fieldXML)
 17:             web.Update()
 18:             Return True
 19:         Catch ex As Exception
 20:             Return False
 21:         End Try
 22:     End Function

The easiest way to create a new field is to use the XML markup to define the field. Notice that there is a placeholder on line 7 for the GUID of the list. This is where most of the issues in creating lookup columns in features were experienced by me. Once it was determined that using the list GUID was necessary for the site column to work properly, it was decided that this was the best way to implement the site lookup column (line 13).

The field is then added to the current web context and the web updated with the new site column (lines 16 – 17).

Method: UpdateKBDocumentContentType

Now that the site column has been added containing the categories for the system, the underlying content types need to be updated with a reference to this new site column.

  1:    Protected Function UpdateKBDocumentContentType(ByVal web As SPWeb) As Boolean
  2:         Try
  3:             ' Get the IT Knowledge Base Article content type
  4:             Dim CT As SPContentType = web.ContentTypes("IT Knowledge Base Article")
  5: 
  6:             ' Create the GUID for the site column to add to the content type
  7:             Dim fieldID As Guid = New Guid("3324B767-6CB6-4789-A0ED-60FB39BAC648")
  8: 
  9:             ' Add a new link to the site column for the IT Knowledge Base Article content type
 10:             CT.FieldLinks.Add(New SPFieldLink(web.Fields(fieldID)))
 11: 
 12:             ' Update the content type and all child content types.
 13:             CT.Update(True)
 14: 
 15:             Return True
 16:         Catch ex As Exception
 17:             Return False
 18:         End Try
 19:     End Function

The content type is located and then a new field link is added to the content type (line 10). The content type is then updated.

Method: CreateKBDocumentLibrary

Finally, all of the pieces are in place to create the document library that will house all of the KB documents. Now, it just needs to be added using the following code:

  1:     Protected Function CreateKBDocumentLibrary(ByVal web As SPWeb) As SPDocumentLibrary
  2:         Dim kbDocLibraryID As Guid
  3:         Dim docLibrary As SPDocumentLibrary
  4:         Try
  5:             docLibrary = web.Lists("Knowledge Base Repository")
  6:             kbDocLibraryID = docLibrary.ID
  7:         Catch ex As Exception
  8:             docLibrary = Nothing
  9:         End Try
 10: 
 11:         ' Create the new document library and store the guid.
 12:         If docLibrary Is Nothing Then
 13:             Try
 14:                 kbDocLibraryID = web.Lists.Add("KB", "Knowledge base articles and resources.", "KB", "386CF027-6AC7-460a-A7D6-4E503B2B6293", 10801, 101)
 15:             Catch ex As Exception
 16:                 kbDocLibraryID = web.Lists("KB").ID
 17:             End Try
 18:         End If
 19: 
 20:         ' Store the GUID in the document properties for use when deactivating the feature.
 21:         If web.AllProperties.ContainsKey("KBDocID") Then
 22:             web.AllProperties("KBDocID") = kbDocLibraryID.ToString()
 23:         Else
 24:             web.AllProperties.Add("KBDocID", kbDocLibraryID.ToString())
 25:         End If
 26:         web.Update()
 27: 
 28:         ' Update the document library and turn on the ability to use content types.
 29:         If docLibrary Is Nothing Then
 30:             docLibrary = web.Lists(kbDocLibraryID)
 31:         End If
 32:         docLibrary.ContentTypesEnabled = True
 33:         docLibrary.Update()
 34: 
 35:         ' Get a reference for the content types that will be changed.
 36:         Dim docType As SPContentType = docLibrary.ContentTypes("Document")                      ' Document content type declared in the library
 37:         Dim kbType As SPContentType = web.ContentTypes("IT Knowledge Base Article")             ' New IT content type declared in the web site
 38:         Dim hicupType As SPContentType = web.ContentTypes("HICUP Knowledge Base Article")       ' Content Type for old KB Articles
 39: 
 40:         ' Add the new KB type and remove the generic document type
 41:         Try
 42:             Dim kbDocLibraryType As SPContentType = docLibrary.ContentTypes.Add(kbType)
 43:             Dim hicupDocLibraryType As SPContentType = docLibrary.ContentTypes.Add(hicupType)
 44:             hicupDocLibraryType.Hidden = False
 45:             docLibrary.Update()
 46: 
 47:             Dim fieldID As Guid = New Guid("3324B767-6CB6-4789-A0ED-60FB39BAC648")
 48: 
 49:             ' Insure the category column is linked to the document library for this content type
 50:             hicupDocLibraryType.FieldLinks.Add(New SPFieldLink(web.Fields(fieldID)))
 51:             hicupDocLibraryType.Update()
 52: 
 53:             ' Remove the original document content type -- it isn't needed for this library
 54:             docLibrary.ContentTypes.Delete(docType.Id)
 55:             docLibrary.Update()
 56:         Catch ex As Exception
 57:         End Try
 58: 
 59:         ' Set some additional properties for the library.
 60:         docLibrary.Title = "Knowledge Base Repository"
 61:         docLibrary.EnableFolderCreation = False                             ' No folder nesting allowed!
 62:         docLibrary.EnableModeration = True                                  ' Items must be approved.
 63:         docLibrary.EnableVersioning = True                                  ' Enable versions for historical tracking
 64:         docLibrary.EnableMinorVersions = False                              ' Do not use minor versions for draft revisions
 65:         docLibrary.DraftVersionVisibility = DraftVisibilityType.Reader      ' Allow everyone to read all documents
 66:         docLibrary.MajorVersionLimit = 8                                    ' Only store the last 8 major versions
 67:         docLibrary.ForceCheckout = True                                     ' You must check out these documents to edit
 68:         docLibrary.OnQuickLaunch = True                                     ' Create a navigational link to the library
 69:         docLibrary.Update()
 70: 
 71:         ' Update the document library views
 72:         Dim defaultViewFieldsArray() As String = {"DocIcon", "LinkFilename", "SWBTS_KBCategory", "_UIVersionString", "Modified", "Editor", "CheckoutUser"}
 73:         Dim defaultViewFields As New System.Collections.Specialized.StringCollection()
 74:         defaultViewFields.AddRange(defaultViewFieldsArray)
 75: 
 76:         ' Add new columns to the default view
 77:         Dim defaultView As SPView = docLibrary.DefaultView
 78:         defaultView.ViewFields.DeleteAll()              ' Remove all the old columns, we want to start with a clean view
 79:         For Each fieldName In defaultViewFields         ' Iterate through the defaultViewFields array to add them to the view
 80:             defaultView.ViewFields.Add(fieldName)       ' Add the field to the view
 81:         Next
 82:         ' Change the query
 83:         defaultView.Query = "<GroupBy Collapse=""FALSE"" GroupLimit=""100""><FieldRef Name=""ContentType"" /><FieldRef Name=""_ModerationStatus"" /></GroupBy><OrderBy><FieldRef Name=""FileLeafRef"" /></OrderBy>"
 84:         ' Set a new row limit
 85:         defaultView.RowLimit = 50
 86:         ' Update the default view
 87:         defaultView.Update()
 88: 
 89:         ' Add a new view to show only the articles transferred from the old system.
 90:         Dim oldItemsView As SPView = docLibrary.Views.Add("KB Articles", defaultViewFields, "<GroupBy Collapse=""FALSE"" GroupLimit=""100""><FieldRef Name=""_ModerationStatus"" /></GroupBy><OrderBy><FieldRef Name=""FileLeafRef"" /></OrderBy><Where><Eq><FieldRef Name=""ContentType"" /><Value Type=""Text"">HICUP Knowledge Base Article</Value></Eq></Where>", 100, True, False)
 91:         oldItemsView.ViewFields.Add("SWBTS_OriginalAuthor")
 92:         oldItemsView.ViewFields.Add("SWBTS_OriginalKBID")
 93:         oldItemsView.ViewFields.Add("SWBTS_OriginalPublished")
 94:         oldItemsView.Update()
 95:         docLibrary.Update()
 96: 
 97:         ' Add a new view to show articles grouped by category.
 98:         Dim categoryView As SPView = docLibrary.Views.Add("By Category", defaultViewFields, "<GroupBy Collapse=""FALSE"" GroupLimit=""100""><FieldRef Name=""SWBTS_KBCategory"" /></GroupBy><OrderBy><FieldRef Name=""FileLeafRef"" /></OrderBy>", 200, True, False)
 99:         categoryView.ViewFields.Delete("SWBTS_KBCategory")      'Since we are grouping by category, remove the category column from the view
100:         categoryView.Update()
101:         docLibrary.Update()
102: 
103:         ' Add a new view to show articles that have been rejected.
104:         Dim rejectedView As SPView = docLibrary.Views.Add("My Rejected Items", defaultViewFields, "<OrderBy><FieldRef Name=""Modified"" Ascending=""FALSE"" /></OrderBy><Where><And><Eq><FieldRef Name=""_ModerationStatus"" /><Value Type=""ModStat"">Rejected</Value></Eq><Eq><FieldRef Name=""Author"" /><Value Type=""Integer""><UserID Type=""Integer"" /></Value></Eq></And></Where>", 15, True, False)
105:         rejectedView.Update()
106:         docLibrary.Update()
107: 
108:         ' Add a new view to show articles that need to be reviewed
109:         Dim reviewView As SPView = docLibrary.Views.Add("Needing Review", defaultViewFields, "<OrderBy><FieldRef Name=""SWBTS_ReviewDate"" /></OrderBy><Where><Leq><FieldRef Name=""SWBTS_ReviewDate"" /><Value Type=""DateTime""><Today /></Value></Leq></Where>", 50, True, False)
110:         reviewView.ViewFields.Add("SWBTS_ReviewDate")
111:         reviewView.Update()
112:         docLibrary.Update()
113: 
114:         ' Add a new view to show my articles that need to be reviewed
115:         Dim myReviewView As SPView = docLibrary.Views.Add("My Documents to Review", defaultViewFields, "<OrderBy><FieldRef Name=""SWBTS_ReviewDate"" /></OrderBy><Where><And><Or><And><Leq><FieldRef Name=""SWBTS_ReviewDate"" /><Value Type=""DateTime""><Today /></Value></Leq><Eq><FieldRef Name=""Author"" /><Value Type=""Integer""><UserID Type=""Integer"" /></Value></Eq></And><Leq><FieldRef Name=""SWBTS_ReviewDate"" /><Value Type=""DateTime""><Today /></Value></Leq></Or><Eq><FieldRef Name=""Editor"" /><Value Type=""Integer""><UserID Type=""Integer"" /></Value></Eq></And></Where>", 20, True, False)
116:         reviewView.ViewFields.Add("SWBTS_ReviewDate")
117:         myReviewView.Update()
118:         docLibrary.Update()
119: 
120:         Return docLibrary
121:     End Function

Admittedly, there is a lot of code above. I would normally stay away from posting this much code, but this also gives an opportunity to show how to do a bunch of things when creating lists and libraries programatically in SharePoint. So, for the broad sweeping brush of what’s happening above:

  1. Find or create the KB Document library. (lines 4-26)
  2. Turn on content types for the library. (lines 29-33)
  3. Add and remove content types. (lines 36-55)
  4. Change some of the settings of the library. (lines 60-69)
  5. Add a bunch of public views for the library. (lines 72-118)

If you follow the comments, you will see a lot of details on what is being done in the code.