Microsoft SharePoint Developer Documentation Team Blog
The Official Blog of the SharePoint Developer Documentation Team

December, 2007

  • Microsoft SharePoint Developer Documentation Team Blog

    How To: Customizing alert emails using IAlertNotifyHandler

    • 22 Comments

    In my post last week I talked about customizing alert notifications and alert templates. Sometimes you need to go further and create an alert handler.  This week I’d like to share a code sample from Rashid Aga, one of our escalation engineers.  His sample demonstrates how to intercept and modify alert mails using the IAlertNotifyHandler interface.

     

    Problem:

    ==============

    There are issues with particular field names like ItemName which will be truncated in an alert email at 70 characters. There can also be situations where you want to embed additional content in the email or change the layout and email appearance altogether.

     

    Solution:

    ==============

    Make use of the IAlertNotifyHandler interface to intercept the email and modify it.

     

    We can create our own class that inherits from the IAlertNotifyHandler interface and uses the OnNotification method. This will allow you to intercept the outgoing alert emails and modify them. We can access most of the properties for the alert and with some xml parsing and SharePoint object model code, we can extract all the information we need to build up the email. We can then construct the HTML stub to display the email based on your requirements and send the email out using SharePoint’s SendMail functionality.

     

    Steps:

    I have included the sample code below along with the steps to set up the scenario. I have formatted the output of my code to resemble the default alert template emails as close as possible, you can customize it further to suit your needs.

     

    1      Create a class project that inhertits from the IAlertNotifyHandler interface. Include the Microsoft.SharePoint and Microsoft.SharePoint.Utilities namespaces in the project.

                        This is the code for the class:

        public class Class1:IAlertNotifyHandler

        {

     

            #region IAlertNotifyHandler Members

     

            public bool OnNotification(SPAlertHandlerParams ahp)

            {

                try

                {

                    SPSite site = new SPSite(ahp.siteUrl+ahp.webUrl);

                    SPWeb web = site.OpenWeb();

                    SPList list=web.Lists[ahp.a.ListID];

                    SPListItem item = list.GetItemById(ahp.eventData[0].itemId) ;

                   

                    string FullPath=HttpUtility.UrlPathEncode(ahp.siteUrl+"/"+ahp.webUrl+"/"+list.Title+"/"+item.Name);

                    string ListPath = HttpUtility.UrlPathEncode(ahp.siteUrl + "/" + ahp.webUrl + "/" + list.Title);

                    string webPath=HttpUtility.UrlPathEncode(ahp.siteUrl+"/"+ahp.webUrl);

                    

                    string build = "";

                     if (ahp.eventData[0].eventType==1)

                     eventType="Added";

                     else if(ahp.eventData[0].eventType==2)

                     eventType="Changed";

                     else if(ahp.eventData[0].eventType==3)

                     eventType="Deleted";

     

                    build = "<style type=\"text/css\">.style1 {              font-size: small; border: 1px solid #000000;"+

                        "background-color: #DEE7FE;}.style2 {               border: 1px solid #000000;}</style></head>"+                    

                        "<p><strong>"+ item.Name.ToString() +"</strong> has been "+eventType +"</p>"+

                        "<table style=\"width: 100%\" class=\"style2\"><tr><td style=\"width: 25%\" class=\"style1\">"+

                        "<a href="+ webPath +"/_layouts/mysubs.aspx>Modify my Settings</a></td>"+

                        "<td style=\"width: 25%\" class=\"style1\"> <a href="+ FullPath +">View "+item.Name+"</a></td>"+

                        "<td style=\"width: 25%\" class=\"style1\"><a href=" + ListPath + ">View " + list.Title + "</a></td>" +

                        "        </tr></table>";

                    string subject=list.Title.ToString() ;              

                    SPUtility.SendEmail(web,true , false, ahp.headers["to"].ToString(), subject,build);

                    return false;

                }

                catch (System.Exception ex)

                {

                    return false;

                }

            }

     

            #endregion

        }

     

    2.            GAC the dll. 

    3.            Make a copy of the alertTemplates.xml file found at this location: C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\XML. Always work with a copy of AlertTemplates.xml, not the original.

    4.            Call this new file CustomAlertTemplates and save the file. Edit the file and search for the keyword properties:

    Include these additional lines into the properties block:

     

              <NotificationHandlerAssembly>AlertHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d59ecf2a3bd66904</NotificationHandlerAssembly>

              <NotificationHandlerClassName>AlertHandler.Class1</NotificationHandlerClassName>

        <NotificationHandlerProperties></NotificationHandlerProperties>

     

    The entire stub should look like this now:

            <Properties>

                <ImmediateNotificationExcludedFields>ID;Author;Editor;Modified_x0020_By;Created_x0020_By;_UIVersionString;ContentType;TaskGroup;IsCurrent;Attachments;NumComments;</ImmediateNotificationExcludedFields>

                <DigestNotificationExcludedFields>ID;Author;Editor;Modified_x0020_By;Created_x0020_By;_UIVersionString;ContentType;TaskGroup;IsCurrent;Attachments;NumComments;</DigestNotificationExcludedFields>

                <NotificationHandlerAssembly>AlertHandler, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d59ecf2a3bd66904</NotificationHandlerAssembly>

                    <NotificationHandlerClassName>AlertHandler.Class1</NotificationHandlerClassName>

                    <NotificationHandlerProperties></NotificationHandlerProperties>

      </Properties>

     

    Include this xml stub in each alert template section you want in the alert template file.

     

    5.            Run this command from C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\BIN:  stsadm -o updatealerttemplates -filename "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\TEMPLATE\XML\customalerttemplates.xml" -url <your sharepoint site url>

    6.            Run this command:  stsadm -o setproperty -pn job-immediate-alerts -pv "every 1 minutes" so that you can see the log file come back in one minute. Be sure to set the time back after testing.

    7.            Make sure you have SharePoint already configured for outgoing emails.

    8.            Make sure that you have alerts for the document library turned on if you are testing with the document library. 

    9.            Run this command from the command prompt: iisreset

    10.         Run this command from the command prompt: services.msc

    11.         From the services window, restart the Windows SharePoint Services Timer.

     

    Your custom email alert handler should be configured at this point. Create a new alert and you should get the updated custom email.

     

    Once again, my thanks to Rashid for this sample.

     

  • Microsoft SharePoint Developer Documentation Team Blog

    SharePoint SDKs (and Other Documentation Resources) Now Updated for SP1

    • 15 Comments

    By now you’ve no doubt heard that SP1 for Windows SharePoint Services 3.0, Office SharePoint Server 2007, and Office SharePoint Designer are now available. (And if you haven’t heard, go here to get all the important details before you download and install the Service Packs.)

    For a complete listing of the documentation available for SharePoint SP1, check out the What’s New in SharePoint Server 2007 Service Pack 1 page on MSDN, which includes information resources for both WSS and MOSS SP1.

    I’m happy to announce that as part of the SP1 push, we’ve again updated the WSS and MOSS SDKs on MSDN:

    ·         Windows SharePoint Services 3.0 SDK (December 2007 Refresh)

    ·         Office SharePoint Server 2007 SDK (December 2007 Refresh)

    Here’s a quick run-down of additions and updates we’ve made to the WSS SDK:

    New and Updated Material in the Windows SharePoint Services 3.0 SP1 SDK

    New conceptual sections and topics that detail new features in Windows SharePoint Services 3.0 SP1 include:

    ·      ASP.NET AJAX in Windows SharePoint Services

    This section provides overview information, installation instructions, and programming examples that introduce you to how Microsoft ASP.NET AJAX interacts with Web Parts. Topics include:

    ·         Overview: ASP.NET AJAX and Web Parts in Windows SharePoint Services 3.0

    ·         Installing ASP.NET 2.0 AJAX Extensions 1.0 in Windows SharePoint Services Version 3.0

    ·         Walkthrough: Creating a Basic ASP.NET AJAX-enabled Web Part

    Other new conceptual sections and topics include:

    ·      Workflow Actions Schema Overview

    The section discusses how to use the Workflow Actions schema to create and deploy custom workflow actions. The section includes reference topics for each of the 14 elements in the schema, as well as an example .ACTIONS file:

    ·         .ACTIONS File Example (WorkflowActions)

    ·      Alerts in Windows SharePoint Services

    This section provides 8 new topics of overview information and programming tasks to help you work with Windows SharePoint Services 3.0 Alerts.

    Significantly revised sections and topics include:

    ·      Custom Field Types

    This section has been expanded with nine new topics, including the following new walkthrough:

    ·         Walkthrough: Creating a Custom Field Type

    In addition, reference material for all base field-rendering control types, and most derived types, in Microsoft.SharePoint.WebControls has been expanded.

    ·      Mobile Development

    This section has been expanded with 6 new conceptual topics, including the following new procedural and walkthrough topics:

    ·         How to: Customize Mobile Home Pages

    ·         How to: Customize Mobile List View and Form Pages

    ·         How to: Customize Field Rendering on Mobile Pages

    ·         Walkthrough: Customizing Item Titles on a Mobile Display Form

    ·         Walkthrough: Creating a Custom Field Rendering Control for Mobile Pages

    In addition, reference material for all types in the Microsoft.SharePoint.MobileControls namespace has been added or expanded. The types in this namespace are now fully documented.

    ·      Working with Site Templates and Definitions

    Several topics have been expanded.

    ·      All types in the Microsoft.SharePoint namespace that connected to auditing are now fully documented.

    ·      More than 80 code samples rewritten to adhere to the best coding practices as described in the following articles:

    ·         Best Practices: Common Coding Issues When Using the SharePoint Object Model

    ·         Best Practices: Using Disposable Windows SharePoint Services Objects

    ·      Greatly expanded reference material for 39 types in the Microsoft.SharePoint.Utilities namespace.

    This update also includes numerous other updates and revisions to existing SDK content.

    And as for the SharePoint Server 2007 SDK, we’ve added and revised quite a bit of material there as well:

    New and Updated Material in the SharePoint Server 2007 SP1 SDK

    New and Improved Features in Office SharePoint Server 2007 SP1

    ·         Support for Custom HTTP and SOAP Headers

    New Conceptual Topics and How Tos

    ·         SharePoint Products and Technologies Customization Best Practices

    ·         Modeling Web Service Systems

    ·         Modeling Database Systems

    ·         Document Converter Framework Sample

    ·         Working with Menus and Navigation Objects

    ·         Modifying Navigation Settings Through the UI

    ·         Customizing Navigation Controls and Providers

    New Web Services and Class Library Reference Topics

    ·         Microsoft.SharePoint.UserProfiles (56 classes) 

    ·         User Profile Web Service (14 classes) 

    ·         User Profile Change Web Service (2 classes) 

    ·         Exception classes (multiple classes in various namespaces)

    ·         Internal only classes (multiple classes in various namespaces)

    New Tools/Samples

    ·         WCM Document Converters Code sample

    ·         Workflow Collect Feedback ASPX sample

    Check it out, and as always, let us know what you think—either through rating our content, entering a comment on the topic online, or pinging us with an email through our blog.

  • Microsoft SharePoint Developer Documentation Team Blog

    Customizing Alert Notifications and Alert Templates in Windows SharePoint Services 3.0

    • 41 Comments

    Hello.  My name is Albert Meerscheidt and I’m one of the Programming Writers on the Windows SharePoint Services SDK team.

    In the coming months I will be posting about the content that’s on the publishing horizon.  The first topic that I'd like to discuss is how to customize alert notifications and alert templates in Windows SharePoint Services 3.0. The following is a somewhat abridged version of what you will see in the upcoming SDK update.

       Overview

    Alerts are an e-mail subscription notification service in Windows SharePoint Services 3.0. Users can create alerts to be notified of changes to list items (item level alert), documents, lists (list level alert), or document libraries. Alerts in Windows SharePoint Services 3.0 are quite flexible; when you create an alert you have options such as when to be notified and what kind of changes will trigger the alert. Alerts can be managed by users and administrators and customized by developers.

    After an alert has been created, changes that fit the criteria specified in the alert are recorded in an event log. Alerts are generated by a timer job that reads the event log, formats the alert email using an alert template, and then sends that email out to the user.

    Alert templates are stored in Alerttemplates.xml. Alerttemplates.xml defines the format, contents, and properties used to create alert messages from each list type in Windows SharePoint Services 3.0. Developers can customize alerts by modifying a copy of Alerttemplates.xml and then loading the customized alert templates using the stsadm -o updatealerttemplates command.

    Note   Do not modify Alerttemplates.xml itself. Doing so may result in loss of functionality when upgrading or installing service packs.

    The <filters> element in each template allows you to create custom triggers for events by using Collaborative Application Markup Language (CAML) queries.

    The default timer interval can be changed to adjust the latency of 'immediate' alerts.

       Default Timer Interval

    Alert emails can be sent immediately or in a daily or weekly summary. Immediate alerts are not actually immediate; they are sent out after a delay determined by the timer interval. This is done for performance reasons.

    The default timer interval is 5 minutes. Thus, if this interval has not been changed you could notice a delay of up to 5 minutes (the default timer interval) before an alert message is generated. Changes are recorded as they occur in an event log (discussed later in this article) and then alert messages are rendered from that log when the next timer job runs.

    The default timer interval can be determined using the stsadm command.

    stsadm -o getproperty -pn job-immediate-alerts -url<url> command.

    The timer interval property can be set using stsadm. In this example I set the interval to 3 minutes.

    stsadm -o setproperty -pn job-immediate-alerts -url<url> -pv "every 3 minutes"

    For more information about STSADM, see http://technet2.microsoft.com/Office/en-us/library/188f006d-aa66-4784-a65b-a31822aa13f71033.mspx?mfr=true.

       Alert templates

    Alert templates are stored in the configuration database and are available at the web application level. Alert templates are defined in Alerttemplates.xml.

    Windows SharePoint Services 3.0 ships with the following templates:

    Table 1. Predefined alert templates

    Alert Template Name

    Description

    SPAlertTemplateType.GenericList

    The first alert template in Alerttemplates.xml. GenericList is used unless there is a match to one of other event types.

    SPAlertTemplateType.DocumentLibrary

    Notification of changes in document libraries

    SPAlertTemplateType.Survey

    Notification of changes in surveys

    SPAlertTemplateType.Links

    Notification of changes in links

    SPAlertTemplateType.Announcements

    Notification of changes in announcements

    SPAlertTemplateType.Contacts

    Notification of changes in contacts

    SPAlertTemplateType.Events

    Notification of changes in events

    SPAlertTemplateType.Tasks

    Notification of changes in tasks

    SPAlertTemplateType.DiscussionBoard

    Notification of changes in discussion boards

    SPAlertTemplateType.PictureLibrary

    Notification of changes in picture libraries

    SPAlertTemplateType.XMLForm

    Notification of changes in XML form

    SPAlertTemplateType.DataConnectionLibrary

    Notification of changes in data connection libraries

    SPAlertTemplateType.AssignedtoNotification

    Assigned to task / issue list notifications

     

    Alerttemplates.xml is located at: Local_Drive\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Template\XML directory.

    Note   Do not modify Alerttemplates.xml itself. Make changes to a working copy.

     

       Alert Template Format

    Alert templates have the following format:

    <AlertTemplates>

     <AlertTemplate Type="List" Default="True" Name ="Default Template">

     </AlertTemplate>

    <AlertTemplate Type="List" Name="SPAlertTemplateType.GenericList">

      <EventTypes IsVisible="True"/>

      <Format>

      </Format>

      <Filters>

        <FilterDefinition>

        </FilterDefinition>

      </Filters>

      </AlertTemplate>

    </AlertTemplates>

     

    Table 2. Alert Template Attributes

    Attribute

    Description

    Name

    The name of the template. Searching on the template names provides an easy way to locate a particular template.

    Type

    The type attribute can be set to List, Item, or Custom.

    Default

    Default="True" sets the default alert template.

    Filters

    If IsVisible = "True", then the filter fields are displayed when creating the alert.

    Filter Definitions

    Define a filter (query).

    Format

    Formatting of the email is defined in the <Format> element.

    Fields

    Specify which fields to render in the alert email.

     

       Filters and Filter Definitions Elements

    Filters enable you to create new triggers for an event such as 'the priority of a task has changed'. To modify existing filters or create additional filters modify the <FilterDefinition> element of the appropriate template. Define the query element using inside the filter using Collaborative Application Markup Language (CAML).  This query will create an alert event if the event date, end date, or location changes.

     

    <FilterDefinition>

       <FriendlyName>$Resources:Alerts_4_filter;</FriendlyName>

       <ShortName>$Resources:Alerts_4_filter_shortname;</ShortName>

       <Query>

       <Or>

          <Or>

          <Neq><FieldRef name="EventDate/New"/>

          <FieldRef name="EventDate/Old"/>

          </Neq>

          <Neq>

             <FieldRef name="EndDate/New"/>

             <FieldRef name="EndDate/Old"/>

          </Neq>

       </Or>

          <Neq>

             <FieldRef name="Location/New"/>

             <FieldRef name="Location/Old"/>

          </Neq>

       </Or>

       </Query>

    </FilterDefinition>

     

    Resource variables listed in AlertTemplates.xml, such as $Resources:Alerts_anything_filter_shortname, can be found in core.resx; located in the Local_Drive\Program Files\Common Files\Microsoft Shared\Web Server Extensions\12\Resources directory.

    Note   The Query element in the Alerts schema contains no Where element.

     

    For more information about CAML query schema, see http://msdn2.microsoft.com/en-us/library/ms467521.aspx.

       

       Format Element

    Use the format element of an alert template to modify the look of the alert email. You can also customize the formatting of the alert email by using embedded styles.

    <Format>

    <Digest> - digest format

        <Subject>

        </Subject>

        <Header>

        </Header>

        <HeaderFieldsHeader>

        </HeaderFieldsHeader>

        <HeaderFields>

        </HeaderFields>

        <HeaderFieldsFooter>

        </HeaderFieldsFooter>

        <RowHeader> - each row’s header (row refers to each item level change in the digest notification)

        </RowHeader>

        <RowFields> - each row’s fields

        </RowFields>

        <RowFooter> - each row’s footer

        </RowFooter>

        <Footer>

        </Footer>

    </Digest>

    <Immediate> - immediate notification format

        <Subject> - email subject

        </Subject>

        <Header>

        </Header>

        <Fields> - the html for the fields. CAML will go over all the fields and render this part of the template. The field itself should be referenced using <GetVar Name=”OldValue#{Field}” /> or <GetVar Name=”NewValue#{Field}” />

        </Fields>

        <Footer>

      </Footer>

    </Immediate>

    </Format>

     

        Fields Element

    Specify the fields to be rendered in the email.

    For example you can specify <GetVar Name="NewValue#{Field}"> inside the <Fields> section. More examples can be seen in AlertTemplates.xml.

    To exclude some fields from being rendered in the email, you should include them in the <DigestNotificationExcludedFields> and <ImmediateNotificationExcludedFields> section. DigestNotificationExcludedFields and ImmediateNotificationExcludedFields give you the flexibilty to render different fields for immediate alerts and summary (digest) alerts.

     

    In addition to these, CAML is supported. For example you can specify <GetVar Name="NewValue#{Field}"> inside the <Fields> section. More examples can be seen in AlertTemplates.xml.

     

    To exclude some fields from being rendered in the email, you should include them in the <DigestNotificationExcludedFields> and <ImmediateNotificationExcludedFields> section.

       Properties Element

    The properties element allows you to include or exclude fields from the list that would be shown in the email notification. The example below demonstrates how to exclude fields for both the immediate and summary (digest) alerts.

    <Properties>

    <ImmediateNotificationExcludedFields>ID;Author;Editor;Modified_x0020_By;Created_x0020_By;_UIVersionString;ContentType;TaskGroup;IsCurrent;Attachments;NumComments;</ImmediateNotificationExcludedFields>

                <DigestNotificationExcludedFields>ID;Author;Editor;Modified_x0020_By;Created_x0020_By;_UIVersionString;ContentType;TaskGroup;IsCurrent;Attachments;NumComments;</DigestNotificationExcludedFields>

            </Properties>

       Customizing the Alert Email

    Alert UI elements

    In addition to the formatting styles defined in the <format> element, alert templates include formatting instructions for user interface elements, such as the Modify my alert settings, Mobile View, and View <list> buttons, which can be modified or removed.

    Modify my alert settings button

    The following code displays the Modify my alert settings button:

    <GetVar Name="MySubsUrl" URLEncodeAsURL="TRUE"/>

                <HTML><![CDATA[">$Resources:Alerts_link_modify;</a></td>

            <td class="toolbarsep">|</td>]]></HTML>

    View list URL button

    The following code displays the List URL button:

    <GetVar Name="ListUrl" URLEncodeAsURL="TRUE" />

                    <HTML><![CDATA[">$Resources:Alerts_link_view; ]]></HTML><GetVar Name="ListName" HTMLEncode="TRUE" />

    Mobile View button

    The following code displays the Mobile View button:

    <Switch>

            <Expr><GetVar Name="MobileUrl"/></Expr>

              <Case Value = "NULL"/>

              <Default>

                  <HTML><![CDATA[

            <td class="toolbarsep">|</td>

            <td class="toolbarbutton"><a href="]]></HTML><GetVar Name="MobileUrl" />

         <HTML><![CDATA[">$Resources:Alerts_mobile_view;</a></td>]]></HTML>

             </Default>

    </Switch>

    Steps to Modify Alerts

    You can use any XML editing tool to edit the templates.

    1.      Create a working copy of AlertTemplates.xml.

    Note   Remember to always modify a copy of Alerttemplates.xml, not Alerttemplates.xml itself.

    2.      Edit the working copy that you just created.

    3.      Use the stsadm command to read the changed templates into the database.
    STSADM -o updatealerttemplates -url <http://urlname> -filename <your working copy filename>.

    4.      Restart IIS.

    Note   It may be necessary to restart SharePoint Timer Services.

    Creating your own alert template

    If you want, you can create your own template, and then use the stsadm command to load that template. Pattern your template after one of the templates in Alerttemplates.xml.

     

    A particular instance of a list can use a specific alert template by setting the SPList.AlertTemplate property with the desired template. Any new alert created for this list through the subnew.aspx or through the object model using SPAlerts.Add(SPList / SPItem, SPEventType, SPAletFrequency) will pick up the alert template defined for the list.

     

    To assign a custom alert template to a specific list

    1.      Create a new custom template with a unique Name attribute in your working copy of AlertTemplates.xml (You can copy paste the entire section with Name SPAlertTemplateType.GenericList, change the name and modify the sections you want to). Modify the template as necessary. After restarting IIS, write object model code to set the list alert template

    SPAlertTemplateCollection ats = new SPAlertTemplateCollection((SPWebService)(WebApplication.Parent)); //give appropriate values for WebApplication

    list.AlertTemplate = ats[“name from above”];

    list.Update();

     

       Event Logs

    Rendering of alert emails occurs some time after the change that generated the alert. Data in the EventCache and EventLog tables is used for rendering the alert since the changed item may no longer exist, or exist in the same form, at the time the email is sent.

    The event log uses a SQL table called the EventCache to record SQL level events as they occur.  Each row in the table corresponds to an event.  The events can be read using the WSS object model.  In general, the number of rows written to the table is the minimum necessary to capture the semantics of the event.  The assumption is that the reader of the event knows how to use the event row to calculate all the implications of a given event.  For example, when a folder is deleted, the folder delete event is the only event written to the change log.  No events are written for the files and sub-folders that are contained in the folder.  The reader of the folder delete event needs to understand that it implies the deletion of the entire contents of the folder.

    By default, the change log retains 15 days worth of data.  You can configure this using the “web application general settings” page.  There is a timer job that runs daily to delete all expired change log entries.

    Change Events

    Change events are returned as objects in an SPChangeCollection.  Each change object is a subclass of the SPChange object.  Depending on the type of SPChange object, different properties are available.  The change collection is created by calling SPSite.GetChanges(), SPWeb.GetChanges(), SPList.GetChanges(), or SPContentDatabase.GetChanges().  An SPChangeToken object is passed into GetChanges() to specify where in the log to begin reading.  An SPChangeToken can be serialized to a string format by calling the ToString() method. 

    Use the SPList.CurrentChangeToken property to get the current change token for that list object.  There is a similar property on the SPSite, SPWeb, and SPContentDatabase objects.  In general, the SPChangeToken from one object cannot be used in the GetChanges() method of another object.  The only exception is that the SPChangeToken from an SPContentDatabase can be used in any object contained in that content database.  There is also an object called an SPChangeTokenCollection which can be used to store multiple change tokens together, that can then be serialized to one single string.

    Change Log Event Types

    The following is a description of the event types recorded in the change log.

    Table 3. Event Types

    Event Type

    Description

    Add

    An object was added.  For items, files and folders, the TimeLastModified in the log should be the same as the Created datetime of the object.

    Modify

    An object was modified.  For items, files and folders, the TimeLastModified in the log should be the same as the modified date time of the object.

    Delete

    An object was deleted.

    Rename

    An object was renamed.  This means that the file name portion of the URL was changed.

    MoveInto/MoveAway

    An object was renamed.  This means that the path portion of the URL was changed.  The leaf portion may or may not have been changed also.

    Restore

    An object was restored from the recycle bin or from a backup. This event signals to a sync client change log reader that it needs to re-sync the object and all its children.

    Role Add

    A role was added at the scope of the object.

    Assignment Add

    A role assignment was added at the scope of the object.

    System Modify

    An object was modified without its Modified date time or Modified By property changing.  The TimeLastModified in the log should be the time that the update took place, not the Modified date time property.

    Member Add

    A member is added to a SharePoint group.

    Member Delete

    A member is deleted from a SharePoint group.

    Role Delete

    A role was deleted at the scope of the object.

    Role Update

    A role was updated at the scope of the object.

    Assignment Delete

    A role assignment was deleted at the scope of the object.

    Navigation

    The navigation nodes were updated at the scope of the object.

     

    Object Types

    The following is a list of the object types that may have changes recorded in the change log.  Not all event types are possible on all object types.

    Table 4. Object Types

    Object Type

    Description

    Item

    This object type applies to all objects that exist in a list: list items, files and folders

    List

    List object type

    Web

    Web object type

    Site

    Site object type

    File

    This object type applies to files that exist outside of a list and don’t have a corresponding item.

    Folder

    This object type applies to folders that exist outside of a list and don’t have a corresponding item.

    Alert

    Alert object type

    User

    User object type

    Group

    Group object type

    ContentType

    Content object type

    Field

    Field object type

    SecurityPolicy

    A security policy change has been made at the web application level that affects the entire content database.  This event was added late in the development cycle, so it and the content database level restore event are logged as a site level event with a SITEID of “00000000-0000-0000-000000000000”

     

       Conclusion

    Alerts are quite flexible; when you create an alert you have options such as when to be notified and what kind of changes will trigger the alert. Alerts can be managed by users and administrators and customized by developers.

    Alerts are generated by a timer job that reads the event log, formats the alert email using an alert template, and then sends that email out to the user.Developers can customize these alert emails by modifying alert templates. Alert templates are stored in Alerttemplates.xml. Alerttemplates.xml defines the format, contents, and properties used to create alert messages from each list type in wssversion3. The <filters> element in each template allows you to create custom triggers for events by using Collaborative Application Markup Language (CAML) queries. Developers can customize alerts by modifying a copy of Alerttemplates.xml and then loading the customized alert templates using the stsadm -o updatealerttemplates command.

     

    In my next post I'll talk about how to use the IAlertNotifyHandler interface to customize alerts. 

     

     

     

     

  • Microsoft SharePoint Developer Documentation Team Blog

    Content Migration in SharePoint (Post 2):

    • 0 Comments

    Key Concepts in Selective Migration 

    Picking up where the first post left off, today's foray explores the basic concepts of SharePoint content migration. Most of these concepts come into play in nearly every migration scenario where you use the SharePoint.Deployment namespace APIs. This post covers the following concents:

    1. Content selection (also known as "cherry picking")
    2. The content migration package (.cmp) file
    3. Object identity (that is, retaining object identity on import)
    4. Reparenting objects
    5. Handling content types when migrating a site collection
    6. Handling workflows when migrating

     

         Content selection for export

    Once the initial full migration has occurred and the source and destination sites are established, selective migration relies on logic in your custom code for selection criteria that determines which items are selected for migration, and when. Also known as "cherry picking," this is the process through which specific items on the source site collection are migrated to the destination site collection based on selection criteria that is specified in the custom code.

    In the basic scenario, logic in a code module associated with a timer job runs on a recurring schedule (for example, every 24 hours at 3:00 a.m.); the module examines date stamps or change logs (or both), then selects and exports only those files that have changed since the last migration.

    The operation relies on the identity of objects in the source and destination site collections. At import time, the destination recognizes objects by GUID identifiers and then updates their corresponding files accordingly.

         Content migration package (.cmp) file

    The content migration package is a compressed cabinet (.cab) file that uses the .cmp file extension. The migration package (.cmp) file aggregates data for export from the source site, along with site structure and dependency data, and stores it as compressed, serialized XML files.

    While the export operation compresses site data by default, you can override this behavior and export uncompressed files by changing the SPDeploymentSettings.FileCompression property to false. This property is on the SPDeploymentSettings object.

    When using file compression, you must must specify the name of the compressed content migration (.cmp) file using the BaseFileName property on the SPExportSettings object. The FileLocation property specifies where the compressed file is located on the source server.

    By default, the .cmp files are limited to 24 MB in size, although you can change this using the FileMaxSize property. When site data exceeds the 24 MB limit, your site data is separated in to two or more migration files. However, where a single file exceeds the maximum file size, the operation resizes the .cmp file to accommodate the file. You can have any number of .cmp files.

         Object identity

    SharePoint objects are identified by GUID on the source server. Upon import, by default, the objects are assigned new GUIDs on import to the destination. To support selective migration scenarios, however, you must change the default and retain the identity of the object that you are exporting. This is very important, because the only way that files can successfully update their corresponding versions on the destination site is for the destination to recognize the object by its identifying GUID.

    You can retain object identity by setting the RetainObjectIdentity property on the SPImportSettings object to true.

    Note   To use the RetainObjectIdentity property to support selective migrations, you must also set the ExportMethod property to the value ExportChanges.

    Retaining object identity should be used carefully, and in limited scenarios. It most commonly supports a publishing scenario in which source and one or more destination servers are mirror images — for example, where a development or test server is migrating updates to one or more production servers.

    If you are creating a new site that you know in advance will receive file updates on a regular basis (for example, from a development or test server), you can enable a smooth link between the two by first doing a full migration from the source to a completely blank site, but with RetainObjectIdentity property set to true. It is very important, then, that you never modifythe destination. The initial migration established the mirrored hierarchy and mappings; any modifications to the destination can break the linkage. If this relationship gets broken, your only recourse is to delete the destination and then reestablish the linkage as originally done.

    Note   In the scenario described above, you can use Stsadm.exe to complete the export portion of the migration, since it does not support the retention of object identity. However, you must use the migration APIs to complete the import portion of the migration in order to retain object identity.

    SharePoint content databases do not permit duplicate GUIDs or file names, so you must be careful when implementing this property. You should not retain object identity when you are simply updating files on the destination server, because the import operation cannot determine whether a file is new or an update, and will therefore place a duplicate copy of the file on the destination.

    This happens because the migration process uses GUID identifiers, but only down to the level of the item collection. Beneath that level, that is, for individual files, the system uses the file name. Consequently, the import simply copies over the updated version of the existing file and leaves the original intact, potentially creating duplicates. When the destination server then encounters duplicate file names, it cannot resolve the ambiguity and becomes unstable.

    Important   When deleting files, it is very important to delete the files on both the source and destination servers. Not doing so can cause duplicate files names and an unstable site.

    To support field deletion (a feature that deletes previous versions of items on the source server when the migration updates and deletes the same file on the destination), the RetainObjectIdentity property must be set to true.

     

         Reparenting

    Now let's consider a much different scenario. Instead of a publishing scenario, in which objects on the source server have to map to their equivalent files on the destination server, consider instead a scenario in which a specific subweb or list item is migrated and you want to place it at a different place in the destination hierarchy. This is a very common requirement and you handle this by reparenting the object (or objects) on import.

    It's important to note that, as discussed in the section on retaining object identity, any time that you do not retain object identity, a migrated object will need a new parent specified on import. It doesn't matter if the destination site collection is the same site collection as the source or even if it is in the same database as the source site collection. It also doesn't matter if the destination site collection is in the same or a different farm as the source site collection.

    If you export an item from a database without exporting its parent, then the item that you've exported will become orphaned in the content migration package, but that's not necessarily a problem. A package can contain multiple orphaned objects.

    Having orphaned objects in the migration package is not a problem because the import method allows us to define a new parent for each of these orphaned objects. This is what is meant by "reparenting." However, objects that are exported with their parent objects keep their relationships during migration. So, for example, if you export Web A and Web B is a sub web of web A, then you can only change the parent of web A. The parent of Web B will remain as Web A, because Web B.

    There are two ways to reparent orphaned objects when importing. In the first, you import all of your orphaned objects into the same subweb, while in the other method you assign parent objects individually to each orphaned object.

          Reparent by importing all orphans to the same subweb

    You can reparent your orphan objects by simply importing all of them into the same subweb. However, this only works if all of the orphan objects are destined for the same subweb. For example, this is the preferred method if you have exported two or more list or document library objects and you want to import them all into the same subweb. This works even if the export objects are from different source sites. Here is some sample code for doing this. Of particular note are the WebUrl and RetainObjectIdentity properties.

     

    SPImportSettings settings = new SPImportSettings();

    settings.SiteUrl = "http://localhost:2001";

    settings.WebUrl = "http://localhost:2001/MyDestinationWeb";

    settings.FileLocation = @"c:\export";

    settings.FileCompression = false;

    settings.RetainObjectIdentity = false;

     

    SPImport import = new SPImport(settings);

    import.Run();

     

    In the above example, the WebUrl property defines the site (the SPWeb) that becomes the new parent for all orphaned objects in the export package.

    Note   You cannot use this method to reparent orphaned objects if the migration package contains orphaned documents; SharePoint site cannot become the parent of a document document object (only list or folder objects can parent documents).

    Note, too, that the RetainObjectIdentity property is set to false. This is important because keeping this property as false (which is the default) cases the operation to assign a new GUID to the orphaned objects, which is essential for reparenting those objects.

          Reparent by assigning new parent objects individually

    Assigning new parents to orphaned objects individually is much more flexible than the previous method, but also requires more coding. In this approch, you must intercept the import operation to assign a new parent to each orphaned object after the operation has accumulated a list of all orphaned objects in the migration package. You can do this by implementing a custom event handler, as in the following example:

     

    static void OnImportStarted(object sender, SPDeploymentEventArgs args)

    {

       SPSite site = new SPSite("http://localhost:2001");

       SPWeb web = site.RootWeb;

     

       SPImportObjectCollection rootObjects = args.RootObjects;

       foreach (SPImportObject io in rootObjects)

       {

          io.TargetParentUrl = web.Url;

       }

     

       web.dispose();

       site.dispose();

    } 

     

    This approach uses the RootObject collection of the event arguments to aggregate all and then reparent all of the orphan objects. Actually, we do much the same thing that we did when we imported all of the objects to the same subweb, that is, we defined a specific site (SPWeb) as the new parent of all included orphaned objects. However, notice how you can extend the logic in the event handler to, for example, assign different parents to different orphans based on object type, as shown here:

     

    static void OnImportStarted(object sender, SPDeploymentEventArgs args)

    {

       SPSite site = new SPSite("http://localhost:2001");

       SPWeb web = site.RootWeb;

       SPList list = web.Lists["MyDocLib"];

     

       SPImportObjectCollection rootObjects = args.RootObjects;

       foreach (SPImportObject io in rootObjects)

       {

          if (io.Type == SPDeploymentObjectType.ListItem)

          {

             io.TargetParentUrl = list.RootFolder.ServerRelativeUrl;

          }

          if (io.Type == SPDeploymentObjectType.List)

          {

             io.TargetParentUrl = web.Url;

          }

          ...

       }

     

       web.dispose();

       site.dispose();

    } 

     

    There is a great deal of flexibility here. In addition to reparenting based on the object type, you could instead look at the original TargetParentUrl, for example, to obtain the location of the source and then include that as part of your reparenting logic.

    The code example below shows us how to hook up the event handler to the import operation. You can do this as follows:

     

     

    static void ImportDocLibItem()

    {

       SPImportSettings settings = new SPImportSettings();

       settings.SiteUrl = "http://localhost:2001";

       settings.FileLocation = @"c:\deployment5";

       settings.FileCompression = false;

       settings.RetainObjectIdentity = false;

     

       SPImport import = new SPImport(settings);

     

       EventHandler<SPDeploymentEventArgs> eventHandler = new EventHandler<SPDeploymentEventArgs>(OnImportStarted);

       import.Started += eventHandler;

     

       import.Run();

    }

     

    Notice that you need to register the event handler with the import class before you start the import operation.

     

    There are several more event handlers that you can register and use during import; these are explained in more details at help topics for SPImportEvents and for SPExportEvents. Similar events can also be registered for export, if required:

     

     

         Content types (handling)

    Migration operations that use the export and import commands include your content type definition schema files in the export package. However, in cases where content type definitions hold references to custom SharePoint features, you must manually install and configure on the destination compute the feature for which the content type holds a reference. Features that are native to the SharePoint server environment will have their type definition references restored automatically.

    On starting the import operation, you will receive a warning message that alerts you with the identity of custom features for which references must be recreated. You must resolve these references after completing the import.

    For more information about content types, see Content Types. For more information about SharePoint features, see Working with Features.

     

         Workflows

    Workflows are not included in export packages so when you initially set up a migration target, you must copy any custom workflows that you have onto the destination server and reconfigure the workflow association table. This includes creating (or restoring on the destination) the workflow definitions files.

    Of course, manually restoring your custom workflows on the migration destination is only necessary when you initially set up your destination server. Subsequently, when doing selective migrations in a publishing scenario, it is advantageous that workflows are excluded from the migration package.

    For more information about managing workflows, see the following:

    ·         Introduction to Workflows in Windows SharePoint Services

    ·         Workflows in Windows SharePoint Services

     

Page 1 of 1 (4 items)