CHUVASH.eu

CHunky Universe of Vigourous Astonishing SHarepoint :)

Tag Archives: oob

Debugging “What’s happening” in Communities

Recently an issue was reported about count mismatches in SharePoint 2013 Communities. The number of replies in category tiles sometimes is different compared to the community stats in the web part called “What’s happening”. The actual number of replies is 1 in the figure below. The user who has reported has tried to add, update and delete discussions and replies.

 

category-replies-count.png   comm-002

I have invested some time debugging this issue. It would be pity to not share my findings. Well the first thing to do was to determine the type name for the “What’s happening” web part. To do so just edit the  page and export the web part. In the exported .webpart file I saw that the type was Microsoft.SharePoint.Portal.WebControls.DashboardWebPart.

With that knowledge it is time to open ILSpy, an awesome and free(!) assembly browser and decompiler. Load the “Microsoft.SharePoint.Portal” assembly from GAC into ILSpy. Then use F3 to search for DashboardWebPart:

comm-003

The number of replies is retrieved from SPWeb.AllProperties:

comm-004

If the Property Bag does not contain it, it gets the number of replies from the list. The formula is as follows:

list.ItemCount - list.RootFolder.ItemCount

It means that it gets the number of both discussions and replies: ItemCount of Discusssions List. The number of Discussions is determined by the ItemCount in the RootFolder of the Discussions List. Discussions are List Items in the RootFolder (num2 in the figure below). Replies are saved in the subfolders, every discussion gets an own folder. The number of all replies are num3 in the figure below.

comm-005

After checking the web properties I could see that the number of replies there were wrong: 2.

The next step was to determine where and when the Web Properties are updated. The first guess every SharePoint Developer has in such cases is an EventReceiver. Here are all EventReceivers connected to the Discussions List:

$list.EventReceivers | select class, Type, Synchronization | Out-GridView

comm-006

Allright, CommunityEventReceiver then:

comm-007

Found where the actual update happens: CommunityUtils.UpdateWebIndexedPropertyBag

comm-008

The method is used in DiscussionListCommunityEventHandler.HandleEvent

comm-009

There is a flag, flag5 that is used to determine if the Web Properties should be updated:

comm-010

But the flag5 is not true on Delete operations in some code flows:

comm-011

 

That’s it. So deleting a reply will not have any effect on “What’s happening”. But adding a new discussion will also update the stats:

comm-012

To summarize the debug session, there is an issue in the OOB code that misses to update community stats when deleting a discussion or a reply. Adding a new discussion, or a reply will synchronize the stats.

Debugging OOB SharePoint. Unable to post comments on SharePoint blogs (SP2013 June CU)

I have had a strange bug. The comment text box in a OOB SharePoint 2013 blog doesn’t appear. It only says: “There are no comments for this post.” In this blog post I’ll tell you how I found the bug and I’ll show you how you can temporarily bring the commenting to life.

comments-not-working-001

I have had luck. While it doesn’t work on the Test Environment, it does actually work on my development machine. The comments text box is rendered as an OnPostRender action in the blog comments display template. After debugging the javascript in hours and comparing the two environments, I just could confirm that displaytemplates are the same. There are two main javascript files that are involved:

  • clienttemplates.js
  • sp.ui.blogs.js

So it must some differences elsewhere. The build versions of the environments are

  • Working Environment:  15.0.4420.1017 (SharePoint 2013 RTM)
  • Not-working Environment: 15.0.4517.1005 (SharePoint 2013 June CU)

No errors are thrown, even on the blog where it doesn’t work. It is because of the permissive try-catch in this function that wraps rendering of the comment text box:

function CallFunctionWithErrorHandling(fn, c, erv, execCtx) {
    if (SPClientRenderer.IsDebugMode(c)) {
        return fn();
    }
    try {
        return fn();
    }
    catch (e) {
        if (c.Errors == null)
            c.Errors = [];
        try {
            e.ExecutionContext = execCtx;
            if (Boolean(SPClientRenderer.AddCallStackInfoToErrors) && typeof execCtx == "object" && null != execCtx) {
                execCtx.CallStack = ULSGetCallstack(CallFunctionWithErrorHandling.caller);
            }
        }
        catch (ignoreErr) { }
        c.Errors.push(e);
        return erv;
    }
}

This is where the error occurs but doesn’t appear in the script console. Here is the error:

ExecutionContext: Object
message: "Syntax error, unrecognized expression: #{B808453A-141A-4091-8467-B6915B8B3E99}-{6C3BF638-43F2-4F12-A297-DEF18635540E}-CommentContainer"
stack: "Error: Syntax error, unrecognized expression: #{B808453A-141A-4091-8467-B6915B8B3E99}-{6C3BF638-43F2-4F12-A297-DEF18635540E}-CommentContainer
    at Error ()
    at Function.st.error (jquery-1.9.1.min.js:4:10926)
    at ft (jquery-1.9.1.min.js:4:17138)
    at wt (jquery-1.9.1.min.js:4:19823)
    at Function.st (jquery-1.9.1.min.js:4:6140)
    at b.fn.extend.find (jquery-1.9.1.min.js:4:20941)
    at b.fn.b.init (jquery-1.9.1.min.js:3:1126)
    at b (jquery-1.9.1.min.js:3:206)
    at /ScriptResource.axd:344:53
    at _foreach (ScriptResource.axd:33:17)"

What? jQuery error? Why?

It turns out that jQuery is used to get the html element for the comments area in the server with June CU, but not in the Server with SharePoint 2013 RTM.

To get the reference to the comments area, it invokes the $get method, which invokes Sys.get which in some cases invokes the jQuery (if present)

$get implementation in SP 2013 June CU

These are the functions which can be found in the SharePoint 2013 June CU (15.0.4517.1005)

$get = $type.getElementById = function DomElement$getElementById(id, element) {
    /// <summary locid="M:J#Sys.UI.DomElement.getElementById">Finds an element by id.</summary>
    /// <param name="id" type="String">The id of the element to find.</param>
    /// <param name="element" domElement="true" optional="true" mayBeNull="true"></param>
    /// <returns domElement="true" mayBeNull="true">The element, or null if it was not found.</returns>
    var e = Function._validateParams(arguments, [
        {name: "id", type: String},
        {name: "element", mayBeNull: true, domElement: true, optional: true}
    ]);
    if (e) throw e;
    return Sys.get("#" + id, element || null);
}

 

        get: function get(selector, context) {
            /// <summary>Queries the DOM for a single DOM element.</summary>
            /// <validationOptions enabled="false" />
            /// <param name="selector">
            /// Selector for a DOM element based on id (#&lt;id>), class (.&lt;name>), or tag name (&lt;tagname>).
            //// More complex selectors may be used if jQuery is loaded.
            /// If multiple elements match the selector, the first one is returned.
            /// </param>
            /// <param name="context" optional="true" mayBeNull="true">An element, array of elements, or Sys.UI.TemplateContext to restrict the query within.</param>
            /// <returns>The matching element, or null if none match.</returns>
            return (context && typeof(context.get) === "function") ?
                context.get(selector) :
                this._find(selector, context, true);
        },

 

_find: function _find(selector, context, single, filter) {
    ...
    else if (window.jQuery) {
        if (!filter) {
            found.push.apply(found, jQuery(selector, context).get());
        }
        if (includeSelf) {
            found.push.apply(found, jQuery(context).filter(selector).get());
        }
    }
    ...
},

older (but working) $get implementation in SharePoint 2013 RTM

These are two versions which can be found in the older SharePoint Release: RTM (15.0.4420.1017)

var $get = Sys.UI.DomElement.getElementById = function Sys$UI$DomElement$getElementById(id, element) {
    /// <summary locid="M:J#Sys.UI.DomElement.getElementById" />
    /// <param name="id" type="String"></param>
    /// <param name="element" domElement="true" optional="true" mayBeNull="true"></param>
    /// <returns domElement="true" mayBeNull="true"></returns>
    var e = Function._validateParams(arguments, [
        {name: "id", type: String},
        {name: "element", mayBeNull: true, domElement: true, optional: true}
    ]);
    if (e) throw e;
    if (!element) return document.getElementById(id);
    if (element.getElementById) return element.getElementById(id);
    var nodeQueue = [];
    var childNodes = element.childNodes;
    for (var i = 0; i < childNodes.length; i++) {
        var node = childNodes[i];
        if (node.nodeType == 1) {
            nodeQueue[nodeQueue.length] = node;
        }
    }
    while (nodeQueue.length) {
        node = nodeQueue.shift();
        if (node.id == id) {
            return node;
        }
        childNodes = node.childNodes;
        for (i = 0; i < childNodes.length; i++) {
            node = childNodes[i];
            if (node.nodeType == 1) {
                nodeQueue[nodeQueue.length] = node;
            }
        }
    }
    return null;
}

It doesn’t even go to Sys.get and doesn’t even try to use jQuery.

The id of the comment are is a combination of two guids and -CommentContainer. jQuery fails to select an element with this id:
This error happens when you try to select this html element with jQuery in the web console:

comments-not-working-002

Temporary solution

The solution is to prevent using jQuery for this element selection. Hopefully new updates of SharePoint will address this issue. Until then we have to tweak the $get method. To do it very carefully, we can copy the old $get function and call it $get_asFoundInRTM and copy the new $get and call it $get_asFoundInJuneCU

The $get function has to rewritten like that:

$get_asFoundInJuneCU = $get

$get = function () {
    var id = arguments[0];
    return /\{/.test(id)
        ? $get_asFoundInRTM.apply(null, arguments)
        : $get_asFoundInJuneCU.apply(null, arguments);
}

This javascript code has to be loaded after two ScriptResource.axd files. Please be very careful if you have to implement this temporary fix. Probably it is better to wait for an official Microsoft bug fix.

 

UPDATE 2014-03-27

I have discovered that in SP1 it is already solved.

Discovering SharePoint

And having fun doing it

Bram de Jager talking Office 365, SharePoint and Azure

My view and thoughts on Productivity and more.

My programming life

and everything in between

SharePoint Development Lab by @avishnyakov

It is a good place to share some SharePoint stories and development practices.

SharePoint Dragons

Nikander & Margriet on SharePoint

RealActivity - Real-time and trustworthy

Blog site of founder, RealActivty - Paul J. Swider

Mai Omar Desouki - Avid SharePointer

Egyptian & Vodafoner - Senior SharePoint Consultant

Cameron Dwyer | Office 365, SharePoint, Outlook, OnePlace Solutions

Office 365, SharePoint, OnePlace Solutions & Life's Other Little Wonders

.:paul.tavares:.

Me and My doings!

Share SharePoint Points!!

By Mohit Vashishtha

Jimmy Janlén "Den Scrummande Konsulten"

Erfarenheter, synpunkter och raljerande om Scrum från Jimmy Janlén

SPJoel

SharePoint for everyone

SharePointRyan

Ryan Dennis is a SharePoint Solution Architect with a passion for SharePoint and PowerShell

SharePoint 2020

The Vision for a Future of Clarity

Aharoni in Unicode, ya mama

Treacle tarts for great justice

... And All That JS

JavaScript, Web Apps and SharePoint

blksthl

Mostly what I know about SharePoint - CommunicoCuspis