Wednesday, November 16, 2011

Tips to change SharePoint 2010 behavior without change out of box UI - Part I tag mapping


Write customer webpart and application pages to change SharePoint out of box behaviors are very common. However, these changes will ask users to use the customized UI (webparts or application pages) instead of out of box UI. There are some cases users want to change some SharePoint behavior globally without changing SharePoint UI. One example is for our SharePoint 2010 extranet implementation, security team asked us to restrict people picker to display users ONLY belongs to the site collection instead of whole farm for external users login from form based authentication. However, the same people picker needs to display all users in the whole farm for internal users login from Kerberos authentication. This requirement drives us to override SharePoint People Picker logic using tag mapping design. 


The tag mapping functionality is a mechanism to instruct the parser to substitute a different derived type implementation whenever it encounters the type being mapped. It was originally invented as part of the WebPart framework so as to allow the ASP.NET WebPartManager to be mapped to the derived Sharepoint WebPartManager implementation without having to change individual pages. However, it is quite powerful and generally applicable.


Here are major steps how to implement this without changing SharePoint UI.
1.    Identify the control out of box used for People Picker using browser tools to view source
2.    Create a new class deriving Microsoft.SharePoint.WebControls.PeopleEditor identified in #1
3.    Overwrite the functions inside class #2 to display only people inside the site collection for external users
4.    Sign the assembly with a Strong Name and install assembly into the GAC using feature
5.    Configure tag mapping entry in the Web.Config for the targeted webapp

The code for #3 is like this:

public class QCPeopleEditor : Microsoft.SharePoint.WebControls.PeopleEditor
{
        protected override void OnLoad(System.EventArgs e)
        {
            base.OnLoad(e);

            // Determine which claims authentication type was used to log in
            SPClaimProviderManager mgr = SPClaimProviderManager.Local;
            if (mgr != null)
            {
                SPClaim userLogonNameClaim = mgr.DecodeClaim(SPContext.Current.Web.CurrentUser.LoginName);
                SPOriginalIssuerType issuerType = SPOriginalIssuers.GetIssuerType(userLogonNameClaim.OriginalIssuer);

                // If user used FBA then switch people picker to only show users already in the site
                if (issuerType == SPOriginalIssuerType.Forms)
                {
                    this.PrincipalSource = Microsoft.SharePoint.Utilities.SPPrincipalSource.UserInfoList;
                }
            }
        }
}

The configuration for #5 is like this:
<add tagType="Microsoft.SharePoint.WebControls.PeopleEditor" mappedTagType="qualcomm.com.sp.peoplepicker.QCPeopleEditor" />

This sounds very simple for certain circumstances. We have other people to use same design to modify people picker and use feature to update the web.config. This has been also used to change other UI as well. The most common user control we may modify using tag mapping design are as follows.
·         Assert Picker
·         People Picker
·         Time Picker
·         List Picker

However, sometime, it will become extremely difficult if you could not identify the out of box control used by SharePoint or the class you need to overwrite is sealed. One example is our users want to allow SharePoint 2010 BCS List Filter Web Part returns 500 items instead of only first 200 items. We have seen such requests from other people also but do not seen any good solution besides adding filters. Here is the difficulties as you might encounter if you try to overwrite.


There are several classes you may identify that need to be modified. Two of them are:
Class Microsoft.SharePoint.Portal.WebControls.SpListFilterValuesPickerUI function protected override void PopulateListItems()
Class Microsoft.SharePoint.WebControls.EntityEditorWithPicker function protected override int IssueQuery(string searchString, string filterName, int pageIndex, int pageSize)
SpListFilterValuesPickerUI is a sealed class and it will invoke other functions that are also sealed that would be very difficult to change them all. EntityEditorWithPicker will aslo call some utility class that are sealed and it is difficult to get the required dll or reference to compile the overwritten classes. Here are two examples of sealed class or functions.
internal sealed class SpListFilterValuesPickerUI : ListFilterValuesPickerUIBase<SpListFilterValuesPickerContext>
BdcClientUtil.GetEntity(BdcClientUtil.MetadataCatalog, pickerDialog.EntityNamespace, pickerDialog.EntityName);

If you try to use third party tool such as Lightning BCS metaman, designer, inforpath to retrieve external BCS items, you will always =get the first 200 items since they will internally call SharePoint default API.


As a result, change SharePoint 2010 behavior without change out of box UI using tag mapping is very useful but it may not be possible for all circumstances.

No comments:

Post a Comment