Wednesday, September 11, 2013

Getting Managed Metadata Term from AfterProperties

If you've ever worked with the Managed Metadata Service you'll know how very little documentation or community support there is for it at present. It took me a long time to figure out how to get the corresponding Term from the int value in the AfterProperties or BeforeProperties collection during an ItemUpdating or ItemAdding event. Hope this helps you.


private Term GetTermFromAfterProperties(SPItemEventProperties properties)
{
       TaxonomySession termSession = 
              new TaxonomySession(properties.ListItem.Web.Site);
       TermStore termStore = termSession.TermStores[0];
       Group group = 
              termStore.Groups.Cast<Group>().First(g => g.Name.Equals("GroupName"));
       TermSet termSet = 
              group.TermSets.Cast<TermSet>().First(t => t.Name.Equals("TermSetName"));
                          
       int value = (Int32)properties.AfterProperties["interalFieldName"];  
       // Yes it's an Int, but if you're saving from an office application
       // like MS Word it's a string number like "23"
       SPField field = properties.ListItem.Fields["fieldDisplayName"];
       TaxonomyFieldValue tfv = new TaxonomyFieldValue(value.ToString(), field);

       Guid termGuid = new Guid(tfv.TermGuid);

       Term term = termSet.GetTerm(termGuid);

       return term;
}

Wednesday, August 22, 2012

Updating Organization Profiles using Object Model

If you're updating properties on organization profiles in the 'User Profile Service Application', but your users don't have permissions to modify profiles, you will need to run with elevated privileges. Seems simple enough. Use the SPSecurity class to elevate and instantiate all new objects within the code block.
It's not that simple. You will most likely get an UnauthorizedAccessException 'Attempted to perform an unauthorized operation'. For some reason the OrganizationProfileManager uses the HttpContext class to access the UPSA. To resolve this issue, you need to run with elevated privileges as well as set the HttpContext.Current property to null then restore it after you committed the changes.

If you debug this code, you can see that the SPContext.Current.Site.RootWeb.CurrentUser is the System Account (aka the application pool account). But you have to go the extra step so the OrganizationProfileManager can't use the HttpContext.Current instance.

Remember to add your application pool account to the User Profile Service Application Administrators and give it Manage Profiles permission.
Central Administration > Application Management > Manage service applications > (highlight) User Profile Service Application > click Administrator in the ribbon.

ThreadAbortedException on People Search

A small, but irritating issue I've found with people search in SharePoint 2010 is the ThreadAbortedException. This exception will be thrown at irregular intervals, usually occurring after an iisreset or if the user is idle or has not accessed the site after a recycle. After the exception is thrown, consecutive searches will not have any issues.

In our environment, the issue was caused by our multi web front end farm with a 'Search Query and Site Settings Service' running on each server. The service is used to handle result set building on multiple servers. I can only assume that at some point during the query process, the exception is caused by simultaneous service access. I was able to prevent the exception from being thrown by stopping the service on all our web front end servers, but leaving one instance running on our central administration server. This is not an ideal solution as it will leave only one server building search result sets from the search index, but we don't have a large organisation so it's sufficient for us. Our central admin server is not used to serve web traffic, so logically it makes sense for it to run search crawls and the querying service.

You can stop the 'Search Query and Site Settings Service' in Central Administration in the 'System Settings' configuration category and 'Manage services on server' page. Be aware that this page only shows services running on the selected server.

Monday, April 30, 2012

Creating a back button on a SharePoint 2010 survey

The best way I've found to create a back button on a SharePoint 2010 survey is to use javascript (with JQuery) to add a html input button and add the onClick event function there.
Though users can easily click the back button on their browser, SharePoint will not let them click the 'Next' button as it will throw the following exception.

Save Conflict.
Your changes conflict with those made concurrently by another user. If you want your changes to be applied, click Back in your Web browser, refresh the page, and resubmit your changes.



My code below is in the EditForm.aspx file of the survey list. You can find and edit it using SharePoint designer.
The code works in the following steps:
  1. Adds the back button to the page
  2. When the button is clicked it sets the 'backClicked' cookie to 'yes' then triggers the 'Next' button. Triggering the 'Next' button causes the current questions to post back to the server and save the input.
  3. Everytime the page is loaded the code checks the 'backClicked' cookie. If it is set to 'yes' it will then set it to 'needRefresh' and will tell the browsers to go back twice "history.go(-2);".
  4. Now the browser is on the correct page of the survey the code checking the 'backClicked' cookie will see that it is set to 'needRefresh', set the cookie to 'no' then cause the browser to reload the page "location.reload();".
  5. It is important that the browser is refreshed on the same page. This resolves the Save Conflict issue mentioned above.

 I hope this helps someone out there. If you know of any alternative solutions, please post in the comments.