Migrating Audience Targeted Information

Slalom Consultant Maarten Sundman

Slalom Consultant Maarten Sundman specializes in .NET, SharePoint, and Silverlight solutions and has experience in the Financial Services, Software, and Utilities and Energy sectors.

Sometimes you’ll encounter a scenario where you need to move a site from one environment to another and the site is using Audiences. Now I’m personally a bit of a fan of Audiences for simple out of the box targeting of information. However, it has one pretty major flaw. Audiences are fundamentally environment specific. There is no out of the box method for remapping or moving audience targeted information and have it still work properly on the other side. This is due to a number of reasons which I’m not going to go in to in this blog post. However, here is a tool that can help with this.

This tool is pretty straight forward with only two command, import and export:

  • Export—Generates a file with a mapping of audiences to be used when updating the new environment.
  • Import—Based on your mapping file updates the content in the new environment to use the new environments audiences.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Office.Server;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Navigation;
using Microsoft.Office.Server.WebControls.FieldTypes;
using Microsoft.Office.Server.UserProfiles;
using Microsoft.Office.Server.Audience;
using System.IO;

namespace WithinSharePoint.MigrateAudiences
{
class Program
{
internal static List Audiences = null;
internal static Dictionary<string, Audience> RemappedAudiences = null;
static void Main(string[] args)
{
try
{
if (args.Count() == 2)
{
SPSite site = new SPSite(args[1]);
foreach (Audience a in GetAudiences(site))
{
Console.WriteLine(a.AudienceName + “,”+ a.AudienceID.ToString());
}
}
if (args.Count() == 3)
{
SPSite site = new SPSite(args[1]);
SPWeb RootWeb = site.OpenWeb();
Audiences = GetAudiences(site);
RemappedAudiences = AudienceMap(args[2]);
ScanWeb(RootWeb);
}
else if ((args.Count() < 2) | (args.Count() > 3))
{
WriteUsage();
}
}
catch(Exception ex)
{
Console.WriteLine(“ERROR:” + ex.Message);
WriteUsage();
}
}

internal static void WriteUsage()
{
Console.WriteLine(“Usage: WithinSharePoint.MigrateAudiences -EXPORT [URL TO RETRIEVE AUDIENCES] >> AudienceExport.csv”);
Console.WriteLine(“Usage: WithinSharePoint.MigrateAudiences -IMPORT [URL TO SCAN AND UPDATE] [FILEPATH]”);
Console.WriteLine(“File is a text document with this format (Audience ID is the ID of the audience in the SOURCE environment, not the destination):”);
Console.WriteLine(“AudienceName,AudienceID”);
}

internal static void ScanWeb(SPWeb web)
{
web.AllowUnsafeUpdates = true;
ScanLists(web.Lists);
try
{
ScanNavigation(web.Navigation.GlobalNodes);
ScanNavigation(web.Navigation.QuickLaunch);
}
catch (Exception ex)
{
Console.WriteLine(“Error updating navigation. ” + ex.Message);
Console.WriteLine(web.Url);
}
foreach (SPWeb child in web.Webs)
{
ScanWeb(child);
}
web.AllowUnsafeUpdates = false;
}

internal static void ScanLists(SPListCollection Lists)
{
foreach (SPList list in Lists)
{
if (list.Fields.ContainsField(“Target_x0020_Audiences”))
{
ScanItems(list.Items, “Target_x0020_Audiences”);
}
else if (list.Fields.ContainsField(“Audience”))
{
ScanItems(list.Items, “Audience”);
}
}
}

///

/// Scans and updates all audience targetted sharepoint navigation nodes with audiences from the new environment
///

///internal static void ScanNavigation(SPNavigationNodeCollection Nodes)
{
string value = “”;
string[] values;
bool pendingupdate = false;
Char[] splitter = new Char[] { ‘;’ };
SPNavigationNode node;
for (int i = 0; i < Nodes.Count; i++ )
{
node = Nodes[i];
string newvalue = “”;
if (node.Properties.Contains(“Audience”))
{
value = node.Properties[“Audience”].ToString();
value = value.Replace(‘,’, ‘;’);
values = value.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
foreach (string val in values)
{
if (RemappedAudiences.ContainsKey(val))
{
//update with new audiences
pendingupdate = true;
newvalue += RemappedAudiences[val].AudienceID + “,”;
}
else
{
//this is to preserve existing unknown audiences
newvalue += val + “,”;
}
}
if (pendingupdate)
{
node.Properties[“Audience”] = newvalue;
node.Update();
}
}
}
}

///

/// Scans all items in an audience targetted list and updates them with new environments audiences
///

//////internal static void ScanItems(SPListItemCollection items, string AudienceField)
{
Console.WriteLine(“Scanning and updating list ” + items.List.Title);
bool ListUpdate = false;
Char[] splitter = new Char[] { ‘;’ };
SPListItem item;
for(int i = 0; i < items.Count;i++)
{
try
{
item = items[i];
string value = “”;
if(item[AudienceField] != null)
{
if (!String.IsNullOrEmpty(item[AudienceField].ToString()))
{
bool PendingUpdate = false;
string NewValue = “”;
value = item[AudienceField].ToString();
if (value.Contains(“,”))
{
value = value.Replace(‘,’, ‘;’);
}
//Console.WriteLine(value);
string[] audiences = value.Split(splitter, StringSplitOptions.RemoveEmptyEntries);
foreach (string a in audiences)
{
//Console.WriteLine(a);
if (RemappedAudiences.ContainsKey(a))
{
//add remapped audience to update
PendingUpdate = true;
NewValue += RemappedAudiences[a].AudienceID + “,”;
}
else
{
//keep unknown audiences in the item
NewValue += a + “,”;
}
}
if (PendingUpdate)
{
//don’t ask why sharepoint uses csv for audience id’s and then appends ;;; at the end
item[AudienceField] = NewValue + “;;;;”;
ListUpdate = true;
item.UpdateOverwriteVersion();
}
}
}
}
catch(Exception ex)
{
Console.WriteLine(“Error reading line item:” + ex.Message);
Console.WriteLine(items[1][AudienceField].ToString());
Console.WriteLine(ex.StackTrace);
}
}
if (ListUpdate)
{
items.List.Update();
}
}

///

/// Reads the contents of the audience export file to generate a mapping of equivalent audiences in the target environment
///

//////
/// String – AudienceID of Source Environment
/// Audience – Audience in New/Target Environment
///
internal static Dictionary<string, Audience> AudienceMap(string FilePath)
{
Dictionary<string, Audience> map = new Dictionary<string, Audience>();
StreamReader reader = new StreamReader(FilePath);
string input = null;
while ((input = reader.ReadLine()) != null)
{
string[] line = input.Split(‘,’);
if(line.Count() == 2)
{
var match = from a in Audiences where a.AudienceName == line[0] select a;
foreach (Audience m in match)
{
map.Add(line[1], m);
}
}
}
return map;
}

///

/// Returns a list of all audiences from the target site collection
///

//////
internal static List GetAudiences(SPSite site)
{
List audiences = new List();
SPServiceContext context = SPServiceContext.GetContext(site);
AudienceManager aMan = new AudienceManager(context);
foreach (Audience a in aMan.Audiences)
{
audiences.Add(a);
}
return audiences;
}
}
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: