Sunday, January 23, 2011

Setting Target Audiences with code

If you search the web you will find many articles explaining how to set audiences on web parts (also on list items). Most are curious - explaining that you need to specify the IDs of the audiences, separated by colons, and then four semi colons to finish it.

Really? four semi colons at the end without any explanation why? I just had to investigate.
It turns out that the four semi colons have a use. The syntax of the "target to" audience field type is as follows:
[Guid Ids separated by comma];;[Active directory groups' LDAP paths separated by line breaks];;[SharePoint security group names separated by commas]

For example:
decd0c08-4649-4e61-a8d6-8fdf5e4017ad,decd0c08-4649-4e61-a8d6-8fdf5e4017ad;;CN=SecGroup,CN=Users,DC=Development,DC=Local
CN=samplegroup1,CN=Users,DC=Development,DC=Local
;;Admin Office, Authors

So if you only have global (user profile) audiences, the value will be guids followed by four semi colons (because the values of the other type of audiences are blank). If you only choose security\distribution lists then you will have two semi colons before them, and two after. If you chose only sharepoint groups you will get 4 semi colons before the group names.

To make things simpler for me, I wrote a small class to create a value for me, or to parse it out for me. Here is the code:

public class AudienceFieldValue
    {
        /// <summary>
        /// A list of the IDs of the sharepoint global audiences (the one defined in the user profile database, accessible with  Microsoft.Office.Server.Audience.AudienceManager
        /// </summary>
        public List<Guid> GlobalAudienceIds;
        /// <summary>
        /// A list of sharepoint security groups
        /// </summary>
        public List<string> SharePointSecurityGroupNames;
        /// <summary>
        /// A list of active directory LDAP paths (CN=SecGroup,CN=Users,DC=Development,DC=Local) pointing to security groups or distribution lists
        /// </summary>
        public List<string> DirectoryGroupsOrDistListLDAPPaths;

        public AudienceFieldValue()
        {
            GlobalAudienceIds = new List<Guid>();
            SharePointSecurityGroupNames = new List<string>();
            DirectoryGroupsOrDistListLDAPPaths = new List<string>();
        }
        /// <summary>
        /// Use this constructor if you have a value from an existing item and you want to parse it. 
        /// You can even join values from more than one item seperated by semi colons. 
        /// For example: AudienceFieldValue val = new AudienceFieldValue(item1["Target Audiences"].toString() +;"+ item1["Target Audiences"].toString())
        /// </summary>
        /// <param name="value">The value of a "audience target to" column from a SPListItem (or more than one, seperated by semi colons)</param>
        public AudienceFieldValue(string value) 
        {
            GlobalAudienceIds = new List<Guid>();
            SharePointSecurityGroupNames = new List<string>();
            DirectoryGroupsOrDistListLDAPPaths = new List<string>();
            string[] arrTargets = value.Split(";".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            foreach (string audienceGroup in arrTargets)
            {
                if (audienceGroup.Contains("CN="))
                {
                    //it is one or more AD groups (CN) split by line breaks
                    string[] adgroups = audienceGroup.Split('\n');
                    foreach (string audienceCN in adgroups)
                    {
                        DirectoryGroupsOrDistListLDAPPaths.Add(audienceCN);
                    }
                }
                else
                {
                    string[] arrAudiences = audienceGroup.Split(',');
                    foreach (string audienceName in arrAudiences)
                    {
                        try
                        {
                            Guid g = new Guid(audienceName);
                            GlobalAudienceIds.Add(g);
                        }
                        catch (Exception ex)
                        {
                            //its not a guid - so it is a local sharepoint security group
                            SharePointSecurityGroupNames.Add(audienceName);
                        }
                    }
                }
            }
        }


        /// <summary>
        /// Get the value that you can set to a list item's target audience field
        /// </summary>
        /// <returns>A string value containing all the IDs specified in a format that sharepoint understands</returns>
        public override string ToString()
        {
            if (GlobalAudienceIds.Count == 0 && SharePointSecurityGroupNames.Count == 0 && DirectoryGroupsOrDistListLDAPPaths.Count == 0)
            {
                return "";
            }
            else
            {
                StringBuilder result = new StringBuilder();
                //first add any global audiences
                foreach (Guid id in GlobalAudienceIds)
                {
                    if (result.Length > 0)
                        result.Append(",");
                    result.Append(id.ToString());
                }
                //must add two semi colons to seperate even if there is nothing after
                result.Append(";;");
                //add any directory group path, seperated by a line break
                bool addedDirGroup = false;
                foreach (string directoryGroupPath in DirectoryGroupsOrDistListLDAPPaths)
                {
                    if (addedDirGroup)
                        result.Append("\n");
                    result.Append(directoryGroupPath);
                    addedDirGroup = true;
                }
                //must add two semi colons to seperate even if there is nothing after
                result.Append(";;");
                //add any sharepoint group names seperated by commas
                bool addedSPGroup = false;
                foreach (string spGroupName in SharePointSecurityGroupNames)
                {
                    if (addedSPGroup)
                        result.Append(",");
                    result.Append(spGroupName);
                    addedSPGroup = true;
                }

                return result.ToString();
            }
        }
    }

1 comment:

Sunday Exaggeration said...

Thanks for the post. I have been trying to work out why I get four semi colons for a while!