Sync TaxonomyHiddenList after updating Term value programmatically for SharePoint 2013/2016

In one of my project, there was a requirement to manually update term set title and see the updated version in library view. When I did that it didn’t reflect the change on demand. So let me share my experience with the below scenario:

I have one library where I have added a custom field of type managed metadata type.

Columns

These fields (Regions, Survey Title) are targeting to its related TermSet from the Term Store and showing it on the library view.

When I added a new item to the library, I selected it’s metadata and saved the document.

Now I had change request to update metadata term’s title. Let’s consider Region has one value “Colorado” and change request was to change it to “CO”.

To achieve this, I first updated the term title in the term store manager but change wasn’t reflected immediately.

Below are the different ways to achieve the changes immediately:

Out of the Box way:

There is a Timer job for this, it actually sync the term store data to the hidden taxonomy list for that site collection and update wherever term fields are used.

Though to run this job manually, below are steps I followed:

  • Go to the Central Administration > Monitoring > Job DefinitionsTaxonomy Update Scheduler (for your web application). Open it.
  • By default that Job will run hourly, so to run it manually you have to click on Run Now.
  • Once Job is successful, Data from term store will be synced to the TaxonomyHiddenList for that site collection and I was able to see the updated metadata field title for the CO in place of Colorado.

Programmatically with PowerShell:

This could also be done by PowerShell, Below is the snippet I used:

$siteUrl = "http://mysharepoint:1327/"
$site = Get-SPSite $siteUrl
[Microsoft.SharePoint.Taxonomy.TaxonomySession]::SyncHiddenList($site)
$site.dispose()

Programatically with C# SharePoint Console Application:

Similar way you can achieve the same with Server side object model. Following code snippet by creating simple console application and run where SharePoint is installed. Below was the snippet I used:

using Microsoft.SharePoint;
using Microsoft.SharePoint.Taxonomy;
using System;

namespace TaxonomyUpdater
{
    public static class TaxonomyHiddenList
    {
        public static void Update(string SiteUrl)
        {
            SPSite Site2Update = new SPSite(SiteUrl);
            TaxonomySession.SyncHiddenList(Site2Update);
            Site2Update.Dispose();
        }
    }
}

Additional Problem:

There was a situation where I wasn’t able to update the termset data by any of the above solution, from this blog post: Taxonomy Update Scheduler not working? I was able to figure out there was a table in the MMS database called ECMUsedTerm. This table wasn’t updated with all the terms data in it. This could be caused by two different scenarios:

  1. If we recreated the Managed Metadata Service with a clean database, importing the terms with the same id’s then of course the ECMUsedTerm table is empty / information is lost.
  2. If we moved the content database from one farm to another (maybe from staging to prod) which of course has a new Managed Metadata Service, then the ECMUsedTerm table is of course not in sync.

Solution:

To solve this issue, from the article referred I found the below PowerShell code, which will sync the ECMUsedTerm data.

$url = "https://yoursite"
$site = Get-SPSite $url
$tax = Get-SPTaxonomySession -Site $url
$ts = $tax.TermStores[0]
$ts.UpdateUsedTermsOnSite($site)
$site.dispose()

By using this snippet, I was able to update the records in the ECMUsedTerm table of MMS database and now my term set was reflecting once any of the above solution or timer job is ran successfully.

Happy SharePointing!!

Advertisements

Add External DLL with SharePoint WSP to GAC

In this blog, I will explain how you can refer external dll in your SharePoint solution to make it work wherever this dll is not there in the Global Assembly Cache. So the solution itself must contain the dll. To add dll into your SharePoint solution below are the steps:

  1. Reference the dll in the Solution references first.
    1
  1. Now add the dll into your solution by selecting the dll. Once you add it, it will appear in the References list. But it will not be added to the package of Solution, which we have to manually do that.
  1. Open package file
    2
  1. Open Advanced Click Add > Add Existing Assembly
    3
  1. Select dll source path. Now click OK. Make sure Deployment Target is
    4

Once you are done with above steps. Now verify that WSP is containing that dll.

In my case I have renamed it from EmbedExternalDLLs.wsp file  to EmbedExternalDLLs.cab and extract it to the folder. In that folder you will find that added dll.

Restore Site Collection with new Content database to existing web application.

In one of my project, I had requirement to migrate record center site collection to the new server but in that requirement I had to create only new site collection with existing web application and different database.

So to achieve this, below is the detailed snippet of PowerShell script.

First of all I took backup of the source site collection:

Backup-SPSite –Identity http://sharepointolddev –LiteralPath "C:\Backup\olddev.bak"

Now to restore above backup into new site collection I needed to create separate content database. Below is the script to create new content database under a web application.

New-SPContentDatabase -Name "WSS_Content_DBNew" -DatabaseServer "MYDBNAME"  -WebApplication http://sharepointdev/

Once that Database is created I created empty site collection with record center site template. Below is the snippet to create new site collection with created content database.

$site = "http://sharepointdev/sites/newdev"
$dbname = Get-SPContentDatabase "WSS_Content_DBNew"
$ownerAlias = "sp\prathod";
New-SPSite -URL $site -OwnerAlias $ownerAlias -SecondaryOwnerAlias $ownerAlias -ContentDatabase $dbname -Template "OFFILE#1"

Once site collection is created I simply restored existing site collection backup with below snippet:

Restore-SPSite –Force –Identity http://sharepointdev –LiteralPath "C:\Backup\olddev.bak"

That’s it, site collection is restored with new content database in existing web application.

Disable ItemUpdated Endless loop in Event Receiver

In one of my project, I had a requirement to build an event receiver which is for item updated.

The logic is when I update the document, programmatically my custom field will be updated with a value.

So I thought of adding event receiver for that and wrote below code:

public override void ItemUpdated(SPItemEventProperties properties)
{
    base.ItemUpdated(properties);
    SPListItem listItem = properties.ListItem;
    listItem["MyCustomField"] = "Okay, I’m updated!";
    listItem.Update();
}

When I ran this code with debugging,

listItem.Update();

fired and event receiver called again as item is being updated so my break-point started over from

base.ItemUpdated(properties);

It means again ItemUpdated event receiver will be called.

So this was like endless loop. There must be some workaround for this which is as follow: we need to write updating code in a way that it doesn’t trigger event receiver again.

So I have created below DisabledEventsScope class in the event receiver file.

class  DisabledEventsScope : SPItemEventReceiver, IDisposable
{
    // Boolean to hold the original value of the EventFiringEnabled property
    bool _originalValue;
    public DisabledEventsScope()
    {
        // Save off the original value of EventFiringEnabled
        _originalValue = base.EventFiringEnabled;

        // Set EventFiringEnabled to false to disable it
        base.EventFiringEnabled = false ;
    }
    public void Dispose()
    {
        // Set EventFiringEnabled back to its original value
        base.EventFiringEnabled = _originalValue;
    }
}

This class will turn off the firing of the event receiver by setting Boolean value of event receiver, run the code without endless loop. We need to implement this class in our code so that it disable event firing.

public override void ItemUpdated(SPItemEventProperties  properties)
{
    base.ItemUpdated(properties);
    using (DisabledEventsScope scope = new DisabledEventsScope ())
    {
        SPListItem listItem = properties.ListItem;
        listItem["MyCustomField"] = "Okay, I’m updated!";
        listItem.Update();
    }
}

Once this code is running, it won’t be firing endless loop of event receiver.

Happy SharePointing.!!

Search with Keyword Query in SharePoint OnPremise

In SharePoint 2013 on premise, I had a requirement to have a webpart, that does search each project site’s task list items to fetch the task assigned to logged in user which is not completed. All the project site has one task lists so to fetch the record so I have used KeywordQuery, which is comparatively faster than SPSiteDataQuery.
So below is the snippet to fetch the records.

using (SPSite site = new SPSite(pwaSiteUrl))
{
    SPUser _currUser = SPContext.Current.Web.CurrentUser;
    KeywordQuery keywordQuery = new KeywordQuery(site);
    keywordQuery.RowLimit = 500;
    keywordQuery.SelectProperties.Add("SiteTitle");
    keywordQuery.SelectProperties.Add("AssignedTo");
    keywordQuery.SelectProperties.Add("PercentCompleteOWSNMBR");
    keywordQuery.SelectProperties.Add("DueDateOWSDATE");
    keywordQuery.QueryText = "ContentClass:\"STS_ListItem_Tasks\" AND " +
                                "(PercentCompleteOWSNMBR<>1.0*) AND " +
                                "(DueDateOWSDATE:2*) AND " +
                                "AssignedTo:" + _currUser.Name;
    SearchExecutor searchExecutor = new SearchExecutor();

    ResultTableCollection resultTableCollection = searchExecutor.ExecuteQuery(keywordQuery);

    ResultTable resultTable = resultTableCollection.FirstOrDefault();
    DataTable dataTable = resultTable.Table;
    GetFormatedMyTasks(dataTable);
}

In QueryText, I have used multiple fitlers on managed properties.
1. All items must be task items. ContentClass:"STS_ListItem_Tasks"
2. Task must not be completed. PercentCompleteOWSNMBR<>1.0*
3. Due Date must not be empty. DueDateOWSDATE:2* (by default system date starts with year)
4. AssignedTo must be current user.

Note:
1. For DueDateOWSDATE I have used not empty filter. Date will always be starting from 2 (current year starting digit).
2. pwaSiteURL is my project root site in that I have all my project sites, so it will search for that context only.
3. By default my custom field will not appear in the result source, so I have to add my properties to results with: keywordQuery.SelectProperties.Add("AssignedTo");

Show All People in search result Webpart

In this blog post, I will explain how you can show all people by default when you load the page having search result webpart.

I assume in your publishing page you have added search result webpart. Now Edit webpart properties and click Change query

Search Result Webpart properties

Search Result Webpart properties

In Build Your Query dialog, select a query dropdown to Local People Results (System) and in Query text add following line:

contentclass:spspeople

Now click Test query.

Build Your Query Dialog

Build Your Query Dialog

Once you test the query, you will see the result in the right side Search Result Preview panel.

Search User Result Preview

Search User Result Preview

Now click OK and Save the page. You will now able to see all employee directory.

Happy SharePointing!!

SharePoint 2013 Calendar not displaying correctly with IE11

SharePoint and other geeky stuff

Been working on my SharePoint Dev machine where I needed to add a calendar to my site. Wrote the code, everything looked good. I then VPN onto the client’s machine to upload the code to their QA environment. Soon as I looked at the calendar, I notice that it was displaying funny and not working as expected. After ensuring I had indeed uploaded the latest code, I decided to go back to basics and create an out of the box site and add a calendar to the site. Again the calendar didn’t look right.

Non Working Calendar

I jumped on the web front end, and used IE11 from there and the same site appeared correctly.

From my machine I checked with Chrome, Safari, Firefox and all appear correctly, but for some reason my IE didn’t work. It was the first time I’ve had a case of “It doesn’t work on…

View original post 599 more words