Walkthrough: Creating a Content Service Object

Applies to: SharePoint Foundation 2010

This walkthrough explores how to define the logic for a custom service to manage site content in a SharePoint Foundation deployment. The example shows how to create classes that derive from classes in the Microsoft.SharePoint.Administration namespace to persist custom administrative settings in the database. The example includes class files that implement data structures that contain metadata about a list of locations. Each content location specifies a URL that must be preserved.

The example includes creating code files for the following classes:

  • ContentService   Defines the top-level object, which derives from the SPService class and provides the logic for managing content locations in a deployment. This class includes constructors for initializing the ContentService object, as well as members for retrieving the content service and its collection of content locations.

  • ContentLocationCollection   Defines a collection class that inherits from the SPPerisistedChildCollection class and provides an object to contain content locations. This class contains a constructor and an Add method.

  • ContentLocation   Inherits from SPPersistedObject and defines a content location. This class includes constructors and members for custom property settings.

In addition to creating an assembly with the previous code files, the example shows how to use a custom action Feature to add a link on the Operations page so that administrators can access the service. The example also describes how to use custom .aspx pages to provide the user interface that is required for managing the content service and its content location items. For information about creating a SharePoint Foundation project in Microsoft Visual Studio 2005, see Getting Started with Programmatically Customizing a SharePoint Web Site in Visual Studio.

ContentService Class File

The following code example defines a FormatType enumeration, and the top-level ContentService class, which includes constructors and the following members:

  • Local   A static property to retrieve the current content location service.

  • Locations   A static property to access the content location collection.

  • GetAllContentLocations   A method to return all content locations provided through the service.

  • Format   A property to get or set the type of format for the content service.

At the top of each code file that is subsequently presented, add a directive to import the Microsoft.SharePoint.Administration namespace, as in the following example. Use the Persisted attribute to make property settings persist in the database. The custom namespace that contains objects in the example is named MS.Samples.SharePoint.ContentManager.

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Microsoft.SharePoint.Administration

Namespace MS.Samples.SharePoint.ContentManager

    Public Enum FormatType
        HTML
        XML
    End Enum 'ContentLocationType

    <System.Runtime.InteropServices.Guid("BB69A6EB-3230-43ca-B4F5-752EAC39C74A")>  _
    Public Class ContentService
        Inherits SPService

        <Persisted()>  _
        Private formatType As FormatType

        Private Shared locations As ContentLocationCollection
        Private Shared local As ContentService = Nothing
      
        ' A static property that retrieves the content service. 
        Public Shared ReadOnly Property Local() As ContentService
            Get
                If ContentService.local Is Nothing Then
                    ContentService.local = _
                      SPFarm.Local.Services.GetValue < ContentService > "ContentService"
                End If

                Return ContentService.local
            End Get
        End Property

        ' A static property for accessing the location collection. 
        Public Shared ReadOnly Property Locations() As ContentLocationCollection
            Get
                If Me.locations Is Nothing Then
                    Me.locations = New ContentLocationCollection(Me)
                End If

                Return Me.locations
            End Get
        End Property

        ' An empty public constructor required for serialization. 
        Public Sub New()
        End Sub 'New

        Public Sub New(farm As SPFarm)
            MyBase.New("ContentService", farm)
            ' Add code to initialize as needed. 
        End Sub 'New

        ' A method to retrieve the content location collection. 
        Public Function GetAllContentLocations() As ContentLocationCollection
            Dim service As ContentService = ContentService.Local
            If service Is Nothing Then
                Return Nothing
            End If

            Return service.Locations
        End Function 'GetAllContentLocations

        Public Property Format () As FormatType
            Get
                Return Me.formatType
            End Get
            Set
                Me.formatType = value
            End Set
        End Property 
    End Class 'ContentService
End Namespace 'MS.Samples.SharePoint.ContentManager
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.Administration;

namespace MS.Samples.SharePoint.ContentManager
{
    public enum FormatType
    {
        HTML,
        XML
    }
    [System.Runtime.InteropServices.Guid("BB69A6EB-3230-43ca-B4F5-752EAC39C74A")]
    public class ContentService : SPService
    {
        [Persisted]
        private FormatType formatType;

        private static ContentLocationCollection locations;
        private static ContentService local = null;

        /* A static property that retrieves the content service. */
        public static ContentService Local
        {
            get
            {
                if (ContentService.local == null)
                {
                    ContentService.local = 
                      SPFarm.Local.Services.GetValue<ContentService>("ContentService");
                }

                return ContentService.local;
            }
        }

        /* A static property for accessing the location collection. */
        public static ContentLocationCollection Locations
        {
            get
            {
                if (this.locations == null)
                {
                    this.locations = new ContentLocationCollection(this);
                }

                return this.locations;
            }
        }

        /* An empty public constructor required for serialization. */
        public ContentService()
        {;}

        public ContentService(SPFarm farm)
            : base("ContentService", farm)
        {/* Add code to initialize as needed. */}

        /* A method to retrieve the content location collection. */
        public ContentLocationCollection GetAllContentLocations()
        {
            ContentService service = ContentService.Local;

            if (service == null)
            {
                return null;
            }

            return service.Locations;
        }

        public FormatType Format
        {
            get 
            {
                return this.formatType; 
            }
            set 
            { 
                this.formatType = value; 
            }
        }
    }
}

Define a custom Provision method to add the ContentService object to the database, such as in the following example. This method can be contained in the previous ContentService class, or it can be separately contained to be more modular and callable from different contexts, such as from a Feature installer that you can create to install the service, or from a command-line operation. The Provision method adds the ContentService object to the database without requiring that you specify the assembly and class.

Note

The custom Provision method that you define is not the Provision method of the base SPPersistedObject class.

Public Sub Provision()
  ' Add the ContentService administration object to the database.
  Dim contentService As ContentService = ContentService.Local
  
  If contentService Is Nothing Then
    contentService = New ContentService(SPFarm.Local)
    contentService.Update()
  End If
End Sub
public void Provision()
{
    /* Add the ContentService administration object to the database. */
    ContentService contentService = ContentService.Local;

    if (contentService == null)
    {
        contentService = new ContentService(SPFarm.Local);
        contentService.Update();
    }
}

ContentLocationCollection Class File

The following example defines the ContentLocationCollection class, which includes constructors and an Add method for adding new content locations to the collection.

Public Class ContentLocationCollection

  Public Sub New(parent As SPPersistedObject)
    MyBase.New(parent)
  End Sub
  
  Public Sub Add(url As String)
    Dim location As New ContentLocation(String.Empty, Me.Parent)
    
    location.Url = url
    
    location.Update()
  End Sub
End Class
public class ContentLocationCollection : SPPersistedChildCollection<ContentLocation>
{
    public ContentLocationCollection(SPPersistedObject parent) : base(parent)
    {;}

    public void Add(String url)
    {
        ContentLocation location = new ContentLocation(String.Empty, this.Parent);

        location.Url = url;

        location.Update();
    }
}

ContentLocation Class File

The following example defines an enumeration, ContentLocationType, that specifies the type of content location, and a class, ContentLocation, that defines the properties for a content location, including its display name, type, URL, and output path. Specifying the Persisted attribute makes a property setting persist in the database.

The ContentLocation class includes the following members:

  • DisplayName   Property to get the display name of the location.

  • Url   Property to get or set the URL for a content location.

  • LocationType   Property to get or set the location type.

  • ContentOutputPath   Property to get or set an output path.

Public Enum ContentLocationType
    Web
    List
End Enum 'ContentLocationType

Public Class ContentLocation
  Inherits SPPersistedObject
    <Persisted()>  _
    Private locationType As ContentLocationType

    <Persisted()>  _
    Private contentOutputPath As String

    <Persisted()>  _
    Private url As String

    Public Sub New()
    End Sub 'New

    Public Sub New(name As String, parent As SPPersistedObject)
        MyBase.New(name, parent)
    End Sub 'New

    Public Overrides ReadOnly Property DisplayName() As String
        Get
            Return Me.url
        End Get
    End Property

    Public Property Url() As String
        Get
            Return Me.url
        End Get
        Set
            If Me.url = value Then
                Return
            End If

        Me.url = value

        ' The Name property must be unique among multiple children in a 
        ' collection.  Use the URL to ensure uniqueness. 
         Me.Name = Me.url
        End Set
    End Property
      
    Public Property LocationType() As ContentLocationType
        Get
            Return Me.locationType
        End Get
        Set
            Me.locationType = value
        End Set
    End Property 
      
    Public Property ContentOutputPath() As String
        Get
            Return Me.contentOutputPath
        End Get
        Set
            Me.contentOutputPath = value
        End Set
    End Property
End Class 'ContentLocation
public enum ContentLocationType
{
    Web,
    List
}

public class ContentLocation : SPPersistedObject
{
    [Persisted]
    private ContentLocationType locationType;

    [Persisted]
    private String contentOutputPath;

    [Persisted]
    private String url;

    public ContentLocation()
    {}

    public ContentLocation(string name, SPPersistedObject parent)
      : base(name, parent)
    {;}

    public override string DisplayName
    {
        get
        {
            return this.url;
        }
    }

    public String Url
    {
        get { return this.url; }
        set 
        {
            if (this.url == value)
            {
                return;
            }

            this.url = value;
            /* The Name property must be unique among multiple children in a collection.  Use the URL to ensure uniqueness. */
            this.Name = this.url; 
        }
    }

    public ContentLocationType LocationType
    {
        get { return this.locationType; }
        set { this.locationType = value; }
    }

    public String ContentOutputPath
    {
        get { return this.contentOutputPath; }
        set { this.contentOutputPath = value; }
    }
}

Add a Custom Action and ASPX Pages

Add .aspx pages to the \Admin folder, and define their code behind in your assembly. For information on administrative .aspx pages, see Central Administration Pages. Use a Feature to add a custom action to a Central Administration page. For information on adding a custom action, see How to: Modify the User Interface Using Custom Actions.

The following Elements.xml file adds a Content export custom action to the Global Configuration section of the Operations page that links to a contentman.aspx page for managing content locations.

<?xml version="1.0" encoding="utf-8" ?>
<Elements xmlns="https://schemas.microsoft.com/sharepoint/">
  <CustomAction
    Id="ContentManagement"
    GroupId="GlobalConfiguration"
    Location="Microsoft.SharePoint.Administration.Operations"
    Sequence="31"
    Title="Content export">
    <UrlAction Url="/_admin/contentman.aspx" />
  </CustomAction>
</Elements>

The contentman.aspx file to which the custom action points can include links to form pages for creating, displaying, or editing content location items. Code behind for the New item page, for example, can include logic like the following, which adds location items for URLs that are typed in a urlImportExport box on the page, and which redirects to the contentman.aspx page:

Imports System
Imports System.Collections.Generic
Imports System.Text
Imports Microsoft.SharePoint.WebControls
Imports System.Web.UI
Imports System.Web.UI.WebControls

Namespace MS.Samples.SharePoint.ContentManager

    Public Class NewContentImportExportPage
        Inherits Page
        Protected urlImportExport As InputFormTextBox

        Protected Sub SaveNewImportExport(sender As Object, eventArgs As EventArgs)
            Dim service As ContentService = ContentService.Local

            service.Locations.Add(Me.urlImportExport.Text)

            Response.Redirect("/_admin/contentman.aspx", True)
        End Sub 'SaveNewImportExport
    End Class 'NewContentImportExportPage
End Namespace 'MS.Samples.SharePoint.ContentManager
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint.WebControls;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace MS.Samples.SharePoint.ContentManager
{
    public class NewContentImportExportPage : Page
    {
        protected InputFormTextBox urlImportExport;

        protected void SaveNewImportExport(object sender, EventArgs eventArgs)
        {
            ContentService service = ContentService.Local;

            service.Locations.Add(this.urlImportExport.Text);

            Response.Redirect("/_admin/contentman.aspx", true);
        }
    }
}

After you implement your custom service, you can access its data by instantiating the service and calling its members. You can also create other custom objects that inherit from other persisted objects in the Microsoft.SharePoint.Administration namespace. You can create a class, for example, that derives from the SPJobDefinition class to implement a timer job and perform timed operations through your custom service. Or you can inherit from the SPFeatureReceiver class to define event handling to register the service when it is installed or activated as a Feature.

Through persisted objects, you can add custom administration objects to the configuration database to persist the logic and data for a Web application that is built on the SharePoint Foundation platform.