May 2, 2007

MOSS: How to hide UI elements according to user's Audience

Problem:
I need to hide different UI elements from the master page depending on the current user's audience. SPSecurityTrimmedControl apparently knows nothing about audiences so it cannot be used.

Solution:
Changing master pages on the fly is possible, as described here, but if you'd just want to hide some specific things without making whole lotta master pages this custom control might come handy.

Create Web Custom Control with VS 2005 and add this code:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using Microsoft.SharePoint;
using Microsoft.Office.Server.Audience;
using Microsoft.Office.Server;
using System.Collections;
 
namespace HamarData.WebControls
{
    [DefaultProperty("Text")]
    public class AudienceControl : SPSecurityTrimmedControl
    {
        private List<string> _audiences = new List<string>();
 
        [DefaultValue(""), Category("Behavior")]
        public string AudiencesString
        {
            get
            {
                return string.Join(",", _audiences.ToArray());
            }
            set
            {
                _audiences.AddRange(value.Split(new char[] { ',' }, System.StringSplitOptions.RemoveEmptyEntries));
            }
        }
 
        protected override void Render(HtmlTextWriter output)
        {
            if (!string.IsNullOrEmpty(AudiencesString) && CheckAudience())
            {
                base.Render(output);
            }
        }
 
        /// 
        /// Checks if the user belongs to an audience that is allowed to view the content.
        /// 
        /// True if user is allowed to see the content, otherwise false.
        private bool CheckAudience()
        {
            bool retVal = false;
 
            try
            {
                SPSite site = SPControl.GetContextSite(HttpContext.Current);
 
                ServerContext context = ServerContext.GetContext(site);
                AudienceManager AudMgr = new AudienceManager(context);
 
                SPWeb web = SPControl.GetContextWeb(HttpContext.Current);
 
                try
                {
                    ArrayList audienceIDNames = AudMgr.GetUserAudienceIDs(HttpContext.Current.User.Identity.Name, true, web);
 
                    for(int i = 0; i < audienceIDNames.Count; i++)
{
                        if(_audiences.Contains(((AudienceNameID)audienceIDNames[i]).AudienceName))
                        {
                            retVal = true;
                            break;
                        }
                    }
                }
                catch(AudienceException)
                {
                    //Your exception handling code here
                }
            }
            catch(Exception)
            {
            }
 
            return retVal;
        }
    }
}

Then register the custom control on your chosen master page:
<%@ Register TagPrefix="HamarData" Namespace="HamarData.WebControls" 
Assembly="AudienceControl, Version=1.0.0.0, Culture=neutral, PublicKeyToken=90342589787ab5be" %>

And finally just surround the control(s) you wish to control with the tags like below. This shows the search functionality only for users in the audience "External users":

<HamarData:AudienceControl AudiencesString="External users" runat="server">
    <asp:ContentPlaceHolder id="PlaceHolderSearchArea" runat="server">
        <SharePoint:DelegateControl runat="server" ControlId="SmallSearchInputBox"/>
    </asp:ContentPlaceHolder>
</HamarData:AudienceControl>

The custom control inherits from SPSecurityTrimmedControl so you could possibly (haven't tested) use some functionality of that control too. It's not necessary to inherit it from SPSecurityTrimmedControl, of course, you could just inherit from WebControl if you're only interested in the Audience functionality.

3 comments:

  1. Need help please. How can i make this work with mytple sp-groups instead of audiences.

    ReplyDelete
  2. If you want to target specific web parts, you can just use the Audience functionality of a web part. Otherwise you can use SPWeb.IsCurrentUserMemberOfGroup(int groupId), or SPGroup.ContainsCurrentUser. Current SPWeb's associated groups (Member, Visitor, Owner) you can get using SPWeb.AssociatedGroups, or SPWeb.AssociatedMember/Owner/VisitorGroup.

    ReplyDelete
  3. Thanks for this solution! It is a great addition to use with custom UI Elements. To answer the use with multiple SharePoint Groups instead of Audiences question, you can use this solution with some modifications to how you add it on a page to achieve this. SharePoint Groups can be used as an Audience without compiling an actual Audience in Central Admin. So with this solution all you have to do is set a Register Tagprefix for the solution on the page or MasterPage you need to use it on. Then for the Tag around your object, set it with your Tagprefix and a unique ID (unique ID if you want to use this feature more than once on a page). You can then set an AudienceString with multiple SharePoint Groups separated with a comma....like..... Group1,Group2,Group3,Group4. Works like a charm. I would actually post the code so it’s more obvious, but your blog won't allow code postings. I could try to post on my own blog with a reference to this post so it’s clearer, if you would like see what I mean. Just let me know.

    ReplyDelete