Fix broken Managed metadata service and more after CU update

After installing the September CU for SharePoint 2013 Server I have several problems.

The two most annoying things:

  • The Managed Metadata Service went down, giving me no managed navigation and no access to term store.
  • The User Profile Synchronization Service stopped and refused to start.

After trying numerous things (including recreation of the Managed Metadata Service application…) I found this message in the ULS logs:

w3wp.exe (0x1D78) 0x21A0 SharePoint Server Taxonomy ca3r Monitorable Error encountered in background cache check System.Security.SecurityException: Requested registry access is not allowed.     at Microsoft.Win32.RegistryKey.OpenSubKey(String name, Boolean writable)

Googling this error gave me some input! There is a command in psconfig.exe with the purpose of setting correct permissions on SharePoint registry keys.

Running

psconfig -cmd secureresources

resolved all my issues.

Here is the blog post that guided me to the correct solution: http://sharepointologic.blogspot.se/2014/02/managed-metadata-service-not-working.html

Advertisements

Managed metadata and KQL Search

Using metadata on your information is a great way of categorizing it. It also enables you to drill up and down in information by the means of the term hierarchy.

By leveraging search, you can gather information from all the site collections, even web applications in your farm (as long as they use the same Search Service Application at least).

Let’s take a look at a basic example of how to create a method that using KQL will gather all items tagged with a specific term.

First, here is the complete method:

public DataTable GetItemsByTag(Term term, string[] selectProperties, string filterManagedProperyName)
{
     KeywordQuery kq = new KeywordQuery(SPContext.Current.Site);
     kq.TrimDuplicates = false;
     kq.SelectProperties.AddRange(selectProperties);
     kq.QueryText = String.Format("{0}:\"GP0|#{1}\"", term.TermGuid, filterManagedProperyName)

     SearchExecutor se = new SearchExecutor();
     var result = se.ExecuteQuery(kq);
     return result.Filter("TableType", KnownTableTypes.RelevantResults).FirstOrDefault().Table;
}

So, a very basic method that just returns the relevant results based on the term passed in. Of course, to be able to render the results we later on would have to iterate the DataTable rows and perhaps generate some more easy to handle objects that we could pass to our view manager.

Some clarifications about the code:
“filterManagedProperyName” should the the name of the managed property created for the metadata column (the one with ows_taxId in it).

The “GP0|#” part of the QueryText makes sure we only get items tagged with the passed in term. If you do not add “GP0|#” in from of the term GUID, you will also get results for the parent terms (since in the managed property also parts of the term hierarchy is stored)

That was it for today!

Avoid duplicated webparts on Page Layout feature reactivation

We’ve all been there:
You have created some nice Page Layouts, added some webparts to the WebPartZones via the Elements.xml file, deployed the solution and activated the feature.

Now it is just a matter of time before the client asks for a new Page Layout, or for a change in one of the existing one.

“Fine”, you think – makes the changes, builds, uploads the .wsp to the server, runs Update-SPSolution and reactivates the feature.

Disaster! All your webparts now are added two times to all new pages created! The client gets furious and you can’t stop hitting yourself.

Don’t worry! There is a quite easy solution to this problem:

Add a FeatureReceiver to the feature containing your Page Layouts by “Right Click on the Feature in Visual Studio -> Add Event Receiver”

In the FeatureActivatedEvent write the following:

public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
    var site = properties.Feature.Parent as SPSite;
    FixDuplicateWebParts(site, "YOURPAGELAYOUTPREFIX");
}

Replace YOURPAGELAYOUTPREFIX with the prefix you hopefully have used in the filename of your webparts.

Now all you have to do is implementing the method

        private void FixDuplicateWebParts(SPSite site, string prefix)
        {
            try
            {
                SPList list = site.GetCatalog(SPListTemplateType.MasterPageCatalog);
                SPListItemCollection items = list.Items;
                List<string> webParts = new List<string>();

                // find the right Page Layout
                for (var i = items.Count - 1; i >= 0; i--)
                {
                    var item = items[i];
                    if (item.Name.IndexOf(prefix,
                        StringComparison.CurrentCultureIgnoreCase) > -1 && item.Name.IndexOf(".aspx",
                        StringComparison.CurrentCultureIgnoreCase) > -1)
                    {
                        SPFile file = item.File;
                        file.CheckOut();
                        // get the Web Part Manager for the Page Layout
                        using (SPLimitedWebPartManager wpm =
                            file.GetLimitedWebPartManager(PersonalizationScope.Shared))
                        {
                            // iterate through all Web Parts and remove duplicates
                            int nbrOfWebParts = wpm.WebParts.Count - 1;
                            for (var j = nbrOfWebParts; j >= 0; j--)
                            {
                                using (var stringWriter = new StringWriter())
                                {
                                    using (var xw = new XmlTextWriter(stringWriter))
                                    {
                                        System.Web.UI.WebControls.WebParts.WebPart wp =
                                        wpm.WebParts[j];

                                        wpm.ExportWebPart(wp, xw);
                                        xw.Flush();

                                        string md5Hash = GetMD5(stringWriter.ToString());
                                        if (webParts.Contains(md5Hash))
                                        {
                                            wpm.DeleteWebPart(wp);
                                        }
                                        else
                                        {
                                            webParts.Add(md5Hash);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

                file.CheckIn(string.Empty);
                if ((file.Level == SPFileLevel.Draft) && (file.CheckOutType == SPFile.SPCheckOutType.None))
                {
                    file.Publish(string.Empty);

                    try
                    {
                        if (file.Item.ModerationInformation.Status == SPModerationStatusType.Pending)
                        {
                            file.Approve(string.Empty);
                        }
                    }
                    catch (System.Exception)
                    { //Suppress 
                    }
                }
            }
            catch (Exception e)
            {
                Logger.WriteLog(Logger.Category.Unexpected, this.ToString(), e.Message);
            }
        }

This code in turn requires this method:

        public static string GetMD5(string Value)
        {
            if (Value == "") return "";
            MD5CryptoServiceProvider x = new MD5CryptoServiceProvider();
            byte[] bs = System.Text.Encoding.UTF8.GetBytes(Value);
            bs = x.ComputeHash(bs);
            x.Clear();  // dispose
            System.Text.StringBuilder s = new System.Text.StringBuilder();

            foreach (byte b in bs)
            {
                s.Append(b.ToString("x2").ToLower());
            }

            return s.ToString();
        }

That’s it! When you reactivate the feature it makes sure that not two identical WebParts will be present in a Page Layout.

The First Post

In this blog I will write about findings, problems and solutions related to SharePoint development