Tuesday, October 18, 2016

How to get events history for specific list or document library in Sharepoint

Sometime we need to retrieve events history for specific Sharepoint list or document library for particular period. Internally events log is stored in EventCache table in content database. In order to get it programmatically we can use SPChange* classes from Sharepoint object model. E.g. the following example shows how to get list of all documents which were added today:

   1: private static List<ItemChange> getListItemChanges(SPWeb web,
   2:     SPList list)
   3: {
   4:     try
   5:     {
   6:         if (list == null)
   7:         {
   8:             return new List<ItemChange>();
   9:         }
  10:  
  11:         var today = DateTime.Today;
  12:         var changeTokenStart = new SPChangeToken(
  13:             SPChangeCollection.CollectionScope.List, list.ID,
  14:             today.ToUniversalTime());
  15:         var changeTokenEnd = new SPChangeToken(
  16:             SPChangeCollection.CollectionScope.List, list.ID,
  17:             today.AddDays(1).ToUniversalTime());
  18:         var changeQuery = new SPChangeQuery(false, false);
  19:         changeQuery.Item = true;
  20:         changeQuery.Add = true;
  21:         changeQuery.Delete = false;
  22:         changeQuery.Update = false;
  23:         changeQuery.ChangeTokenStart = changeTokenStart;
  24:         changeQuery.ChangeTokenEnd = changeTokenEnd;
  25:         var changes = list.GetChanges(changeQuery);
  26:  
  27:         var listItemChanges = new List<ItemChange>();
  28:         foreach (SPChangeItem c in changes)
  29:         {
  30:             SPListItem item = null;
  31:             try
  32:             {
  33:                 item = list.GetItemById(c.Id);
  34:             }
  35:             catch (Exception x)
  36:             {
  37:                 Console.WriteLine("Error occured: {0}", x.Message);
  38:                 continue;
  39:             }
  40:  
  41:             if (item == null)
  42:             {
  43:                 continue;
  44:             }
  45:  
  46:             listItemChanges.Add(new ItemChange
  47:                 {
  48:                     Time =
  49: web.RegionalSettings.TimeZone.UTCToLocalTime(c.Time),
  50:                     ChangeType = c.ChangeType,
  51:                     FileName = item.File.Name,
  52:                     Url = SPUrlUtility.CombineUrl(web.Url, item.File.Url)
  53:                 });
  54:         }
  55:         return listItemChanges;
  56:     }
  57:     catch (Exception x)
  58:     {
  59:         Console.WriteLine("Exception occured: {0}\n{1}",
  60:             x.Message, x.StackTrace);
  61:         return new List<ItemChange>();
  62:     }
  63: }

Class ItemChange used in this example if POC helper class defined like this:

   1: public class ItemChange
   2: {
   3:     public DateTime Time { get; set; }
   4:     public SPChangeType ChangeType { get; set; }
   5:     public string FileName { get; set; }
   6:     public string Url { get; set; }
   7: }

At first we create instances of SPChangeToken class where specify change scope (List), id of specific list and start and end time for limiting search (lines 11-17). Then we create SPChangeQuery instance where specify that we want to get changes made for files in our list (line 19) and what kind of event types we want to track (lines 20-22). In our example we set it so only Add events should be returned, in order to return other event types specify true for Delete and Update properties. After that we pass start and end change tokens to appropriate properties of the query (lines 23-24), call SPList.GetChanges method and pass constructed SPChangeQuery object there. On lines 27-55 we iterate through returned results and create more convenient and simple collection of ItemChange objects which together with event time and change type also contain file name and url.

Note that there is also SPChangeQuery.FetchLimit property which by default is set to 1000. If your doclib may contain more changes for specific period, you need to add pagination logic to your code.

2 comments:

  1. How do you get the user how made the change?

    ReplyDelete
  2. Ofer, seems like SPChangeItem doesn't contain this information. What you can do is to check codebehind class of the Sharepoint page which is shown when you click version history for list item (on this page it shows changes together with the user which made the change) in reflector and see how it is done in Sharepoint

    ReplyDelete