Why would a custom SharePoint timer job work on only half the items in a list?

75 Views Asked by At

We have a timer job that checks the SharePoint User Profile service for a users location and title, then updates the metadata for a page library of offices with the associated manager. We recently updated the logic, published and ran it in our QA environment and some pages do get updated, some don't. Roughly half are unchanged, despite having managers in the User Profile Service. Why would the same code to fail on half the pages?

The list has columns for Office, Manager, etc. The code cycles through each profile and if a user has the title "Manager" and the office "Seattle" in their profile, it searches the library and sets that user as the manager and publishes the page. All the pages are based on a common content type.

Tried clearing all the manager fields on all pages & half of them update. The users that fail do have user profiles and I can set the manager manually. What could cause it to fail on only some pages?

Here's the code. In the GetOfficeManagers method I loop through them twice, once to set Managers in Training, then to overwrite them with full managers if they exist (some only have managers in training). This is the change I made to the code.

//using statements snipped for brevity

namespace RC.SharePoint.Portal.TimerJobs
{
public class SyncOfficeLocationService: SPJobDefinition
{

    #region CONSTANTS

    public const string JOB_NAME = "World Office Location Synchronization Service";
    public const string TIMER_JOB_META_DATA = "TimerJobMetaData";
    private const string PAGES_LIBRARY = "Pages";
    private const string USER_PROFILE_FIELD_OFFICE = "Office";
    private const string USER_PROFILE_FIELD_TITLE = "Title";
    private const string USER_PROFILE_FIELD_DEPT = "Department";
    private const string USER_PROFILE_DEPT_REST_OP = "Office Operations";
    private const string Office_PROFILE_CONTENT_TYPE = "Office Profile";
    private const string Office_SITE_NAME = "rest";

    private struct Designations
    {
        public const string General_Manager = "General Manager";
        public const string General_Manager_In_Training = "General Manager in Training";
        public const string ManagingPartner = "Managing Partner";
        public const string ManagingPartner_In_Training = "Managing Partner in Training";
        public const string OperationsManager = "Operations Manager";
        public const string OperationsManager_In_Training = "Operations Manager in Training";
        public const string ShiftManager = "Shift Manager";
        public const string ShiftManager_In_Training = "Shift Manager in Training";
    }

    private struct Pages
    {
        public const string Title = "Title";
        public const string ContentType = "ContentType";
        public const string Name = "Name";
        public const string NameInt = "FileLeafRef";
        public const string GeneralManager = "General Manager";
        public const string GeneralManagerInt = "RC_RestProfile_GeneralManager";
        public const string ManagingPartner = "Managing Partner";
        public const string ManagingPartnerInt = "RC_RestProfile_ManagingPartner";
        public const string OperationsManager = "Operations Manager";
        public const string OperationsManagerInt = "RC_RestProfile_OperationsManager";
        public const string ShiftManager1 = "Shift Manager 1";
        public const string ShiftManager1Int = "RC_RestProfile_ShiftManager1";
        public const string ShiftManager2 = "Shift Manager 2";
        public const string ShiftManager2Int = "RC_RestProfile_ShiftManager2";
        //snipped for space
    }

    #endregion


    #region CONSTRUCTORS
    public SyncOfficeLocationService()
        : base()
    {
    }

    public SyncOfficeLocationService(string jobName, SPService service, SPServer server, SPJobLockType targetType)
        : base(jobName, service, server, targetType)
    {
    }

    public SyncOfficeLocationService(string jobName, SPWebApplication webApplication)
        : base(jobName, webApplication, null, SPJobLockType.ContentDatabase)
    {
        this.Title = jobName;
    }

    #endregion


    #region METHODS

    protected override bool HasAdditionalUpdateAccess()
    {
        return true;
    }

    public override void Execute(Guid targetInstanceId)
    {
        try
        {
            //Read settings from Hierarchical object store
            TimerJobMetaData settings = this.WebApplication.GetChild<TimerJobMetaData>(TIMER_JOB_META_DATA);

            using (SPSite site = new SPSite(settings.SiteUrl))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, string.Format("Timer Service started for SharePoint portal: {0}", web.Url), "");

                    List<OfficeLocation> Offices = GetOfficeManagers(site);
                    SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, "User profile service parsed successfully. " + Offices.Count.ToString() + " Offices found.", "");
                    SyncOfficeManagers(web.Webs[Office_SITE_NAME], Offices);

                    SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, string.Format("Timer Service finished for SharePoint portal: {0}", web.Url), "");
                }
            }
        }
        catch (Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
    }

    private Dictionary<string, string> GetUserProfiles(SPSite site)
    {
        Dictionary<string, string> users = new Dictionary<string, string>();
        try
        {
            SPServiceContext serverContext = SPServiceContext.GetContext(site);
            UserProfileManager profileManager = new UserProfileManager(serverContext);
            IEnumerator userProfiles = profileManager.GetEnumerator();
            while (userProfiles.MoveNext())
            {
                UserProfile userProfile = (UserProfile)userProfiles.Current;
                if (userProfile[USER_PROFILE_FIELD_TITLE] != null && userProfile[USER_PROFILE_FIELD_TITLE].Value != null && userProfile[USER_PROFILE_FIELD_TITLE].Value.ToString().Equals(Designations.General_Manager))
                {
                    if (userProfile[USER_PROFILE_FIELD_OFFICE] != null && userProfile[USER_PROFILE_FIELD_OFFICE].Value != null)
                    {
                        string key = string.Format("{0}.aspx", userProfile[USER_PROFILE_FIELD_OFFICE].Value.ToString().Replace("RC ", "C"));
                        if (!users.ContainsKey(key))
                            users.Add(key, userProfile.AccountName);
                    }
                }
            }
        }
        catch(Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
        return users;
    }

    private void SyncOffices(SPWeb web, Dictionary<string, string> users)
    {
        try
        {
            SPDocumentLibrary pagesLib = web.Lists[PAGES_LIBRARY] as SPDocumentLibrary;
            SPClaimProviderManager cpm = SPClaimProviderManager.Local;
            SPWeb rootWeb = web.Site.RootWeb;

            var query = new SPQuery();
            query.Query = string.Format(@"<Where><Eq><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Eq></Where>", Pages.ContentType, Office_PROFILE_CONTENT_TYPE);
            query.ViewFields = string.Format(@"<FieldRef Name=""{0}"" /><FieldRef Name=""{1}"" /><FieldRef Name=""{2}"" /><FieldRef Name=""{3}"" />", Pages.ContentType, Pages.Title, Pages.NameInt, Pages.GeneralManagerInt);
            query.ViewAttributes = @"Scope=""Recursive""";
            query.RowLimit = 0;

            SPListItemCollection items = pagesLib.GetItems(query);
            foreach (SPListItem item in items)
            {
                string fileName = item[Pages.Name].ToString();
                if (users.ContainsKey(fileName))
                {
                    string mgr = string.Empty;
                    if (item[Pages.GeneralManager] != null)
                    {
                        mgr = new SPFieldUserValue(web, item[Pages.GeneralManager].ToString()).User.LoginName;
                    }

                    if (!mgr.EndsWith(users[fileName]))
                    {
                        SPFile file = item.File;
                        if (file.CheckOutType == SPFile.SPCheckOutType.None)
                            file.CheckOut();

                        SPClaim userClaim = cpm.ConvertIdentifierToClaim(users[fileName], SPIdentifierTypes.WindowsSamAccountName);
                        SPUser newMgr = rootWeb.EnsureUser(userClaim.ToEncodedString());
                        item[Pages.GeneralManager] = new SPFieldUserValue(web, newMgr.ID, newMgr.Name);
                        item.Update();
                        file.CheckIn("Automatically checked-in by SharePoint Synchronization Timer Job");
                        file.Publish("Automatically published by SharePoint Synchronization Timer Job");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
    }


    private List<OfficeLocation> GetOfficeManagers(SPSite site)
    {
        List<OfficeLocation> Offices = new List<OfficeLocation>();
        try
        {
            SPServiceContext serverContext = SPServiceContext.GetContext(site);
            UserProfileManager profileManager = new UserProfileManager(serverContext);
            IEnumerator userProfiles = profileManager.GetEnumerator();
            while (userProfiles.MoveNext())
            {
                UserProfile userProfile = (UserProfile)userProfiles.Current;
                //Check for department name, it must be "Office Operations"
                if (userProfile[USER_PROFILE_FIELD_DEPT] != null && userProfile[USER_PROFILE_FIELD_DEPT].Value != null && userProfile[USER_PROFILE_FIELD_DEPT].Value.ToString().Equals(USER_PROFILE_DEPT_REST_OP))
                {
                    //Check for Office location, it must not be null or empty
                    if (userProfile[USER_PROFILE_FIELD_OFFICE] != null && userProfile[USER_PROFILE_FIELD_OFFICE].Value != null)
                    {
                        string location = userProfile[USER_PROFILE_FIELD_OFFICE].Value.ToString();
                        OfficeLocation Office = FindOffice(Offices, location);
                        if (Office == null)
                        {
                            Office = new OfficeLocation();
                            Office.Location = location;
                            Office.PageName = string.Format("{0}.aspx", location.Replace("RC ", "C"));
                            Offices.Add(Office);
                        }

                        if (userProfile[USER_PROFILE_FIELD_TITLE] != null && userProfile[USER_PROFILE_FIELD_TITLE].Value != null)
                        {
                            string designation = userProfile[USER_PROFILE_FIELD_TITLE].Value.ToString();
                            switch(designation)
                            {
                                case Designations.General_Manager_In_Training:
                                    Office.GeneralManager = userProfile.AccountName.ToLower();
                                    break;
                                case Designations.ManagingPartner_In_Training:
                                    Office.ManagingPartner = userProfile.AccountName.ToLower();
                                    break;
                                case Designations.OperationsManager_In_Training:
                                    Office.OperationsManager = userProfile.AccountName.ToLower();
                                    break;
                                case Designations.ShiftManager:
                                    Office.ShiftManagers.Add(userProfile.AccountName.ToLower());
                                    break;
                            }
                        }
                    }
                }
            }


            IEnumerator userProfiles2 = profileManager.GetEnumerator();
            while (userProfiles2.MoveNext())
            {
                UserProfile userProfile = (UserProfile)userProfiles2.Current;
                //Check for department name, it must be "Office Operations"
                if (userProfile[USER_PROFILE_FIELD_DEPT] != null && userProfile[USER_PROFILE_FIELD_DEPT].Value != null && userProfile[USER_PROFILE_FIELD_DEPT].Value.ToString().Equals(USER_PROFILE_DEPT_REST_OP))
                {
                    //Check for Office location, it must not be null or empty
                    if (userProfile[USER_PROFILE_FIELD_OFFICE] != null && userProfile[USER_PROFILE_FIELD_OFFICE].Value != null)
                    {
                        string location = userProfile[USER_PROFILE_FIELD_OFFICE].Value.ToString();
                        OfficeLocation Office = FindOffice(Offices, location);
                        if (Office == null)
                        {
                            Office = new OfficeLocation();
                            Office.Location = location;
                            Office.PageName = string.Format("{0}.aspx", location.Replace("RC ", "C"));
                            Offices.Add(Office);
                        }

                        if (userProfile[USER_PROFILE_FIELD_TITLE] != null && userProfile[USER_PROFILE_FIELD_TITLE].Value != null)
                        {
                            string designation = userProfile[USER_PROFILE_FIELD_TITLE].Value.ToString();
                            switch (designation)
                            {
                                case Designations.General_Manager:
                                    Office.GeneralManager = userProfile.AccountName.ToLower();
                                    break;
                                case Designations.ManagingPartner:
                                    Office.ManagingPartner = userProfile.AccountName.ToLower();
                                    break;
                                case Designations.OperationsManager:
                                    Office.OperationsManager = userProfile.AccountName.ToLower();
                                    break;
                                case Designations.ShiftManager_In_Training:
                                    Office.ShiftManagers.Add(userProfile.AccountName.ToLower());
                                    break;
                            }
                        }
                    }
                }
            }
        }
        catch (Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
        return Offices;
    }

    private void SyncOfficeManagers(SPWeb web, List<OfficeLocation> Offices)
    {
        try
        {
            SPDocumentLibrary pagesLib = web.Lists[PAGES_LIBRARY] as SPDocumentLibrary;
            SPClaimProviderManager cpm = SPClaimProviderManager.Local;
            SPWeb rootWeb = web.Site.RootWeb;
            SPClaim userClaim = null;
            SPUser newMgr = null;
            var query = new SPQuery();
            query.Query = string.Format(@"<Where><Eq><FieldRef Name=""{0}"" /><Value Type=""Text"">{1}</Value></Eq></Where>", Pages.ContentType, Office_PROFILE_CONTENT_TYPE);
            //query.ViewFields = string.Format(@"<FieldRef Name=""{0}"" /><FieldRef Name=""{1}"" /><FieldRef Name=""{2}"" /><FieldRef Name=""{3}"" />", Pages.ContentType, Pages.Title, Pages.NameInt, Pages.GeneralManagerInt);
            query.ViewAttributes = @"Scope=""Recursive""";
            query.RowLimit = 0;

            SPListItemCollection items = pagesLib.GetItems(query);
            foreach (SPListItem item in items)
            {
                string pageName = item[Pages.Name].ToString();
                OfficeLocation Office = FindOfficeByPageName(Offices, pageName);
                if (Office != null)
                {
                    bool updateItem = false;
                    string mgr = string.Empty;


                    #region General Manager
                    if (item[Pages.GeneralManager] != null)
                    {
                        mgr = new SPFieldUserValue(web, item[Pages.GeneralManager].ToString()).User.LoginName;
                    }

                    if (string.IsNullOrEmpty(Office.GeneralManager) && !string.IsNullOrEmpty(mgr))
                    {
                        item[Pages.GeneralManager] = null;
                        updateItem = true;
                    }
                    else if (!mgr.ToLower().EndsWith(Office.GeneralManager))
                    {
                        userClaim = cpm.ConvertIdentifierToClaim(Office.GeneralManager, SPIdentifierTypes.WindowsSamAccountName);
                        newMgr = rootWeb.EnsureUser(userClaim.ToEncodedString());
                        item[Pages.GeneralManager] = new SPFieldUserValue(web, newMgr.ID, newMgr.Name);
                        updateItem = true;
                    }
                    #endregion

                    #region Managing Partner
                    mgr = string.Empty;
                    if (item[Pages.ManagingPartner] != null)
                    {
                        mgr = new SPFieldUserValue(web, item[Pages.ManagingPartner].ToString()).User.LoginName;
                    }

                    if (string.IsNullOrEmpty(Office.ManagingPartner) && !string.IsNullOrEmpty(mgr))
                    {
                        item[Pages.ManagingPartner] = null;
                        updateItem = true;
                    }
                    else if (!mgr.ToLower().EndsWith(Office.ManagingPartner))
                    {
                        userClaim = cpm.ConvertIdentifierToClaim(Office.ManagingPartner, SPIdentifierTypes.WindowsSamAccountName);
                        newMgr = rootWeb.EnsureUser(userClaim.ToEncodedString());
                        item[Pages.ManagingPartner] = new SPFieldUserValue(web, newMgr.ID, newMgr.Name);
                        updateItem = true;
                    }
                    #endregion

                    #region Operations Manager
                    mgr = string.Empty;
                    if (item[Pages.OperationsManager] != null)
                    {
                        mgr = new SPFieldUserValue(web, item[Pages.OperationsManager].ToString()).User.LoginName;
                    }

                    if (string.IsNullOrEmpty(Office.OperationsManager) && !string.IsNullOrEmpty(mgr))
                    {
                        item[Pages.OperationsManager] = null;
                        updateItem = true;
                    }
                    else if (!mgr.ToLower().EndsWith(Office.OperationsManager))
                    {
                        userClaim = cpm.ConvertIdentifierToClaim(Office.OperationsManager, SPIdentifierTypes.WindowsSamAccountName);
                        newMgr = rootWeb.EnsureUser(userClaim.ToEncodedString());
                        item[Pages.OperationsManager] = new SPFieldUserValue(web, newMgr.ID, newMgr.Name);
                        updateItem = true;
                    }
                    #endregion

                    #region Shift Managers
                    for (int count = 0; count < 6; count++)
                    {
                        string shiftMgr = string.Empty;
                        if (Office.ShiftManagers.Count > count)
                            shiftMgr = Office.ShiftManagers[count];
                        string shiftMgrFieldName = GetShiftManagerFieldName(count + 1);
                        if (!string.IsNullOrEmpty(shiftMgrFieldName))
                        {
                            mgr = string.Empty;
                            if (item[shiftMgrFieldName] != null)
                            {
                                mgr = new SPFieldUserValue(web, item[shiftMgrFieldName].ToString()).User.LoginName;
                            }

                            if (string.IsNullOrEmpty(shiftMgr) && !string.IsNullOrEmpty(mgr))
                            {
                                item[shiftMgrFieldName] = null;
                                updateItem = true;
                            }
                            else if (!mgr.ToLower().EndsWith(shiftMgr))
                            {
                                userClaim = cpm.ConvertIdentifierToClaim(shiftMgr, SPIdentifierTypes.WindowsSamAccountName);
                                newMgr = rootWeb.EnsureUser(userClaim.ToEncodedString());
                                item[shiftMgrFieldName] = new SPFieldUserValue(web, newMgr.ID, newMgr.Name);
                                updateItem = true;
                            }
                        }
                    }
                    #endregion

                    if (updateItem)
                    {
                        SPFile file = item.File;
                        if (file.CheckOutType == SPFile.SPCheckOutType.None)
                            file.CheckOut();

                        item.Update();
                        file.CheckIn("Automatically checked-in by SharePoint Synchronization Timer Job");
                        file.Publish("Automatically published by SharePoint Synchronization Timer Job");
                        SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Medium, EventSeverity.Information), TraceSeverity.Medium, string.Format("Page {0} updated.", pageName), "");
                    }
                }
            }
        }
        catch (Exception ex)
        {
            SPDiagnosticsService.Local.WriteTrace(1, new SPDiagnosticsCategory("SharePoint Synchronization Timer Job", TraceSeverity.Unexpected, EventSeverity.Error), TraceSeverity.Unexpected, ex.Message, ex.StackTrace);
        }
    }

    private string GetShiftManagerFieldName(int count)
    {
        switch(count)
        {
            case 1:
                return Pages.ShiftManager1;
            case 2:
                return Pages.ShiftManager2;
            //snipped for brevity - goes to 6
        }

        return string.Empty;
    }

    private static OfficeLocation FindOffice(List<OfficeLocation> Offices, string location)
    {
        OfficeLocation Office = Offices.Find(
                              delegate(OfficeLocation r)
                              {
                                  return r.Location.Equals(location);
                              }
                          );

        return Office;
    }

    private static OfficeLocation FindOfficeByPageName(List<OfficeLocation> Offices, string pageName)
    {
        OfficeLocation Office = Offices.Find(
                              delegate(OfficeLocation r)
                              {
                                  return r.PageName.Equals(pageName);
                              }
                          );

        //Handle pages with name "C01.aspx"
        if (Office == null)
        {
            if (pageName.IndexOf("0") != 1)
            {
                pageName = pageName.Insert(1, "0");
                Office = Offices.Find(
                              delegate(OfficeLocation r)
                              {
                                  return r.PageName.Equals(pageName);
                              }
                          );
            }
        }


        //Handle pages with name "C1.aspx"
        if (Office == null)
        {
            if (pageName.IndexOf("0") != 2)
            {
                pageName = pageName.Insert(1, "0");
                Office = Offices.Find(
                              delegate(OfficeLocation r)
                              {
                                  return r.PageName.Equals(pageName);
                              }
                          );
            }
        }

        return Office;
    }

    #endregion

}

public class OfficeLocation
{
    public OfficeLocation()
    {
        Location = string.Empty;
        PageName = string.Empty;
        GeneralManager = string.Empty;
        ManagingPartner = string.Empty;
        OperationsManager = string.Empty;
        ShiftManagers = new StringCollection();
    }
    public string Location { get; set; }
    public string PageName { get; set; }
    public string GeneralManager { get; set; }
    public string ManagingPartner { get; set; }
    public string OperationsManager { get; set; }
    public StringCollection ShiftManagers { get; set; }
}

public class TimerJobMetaData : SPPersistedObject
{

    [Persisted]
    public string SiteUrl;

    public TimerJobMetaData() { }
    public TimerJobMetaData(string name, SPPersistedObject parent, Guid Id)
        : base(name, parent, Id)
    { }
}
}
0

There are 0 best solutions below