Item Level Audience targeting in XSLTListViewWebPart

 

You can enable “Audience Targeting” in list level in SharePoint 2010, When you enable the Audience Targeting a filed called “Target Audience” is added to the list and you can populate this field with target audience for every item to show the items only to the specified audience. But the audience filtering doesn’t apply to XSLTListViewWebPart and only applies to “ContentByQueryWebpart”. That means, you cant expect the XSLTListViewWebPart to filter the items based on audience while you are viewing the items in the list view or through XSLTListViewWebPart in any web part page, This item level audience filtering works only when you use the “ContentByQueryWebpart” and configures it to apply audience filtering.

This behavior is because item level audience filtering is implemented through “CrossListQueryCache” and “CrossListQueryInfo” API and ContentByQueryWebpart uses them to query against the sites and lists, Hence able to apply the item level audience filtering in the ContentByQueryWebpart, But the XSLTListViewWebPart renders the item based on view (SPView) which fetches the item based on the “Query” (SPQuery) element of view. In Short, Item level audience filtering cannot be applied for XSLTListViewWebPart.

I have implemented the following work around to filter the list items based on audience in the XSLTListViewWebPart

1. Construct the CrossListQueryInfo and CrossListQueryCache to fetch the items from the list
2. The result set after executing the CrossListQueryInfo would be “DataTable” which cannot be fed to XSLTListViewWebPart directly, So need to loop through the “rows” in the datatable and get the “Target Audience” field value
3. Construct the CAML query on the fly based on the “Target Audience” field value in the result data table and apply the query to the current view using XMLDefinition property of XSLTListViewWebPart.
4. Implement the above steps in a hidden control/delegate/WebPart and it to the “AllItems.aspx” view page or to any other web part page which has the XSLTListViewWebPart.

Following is the sample hidden web part which implements the above said work around, Create the hidden web part and add it to the Web Part page which has the XSLTListViewWebPart :

It’s a hidden web part doesn’t carry any control and the code is implemented in the “OnLoad” event of the Web part :

 

 protected override void OnLoad(EventArgs e)
         {
             base.OnLoad(e);
             
             CrossListQueryInfo cqInfo = new CrossListQueryInfo();
  
             cqInfo.Lists = "<Lists><List ID=\"60C4944A-9E1C-4089-ADDF-A6EAD9274029\" /></Lists>"; // Hard coded GUID of the List
  
             cqInfo.AudienceFieldId = "Target_x0020_Audiences";
  
  
             cqInfo.ViewFields = "<FieldRef Name=\"Title\" /><FieldRef Name=\"Body\" /><FieldRef Name=\"Target_x0020_Audiences\" />";
  
             cqInfo.Webs = "<Webs Scope=\"Recursive\" />";
             cqInfo.Query = "<Where></Where>";
             cqInfo.RowLimit = 500;
             cqInfo.FilterByAudience = true;
             
             cqInfo.UseCache = true;
  
             CrossListQueryCache clqc = new CrossListQueryCache(cqInfo);
  
             DataTable dt = clqc.GetSiteData(SPContext.Current.Site, SPContext.Current.Web.Url); // Get the datatable after Audience filtering
  
             SPWeb web = SPContext.Current.Web;
  
             SPList oList = SPContext.Current.Web.Lists["Custom Announcements"];
  
  
             SPLimitedWebPartManager webPartManager = web.GetLimitedWebPartManager(web.Url + "/sitepages/Home.aspx", PersonalizationScope.Shared);
  
  
             oWP = this.WebPartManager.WebParts.OfType<Microsoft.SharePoint.WebPartPages.XsltListViewWebPart>().FirstOrDefault();
  
             SPQuery oQuery = new SPQuery();
  
  
             string query = BuildCAMLQuery(dt); // Build the Query for the current view to filter the items by getting the Target Audience values from Datatable
  
             XmlDocument viewXmlDoc = new XmlDocument();
             viewXmlDoc.LoadXml(oWP.XmlDefinition);
             XmlNode queryNode = viewXmlDoc.DocumentElement.SelectSingleNode("Query");
  
             queryNode.InnerXml = query;
  
  
             oWP.XmlDefinition = viewXmlDoc.OuterXml;
            
            
             this.Hidden = true;
  
         }

 

Following is the BuildCAMLQuery method which is used above in which i am building the CAML query based on the values of returned dataset from CrossListQueryCache

 

 public string BuildCAMLQuery(DataTable oDt)
         {
             StringBuilder sb = new StringBuilder();
  
  
             sb.Append("<Where>");
  
             sb.Append("<In>");
             sb.Append("<FieldRef Name='Target_x0020_Audiences'/>");
             sb.Append("<Values>");
             
             foreach (DataRow dr in oDt.Rows)
             {
  
                 sb.Append("<Value Type='TargetTo'>" + dr["Target_x0020_Audiences"].ToString() + "</Value>");
  
  
             }
  
  
             sb.Append("</Values>");
             sb.Append("</In>");
             sb.Append("</Where>");
         
             return sb.ToString();
  
         }    
  

 

Deploy this WebPart to the site and add the Hidden WebPart to the view page or to the web part page in which you have the XSLTListViewWebPart, I have a hardcoded List ID in the above sample, You can create a configurable web part property to provide the list id.

 

                                                        HAPPY CUSTOMIZING