SharePoint 2013: I’ll build you a custom navigation provider – applying audience visibility (part 2)

Hello everyone!

In my part 1 of this series I have covered most of the building blocks that will allow you to create a custom navigation provider for SharePoint. The part I omitted for brevity was the page in central administration that I created that allows me to apply audience visibility trimming on the terms in our navigation term set. Basically what it does is setting certain custom properties into term sets, and that’s it. The code that actually acts on them can be found here in line 616 – method called “TrimByAudienceOrExemptionNeeded”, which is applied to every node before adding it to a display collection. The way it works – if a node has child terms and is trimmed by audience for a particular user – the child nodes will be hidden as they will not even be processed. Makes sense.

This is what we’ll cover today

  • Where to place your page in the solution in order for it to be accessible in Central Administration
  • Providing accessible links to our page (optional) using SharePoint module
  • Page itself, markup and code-behind

So, without further ado.

File placing in your solution


Look at the picture above – basically you need to ensure that your page resides under TEMPLATE/ADMIN folder in SharePoint hive. Visual Studio provides several default mapped folders – it’s up to you to organize your hive files, I’m sure you have a way that works for you. The way I do it – I map the SharePointRoot folder and then create the structure underneath it, so basically I have a single mapped node with all the mapped content under it.

Adding a link to your page

We can make our lives easier by exposing our page through a link on a welcome page in Central Administration (default.aspx). To do so add an empty element to your solution and in the Elements.xml file paste the following

Note, that Custom in “_admin/Custom/NavigationAudienceManager.aspx” is a folder in my image earlier. If you place your file in TEMPLATE/ADMIN folder directly, then, of course, your Url will be “_admin/NavigationAudienceManager.aspx”, mkay?

Also, please create a Web-scoped feature, set  the it’s properties to “Activate On Default – False” and “Auto Activate In Central Admin – True” and add your module to it. After deployment the feature should be activated in your Central Administration and link should be visible.

Page code itself

Firstly let’s have a look at the markup. Nothing too fancy here.


Now, the code-behind. Please forgive the lack of comments, in my defense I do try to make method names reflect their purposes. Basically, what the code does is create a TreeView control that reflects the structure of taxonomy term set that we are using for navigation. It also displays two lists of checkboxes, each having a checkbox for each audience that you have defined in your farm. One checkbox list is called “Grant access to audiences” and the other “Deny access to audiences”. Important! Deny takes priority in my code, which means if you select a node in tree view, and then tick checkboxes for same “Audience 1” in both “Grant” and “Deny” lists and hit save – that audience will not see the said node. Hope this makes sense.

Also, underneath “Deny” checkbox list I have created a user picker control where we can select users that should not see the selected node. Sort of even more granular control, if you will.

So, there you have it. Combine this with the part 1 and you have yourself a workable template to create a thing of your own. Thank you for taking your time to read this through, and hope it was of use. This is how the page looks in my farm:


A note on performance

This code indeed is a resource hog in a way. In a few months after this implementation I decided to make this load asynchronously using same web control that SharePoint uses in its default master pages – Microsoft.SharePoint.WebControls.AspMenu – Watch this space, I will write a post on how I did that.

Edit: here is the post on improving performance, by loading the AspMenu control asynchronously

One comment

Leave a Reply

Your email address will not be published. Required fields are marked *