Saturday, March 14, 2015

Create managed properties and map to crawl properties programmatically using a feature

This is the second part of the article series, regarding explicitly creating crawl properties and later map in to managed properties.

In this article I will show how to create managed properties and map to explicitly created crawl properties using a custom feature.

1. Create classes for managed property and crawl property collections

  1. public class CrawlPropertyInfo
  2. {
  3.     public string Category { get; set; }
  4.     public string Name { get; set; }
  5.     public ManagedDataType Type { get; set; }
  6. }
  7.  
  8. public class ManagedPropertyInfo
  9. {
  10.     public string ManagedPropertyName { get; set; }
  11.     public ManagedDataType Type { get; set; }
  12.     public string Description { get; set; }
  13.     public List<CrawlPropertyInfo> CrawledProperties { get; set; }
  14. }

2. Create method to map crawl properties to managed properties

  1. public static void SetManagedPropMappings(List<ManagedPropertyInfo> managedPropertyList)
  2. {
  3. try
  4. {
  5.     SPServiceContext serviceContext =
  6.         SPServiceContext.GetContext
  7.         (SPServiceApplicationProxyGroup.Default, SPSiteSubscriptionIdentifier.Default);
  8.  
  9.     var searchProxy =  serviceContext.GetDefaultProxy(typeof(SearchServiceApplicationProxy))
  10.         as SearchServiceApplicationProxy;    
  11.  
  12.     SearchServiceApplicationInfo info = searchProxy.GetSearchServiceApplicationInfo();
  13.  
  14.     SearchServiceApplication application = SearchService.Service.SearchApplications.
  15.     GetValue<SearchServiceApplication>(info.SearchServiceApplicationId);
  16.  
  17.     SearchObjectOwner searchOwner = new SearchObjectOwner(SearchObjectLevel.Ssa);
  18.     Schema schema = new Schema(application);
  19.  
  20.     ManagedPropertyCollection properties = schema.AllManagedProperties;
  21.  
  22.     foreach (ManagedPropertyInfo managedPropertyInfo in managedPropertyList)
  23.     {
  24.         var prop = from pr in schema.AllManagedProperties
  25.                     where pr.Name == managedPropertyInfo.ManagedPropertyName
  26.                     select pr;
  27.  
  28.         ManagedProperty currentProperty = null;
  29.         //create if managed property is null
  30.         if (null == prop || prop.Count() == 0)
  31.         {
  32.             currentProperty = properties.Create(managedPropertyInfo.ManagedPropertyName, managedPropertyInfo.Type);
  33.         }
  34.  
  35.         foreach (CrawlPropertyInfo crawledProperty in managedPropertyInfo.CrawledProperties)
  36.         {
  37.             List<CrawledPropertyInfo> crawledProperties = application.GetAllCrawledProperties(crawledProperty.Name, crawledProperty.Category, 0, searchOwner);
  38.  
  39.             if (prop != null || prop.Count() > 0)
  40.             {
  41.                 currentProperty = prop.First();
  42.                 CrawledPropertyInfo ci = crawledProperties[0];
  43.                 MappingCollection mpc = currentProperty.GetMappings();
  44.  
  45.                 int i;
  46.                 for (i = mpc.Count - 1; i >= 0; i--)
  47.                 {
  48.                     mpc.RemoveAt(i);
  49.                 }
  50.                 currentProperty.Update();
  51.  
  52.                 Mapping map = new Mapping();
  53.                 map.CrawledPropertyName = ci.Name;
  54.                 map.CrawledPropset = ci.Propset;
  55.                 map.ManagedPid = currentProperty.PID;
  56.                 mpc.Add(map);
  57.                 currentProperty.SetMappings(mpc);
  58.                 currentProperty.Update();
  59.             }
  60.         }
  61.     }
  62. }
  63. catch (Exception ex)
  64. {
  65.     //handle error
  66. }
  67. }

3. From the feature activated in feature receiver, call above method with managed properties

  1. public override void FeatureActivated(SPFeatureReceiverProperties properties)
  2. {
  3.     SPSite site = properties.Feature.Parent as SPSite;
  4.     if (null != site)
  5.     {
  6.         List<ManagedPropertyInfo> managedPropertyList = new List<ManagedPropertyInfo>();
  7.         ManagedPropertyInfo testProperty = new ManagedPropertyInfo
  8.         {
  9.             ManagedPropertyName = "TestManagedProperty",
  10.             Type = ManagedDataType.Text,
  11.             CrawledProperties = new List<CrawlPropertyInfo> {
  12.                     new CrawlPropertyInfo{
  13.                         Name = "ows_TestCrawlProperty",
  14.                         Category = "SharePoint",
  15.                         Type = ManagedDataType.Text
  16.                     }
  17.             }
  18.         };
  19.  
  20.         managedPropertyList.Add(testProperty);
  21.         SetManagedPropMappings(managedPropertyList);
  22.     }
  23. }

4. After activating the feature you can see a managed property is created and mapped to a crawl property

image

Wednesday, March 4, 2015

SharePoint 2013 – Create custom Crawl Properties using PowerShell

Sometimes we need to create, custom site columns and some search related logic which requires above columns as managed properties within the same SharePoint solution (WSP). But as we all aware, following steps need to be done to map site columns to managed properties.
image
How can we do this without full crawl ?

As a solution, I create crawl properties using PowerShell prior to the solution deployment. Using the SharePoint solution I create managed properties and map them to crawl properties. Then after sometime, we can run full crawl to finish the process.

I split the article in to two section, to make it clear.
In this post I’ll discuss about creating Crawl Properties using PowerShell. Following are the steps used to create crawl properties

1. Get value for property set parameter from existing category. In my case I added the property to SharePoint category
  1. $searchapp = Get-SPEnterpriseSearchServiceApplication
  2. $cat = Get-SPEnterpriseSearchMetadataCategory -SearchApplication $searchapp -Identity SharePoint
  3. Get-SPEnterpriseSearchMetadataCrawledProperty -SearchApplication $searchapp -Category $cat -Limit 1

I got “00130329-0000-0130-c000-000000131346” as the result

2. Determine Crawl Property names
If your site column is ClientName, then the Crawl Property name will be ows_ClientName

3. Create Crawl Property using PowerShell
  1. New-SPEnterpriseSearchMetadataCrawledProperty -Category SharePoint -IsNameEnum $false -Name "ows_CustomClientName" -PropSet "00130329-0000-0130-c000-000000131346" -SearchApplication $searchapp -VariantType 72
  2.  
  3. New-SPEnterpriseSearchMetadataCrawledProperty -Category SharePoint -IsNameEnum $false -Name "ows_CustomProperty" -PropSet "00130329-0000-0130-c000-000000131346" -SearchApplication $searchapp -VariantType 72
  4.  
  5. New-SPEnterpriseSearchMetadataCrawledProperty -Category SharePoint -IsNameEnum $false -Name "ows_CustomCountry" -PropSet "00130329-0000-0130-c000-000000131346" -SearchApplication $searchapp -VariantType 72

4. That will create Crawl Properties in Search schema
image

Tuesday, February 17, 2015

Resolve error “The base type <Page> is not allowed for this page. The type <Type> could not be found or it is not registered as safe” when deploying application pages with code behind using a module to SharePoint

When we deploy application pages to SharePoint, sometimes we need to deploy them to libraries or root instead of “Layouts” folder and may be with some code behind. By default SharePoint will issue above error since it violates its derived Code Access Security principles.

image 

In this case we need to explicitly add the safe control entry to web.config file. There can be following concerns.

  • What if there are multiple modules ?
  • What if we need to fully automate the deployment process without anyone manually touching config files ?

Luckily, there is a solution provided by Visual Studio itself. We can add a safe control entry to module by following the steps given below.

1. Right click your module and click Properties

image 

2. Select Safe Control Entries and Expand to add one

image

3. Add new entry and fill content accordingly

image

4. Deploy the package again

Now the page renders as expected.

image

Sunday, February 15, 2015

Presentation–Enhance user experience for Search using display templates

Recently I did a presentation on “Search Display Templates” at Sri Lanka SharePoint forum. In that session I discussed about display templates in general and different customization options.

If you need more information on Display Templates, you can refer these posts I have written so far.Following is the presentation I did

Wednesday, January 21, 2015

SharePoint 2013 with SQL Server 2014, Resolving “UserProfileApplication.SynchronizeMIIS: Failed to configure MIIS post database, will attempt during next rerun. Exception: System.Configuration.ConfigurationErrorsException: ERR_CONFIG_DB”

User profile service synchronization in SharePoint is not the favorite among administrators. If not its prerequisites are addressed properly it will definitely cause you problems. Fortunately those steps are discussed in Technet as well as in some technical blogs.

Although I’ve followed best practices, I had trouble in starting the “User Profile Synchronization Service” service in the services on this server section. It got stuck in Starting and later it showed as Error.

Luckily ULS logs came in to rescue. following is the full error message I received.

UserProfileApplication.SynchronizeMIIS: Failed to configure MIIS post database, will attempt during next rerun. Exception: System.Configuration.ConfigurationErrorsException: ERR_CONFIG_DB   
at Microsoft.Office.Server.UserProfiles.Synchronization.ILMPostSetupConfiguration.ValidateConfigurationResult(UInt32 result)   
at Microsoft.Office.Server.UserProfiles.Synchronization.ILMPostSetupConfiguration.ConfigureMiisStage2()   
at Microsoft.Office.Server.Administration.UserProfileApplication.SetupSynchronizationService(ProfileSynchronizationServiceInstance profileSyncInstance).

It seems that SharePoint Server 2013 farms without April 2014 Cumulative Update does not support user profile synchronization in SQL Server 2014. Following is the exact text from the CU download page (KB)

image

Once it is installed in all SharePoint servers I was able to easily start profile synchronization. I will dig little deeper in to the cause of the issue later. But for the time being will stop in this point. One thing to remember is that you should install SharePoint Server 2013 SP1 prior to the cumulative pack update

Monday, January 19, 2015

Presentation-Introduction to SharePoint 2013 at Public Utilities Commission of Sri Lanka

Following is the presentation I did at PUCSL, with some demonstrations using a sample Office 365 tenant created using www.microsoftofficedemos.com

Sunday, January 11, 2015

Change existing application pool identity of a SharePoint web application

Following is the PowerShell script I used to change current application pool identity to a different managed account.

  1. $web = Get-SPWebApplication "http://sp13"
  2. $account = Get-SPManagedAccount -Identity "dev\portalapppool"
  3. $web.ApplicationPool.ManagedAccount = $account
  4. $web.ApplicationPool.Update()
  5. $web.ApplicationPool.Deploy()

That’s all I had to do :)

I described how to change application pools for service applications in this article. It has answers to your questions like, “Why can’t I change the application pool identity directly from the IIS itself?”.