MOSS MVP

I've moved my blog to http://blog.falchionconsulting.com!. Please update your links. This blog is no longer in use--you can find all posts and comments at my new blog; I will no longer be posting to this site and comments have been disabled.

Wednesday, April 30, 2008

Programmatically Setting Web Part Audience Targeting

I've been doing some work on my gl-exportlistitem2 and gl-addlistitem commands so that I can support the import of web part pages.  I thought I was about done until I discovered that I had an issue with pages and web parts that were using audience targeting.  There was actually two issues - one was that when I imported a page to another farm the GUID used to store the audience didn't match up so it would lose its setting for the page.  The other issue was that some web parts (specifically anything that is not a V2 web part) do not export the AuthorizationFilter property which is where the audience settings are stored.  I find this very odd that they chose to omit this property when exported.  Note that for V2 web parts the audience information is exported because it is stored in the IsIncludedFilter property of the web part which has been marked as obsolete (internally this property just references the AuthorizationFilter property).

When I set out to do this I thought it would be pretty easy - just store the name with the audience ID and store the configuration information in a MetaData element that I have which I could then use to set the property during the import.  The problem that I ran into was the format of the AuthorizationFilter property - it's just not documented anywhere!  If you view the MSDN documentation for the property it says the following:

The Web Part infrastructure does not implement any default behavior for the AuthorizationFilter property. However, the property is provided so that you can assign an arbitrary string value to a custom Web Part. This property can be checked by SPWebPartManager during its AuthorizeWebPart event to determine whether the control can be added to the page.

The thing is - there's nothing arbitrary about this property - it has a very explicit format which if you don't follow will result in the web part failing to process the audience settings - the format of this matches the format of the Audience field of the web part page - if you mess that field up you will get an error when trying to get into the page settings.

So what is the format of the property?  First you need to understand that there are three types of audience information that the property is storing: Global Audiences created via the SSP; Distribution Lists; SharePoint Groups.  Each of these values is stored slightly differently and the order of their appearance is important.  Each item is delimited with two semi-colons: ";;".

The global audience is stored as a GUID and is the only type of item that can be stored without any delimiter information if no other items exist.  Multiple items are separated with a comma.

The distribution list is stored as an LDAP string.  Multiple items are separated with a new line character ("\n").

The SharePoint groups are stored as a named value (i.e., "Members", "Owners", etc.) and multiple items are separated with a comma.

So putting it all together you would construct a string containing one or more elements of each like so:

   1: string[] globalAudienceIDs = new string[] {"e4687e64-c9d8-4860-bbc3-ec036bf9915d"};
   2: string[] dlDistinguishedNames = new string[] {"cn=group1,cn=users,dc=spdev,dc=com", "cn=group2,cn=users,dc=spdev,dc=com"};
   3: string[] sharePointGroupNames = new string[] {"Demo Members", "Demo Owners"};
   4:  
   5: string result = string.Format("{0};;{1};;{2}",
   6:                               string.Join(",", globalAudienceIDs),
   7:                               string.Join("\n", dlDistinguishedNames),
   8:                               string.Join(",", sharePointGroupNames));

That being said - if you can avoid hard coding this formatting than you should.  So how do you avoid it - you use the GetAudienceIDsAsText method of the AudienceManager class.  To use this method you would do something like the following:

   1: string[] globalAudienceIDs = new string[] {"e4687e64-c9d8-4860-bbc3-ec036bf9915d"};
   2: string[] dlDistinguishedNames = new string[] {"cn=group1,cn=users,dc=spdev,dc=com", "cn=group2,cn=users,dc=spdev,dc=com"};
   3: string[] sharePointGroupNames = new string[] {"Demo Members", "Demo Owners"};
   4:  
   5: string result = AudienceManager.GetAudienceIDsAsText(globalAudienceIDs, dlDistinguishedNames, sharePointGroupNames);

What's cool is that there is a reciprocal method called GetAudienceIDsFromText which will give you the IDs based on the string.

In my particular case I wasn't able to use these and had to know the format of the string because I needed to supplement the GUIDs with the named value so that I could do an import in a different farm.

Note that this same format is used for the Audience field of a publishing page.

2 comments:

Jayesh Prajapati said...

How can I implement “Audience targeting” feature in Web Part , so that People or Group assign for that particular web part can only see it… rest of not allow to see it .
As its feature in MOSS 2007 but not available with WSS 3.0 .. I want to implement it in WSS 3.0 . do you have any code snippet for it?

Gary Lapointe said...

Jayesh - you basically do this the same way with WSS - just set the AuthorizationFilter property. Reza has a good example you can use: http://blogs.devhorizon.com/blogs/reza_on_blogging/archive/2007/03/08/456.aspx