SharePoint get followed sites using REST Api


Recently I was tasked with a project requirement that the user should be able to see list of content he/she followed. To me this sounds much like using the following feature of SharePoint 2013 which allows you to follow documents, sites, people and tags. Also, we don’t want the user to navigate to his/her mySite and have a look on to the content followed.

We can use the SharePoint 2013 Representational State Transfer (REST) service to do the same tasks you can do when you use the .NetCSOM, JSOM.

Here I explain how to retrieve the site name and URL followed by the current user in SharePoint 2013 using a client object model (REST API and JavaScript) and displaying it in the SharePoint page.

1. Create a new page and a Content Editor Webpart (CEWP).

Create a New page

2. Edit the web part that was added to the page.

Edit the web part

3. Upload your text file script into the site assests and copy the path of the text file and paste it into the Content link in CEWP.

4. Output

Output

Code

The following example shows how to retrieve all of the following sites:

<html>
<head>
<script type=”text/javascript” src=”//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js”></script>

<script type=”text/javascript”>
var followingManagerEndpoint;
var followedCount;

var followingEndpoint;
var URL;
var website;
var clientContext;

SP.SOD.executeFunc(‘sp.js’, ‘SP.ClientContext’, loadWebsite);
function loadWebsite() {
clientContext = SP.ClientContext.get_current();
website = clientContext.get_web();
clientContext.load(website);
clientContext.executeQueryAsync(onRequestSucceeded, onRequestFailed);
}

function onRequestSucceeded() {

URL = website.get_url();
followingManagerEndpoint = decodeURIComponent(URL) + “/_api/social.following”;

getMyFollowedContent();
}

function onRequestFailed(sender, args) {
alert(‘Error: ‘ + args.get_message());
}

// Get the content that the current user is following.
// The “types=14” parameter specifies all content types
// (documents = 2 + sites = 4 + tags = 8).
function getMyFollowedContent() {

$.ajax( {
url: followingManagerEndpoint + “/my/followed(types=14)”,
headers: {
“accept”: “application/json;odata=verbose”
},
success: followedContentRetrieved,
error: requestFailed
});
}

// Parse the JSON data and iterate through the collection.

function followedContentRetrieved(data) {
var stringData = JSON.stringify(data);
var jsonObject = JSON.parse(stringData);
var types = {
1: “document”,
2: “site”,
3: “tag”
};

var followedActors = jsonObject.d.Followed.results;
var followedList = “You’re following items:”;

for (var i = 0; i < followedActors.length; i++) {
var actor = followedActors[i];
followedList += “<p>The ” + types[actor.ActorType] + “: \”” +actor.Name + “\”</p>”+”<p>Site URL ” + “: \”” +
actor.Uri+ “\”</p>”;;
}
$(“#Follow”).html(followedList);
}

function requestFailed(xhr, ajaxOptions, thrownError) {
alert(‘Error:\n’ + xhr.status + ‘\n’ + thrownError + ‘\n’ + xhr.responseText);
}

</script>
</head>
<body>
<div id=”Follow”></div>
</body>
</html>

Happy SharePointing 🙂

Advertisements

Send message to client app part using a “PostMessage Shim”


In this post, I’ll walk through how to use the postMessage api to enable cross-frame communication between your Client App Parts and the hosting SharePoint page, to make your SharePoint App Parts more dynamic and responsive to changes in the parent page.

Overview

In the SharePoint 2013 App Model, Client App Parts are implemented as iframes into pages hosted in App Webs or Provider Hosted web applications. Because SharePoint apps are hosted on different domains, the iframes can’t use javascript to access the parent window and get information from the hosting page. This is a good thing. You wouldn’t want a Client App Part that you installed from the marketplace to be able to see the list of customers on that List View web part that sits right next to it on the page. But it does make it very hard as a developer to give Client App Parts more dynamic page information to work with. The only contextual info a Client App Part can get is through Client App Part properties.

Normal SharePoint Web Parts have a number of ways of getting initialization data from the hosting page when they first load up:

  1. Web Part Properties (Tool Pane)
  2. Web Part Connections (Passing info from Web Part to Web Part)
  3. Host Page QueryString
  4. Reading Hidden Fields or other form elements on the page
  5. Built-in SharePoint objects like _spPageContextInfo
  6. Reading the metadata of the host page

Unfortunately, SharePoint Client App Parts can only get information from the first option, through Client App Part Properties. When you build your Client App Part with custom properties, they appear in the App Part’s tool pane when you edit the App Part, similar to normal Web Part toolpane properties. Client App Part properties are a little different though – setting these actually appends a querystring parameter to the App Part’s iframe src attribute, which your App Part page can then read when it starts up. That’s good for setting a one-time configuration of your App Part, but you can’t change any of those properties dynamically in response to changes in the host page.

In this post, I’ll show you how to pass additional data from the host page to your Client App Parts via the postMessage api, effectively opening the door to leveraging 2-6 above. The example I’ll show will be an App Part placed on the MySite Host’s About Me page. The App Part will read the host page’s accountname querystring parameter to determine which user profile is being viewed, and will display some basic profile information about that user.

The postMessage API

The postMessage API was designed to enable safe, cross-domain communication between windows or iframes. Essentially each window needs to opt-in to accepting communications from other cross-origin/cross-domain windows. Any window or iframe can send messages to another window or iframe just by calling the postMessage method. If the target window hasn’t opted-in to listen for these messages, the messages are just silently ignored.

Requesting Information from the Host Page

The first step in getting this to work is to configure your Client App Part page to send a request to the host page, and to configure a listener for the host page’s response.

To start this out, using Visual Studio 2013, I created a new SharePoint App project called PostMessageApp, added a Client Web Part (Host Web) called PostMessageAppPart, and created a new page for the App Part called PostMessageAppPartPage.aspx. I gave the App Part the Read permissions to the User Profile (Social) permission set.

The basic solution structure.

In the App Part page, I added some basic HTML markup:

1
2
3
4
5
6
7
8
9
<body>
    <div>
        Host page's full url:<br />
        <textarea id="hostpageurl" readonly="readonly" style="width:100%;height:75px;overflow:scroll;" ></textarea><br /><br />
        First name: <span id="firstname"></span><br />
        Last name: <span id="lastname"></span><br />
        Department: <span id="department"></span><br />
    </div>
</body>

Here is what the app part looks like empty:

Empty App Part

In the newly created App Part page, I added a javascript function to the page head called getQueryStringParameter which is needed to extract querystring information. You’ve probably seen a similar function in many of the SharePoint Hosted App code samples on the internet. This version below includes an overload to get a querystring value from a passed-in url (rather than the current document’s url), which will be used later:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
function getQueryStringParameter(key, urlToParse) {
    /// <signature>
    /// <summary>Gets a querystring parameter, case sensitive.</summary>
    /// <param name="key" type="String">The querystring key (case sensitive).</param>
    /// <param name="urlToParse" type="String">A url to parse.</param>
    /// </signature>
    /// <signature>
    /// <summary>Gets a querystring parameter from the document's URL, case sensitive.</summary>
    /// <param name="key" type="String">The querystring key (case sensitive).</param>
    /// </signature>
    if (!urlToParse || urlToParse.length === 0) {
        urlToParse = document.URL;
    }
    if (urlToParse.indexOf("?") === -1) {
        return "";
    }
    var params = urlToParse.split('?')[1].split('&');
    for (var i = 0; i < params.length; i = i + 1) {
        var singleParam = params[i].split('=');
        if (singleParam[0] === key) {
            return decodeURIComponent(singleParam[1]);
        }
    }
    return "";
}

After including the querystring function, I added the following script underneath it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
(function () {
    var getHostPageInfoListener = function (e) {
        /// <summary>Callback function for getting the host page's info via postMessage api.</summary>
        console.log("postMessage response received: " + e.data);
        var messageData;
        try {
            messageData = JSON.parse(e.data);
        }
        catch (error) {
            console.log("Unable to parse the response from the host page.");
            return;
        }
    }
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', getHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', getHostPageInfoListener);
    }
    // Send the host page a message
    var hostPageMessage = {};
    hostPageMessage.message = "getHostPageInfo";
    var hostPageMessageString = JSON.stringify(hostPageMessage);
    window.parent.postMessage(hostPageMessageString, document.referrer);
    console.log("Sent host page a message: " + hostPageMessageString);
})();

This script accomplishes two things: 1) it sends a message to the host page requesting information, and 2) it registers a listener (callback) for the response from the host page. Notice that I’m sending a stringified JSON object to the host page, which I will reconstitute later. When you send messages between windows, you are just sending one string of data. You can choose to send XML, plain text, or even stringified JSON.

At this point I can send a message to the host page, but since the host page isn’t listening for it yet, the message will just silently get ignored.

Sending Information Back to the Client App Part Page

The next step in getting this to work is to configure the host page to listen and respond to the request for more information. For this, some javascript must be placed on the host page to opt-in to receiving messages from other windows. You can add javascript to a SharePoint page in a variety of ways, through a Content Editor or Script Editor web part, by editing the page or page layout in SharePoint Designer, or by adding the script directly to a masterpage.

For this example, I am going to edit the About Me page in a MySite Host site collection (“Person.aspx”) with SharePoint Designer to add the following script. I am going to add the script to the PlaceHolderAdditionalPageHead area:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<asp:Content contentplaceholderid="PlaceHolderAdditionalPageHead" runat="server">
<SPSWC:ActivityFeedLink Consolidated="false" runat="server"/> 
<SPSWC:MySiteHideDiv HideRibbonRow="true" runat="server"/>
<script type="text/javascript">
(function() {
    var sendHostPageInfoListener = function (e) {
        var messageData;
        try
        {
            messageData = JSON.parse(e.data);
        }
        catch (error)
        {
            console.log("Could not parse the message response.");
            return;
        }
        // Construct the return data to send to the app part
        var returnData = {};
        returnData._spPageContextInfo = _spPageContextInfo;
        returnData.hostPageURL = document.URL;
        var returnDataString = JSON.stringify(returnData);
        e.source.postMessage(returnDataString, e.origin);
        console.log("Sent app part iframe message: " + returnDataString);
    };
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', sendHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', sendHostPageInfoListener);
    }
})();
</script
</asp:Content>

The code above does two things: 1) Opts-in to listen for messages from other windows, and 2) Sends JSON data about the current page to the window that sent the request. I’ve chosen here to send a couple of pieces of information. First, I sent the full url of the host page, including any querystring parameters, by passing the document.URL. Second, I’ve also chosen to send the _spPageContextInfo object of the host page, which contains some rich data about the host page. This is just to demonstrate that you aren’t limited to sending plain text, you can serialize javascript objects from the host page as well.

With the App Part and the script above on the page, I can now see the communication back and forth between the windows in the console, and can view the returned data in a watch window. Notice the host page’s _spPageContextInfo is fully deserialized and expanded into a javascript object for use in the App Part.

The returned data

Securing the Requests

By putting these scripts in place, I have allowed my host page to give information to any window or iframe that sends a request message. It’s a good idea to make this more secure, and only give host page information out to windows that you trust. You can get as restrictive or permissive as you want/need with this validation.

For home-grown side-loaded SharePoint apps, this could be as simple as passing a shared key around, and checking on both sides. To demonstrate this basic validation, I’ll add a couple of lines to the code in the Client App Part page to store and send the secret key and to parse and read it from the host page:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var secretKey = "mysecretkeyxyz";
(function () { 
    var getHostPageInfoListener = function (e) {
        /// <summary>Callback function for getting the host page's info via postMessage api.</summary>
        console.log("postMessage response received: " + e.data);
        var messageData;
        try {
            messageData = JSON.parse(e.data);
        }
        catch (error) {
            console.log("Unable to parse the response from the host page.");
            return;
        }
        if (!messageData || !messageData.secretKey || messageData.secretKey !== secretKey) {
            console.log("Could not validate the message.");
            return;
        }
    };
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', getHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', getHostPageInfoListener);
    }
    // Send the host page a message
    var hostPageMessage = {};
    hostPageMessage.secretKey = secretKey;
    hostPageMessage.message = "getHostPageInfo";
    var hostPageMessageString = JSON.stringify(hostPageMessage);
    window.parent.postMessage(hostPageMessageString, document.referrer);
    console.log("Sent host page a message: " + hostPageMessageString);
})();

On the host page, I’ve also added some validation code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
(function() {
    var sendHostPageInfoListener = function (e) {
        var secretkey = "mysecretkeyxyz";  
        var messageData;
        try {
            messageData = JSON.parse(e.data);
        }
        catch (error)
        {
            console.log("Could not parse the message response.");
            return;
        }
        if (!messageData || !messageData.secretKey || messageData.secretKey !== secretKey) {
            console.log("Could not validate message.");
            return;
        }
        // Validate that it contains the expected instruction
        if (messageData.message !== "getHostPageInfo") {
            return;
        }
        // Construct the return data to send to the app part
        var returnData = {};
        returnData.secretKey = secretKey;
        returnData._spPageContextInfo = _spPageContextInfo;
        returnData.hostPageUrl = document.URL;
        var returnDataString = JSON.stringify(returnData);
        e.source.postMessage(returnDataString, e.origin);
        console.log("Sent app part iframe message: " + returnDataString);
    };
    // Register the listener
    if (typeof window.addEventListener !== 'undefined') {
        window.addEventListener('message', sendHostPageInfoListener, false);
    }
    else if (typeof window.attachEvent !== 'undefined') {
        window.attachEvent('onmessage', sendHostPageInfoListener);
    }
})();

For the purposes of this example, this basic validation will suffice to demonstrate the point, but I would recommend beefing this up in your own implementations.

Now, on to the last part, consuming the information.

Consuming the Data

Once you’ve got these hooked up, you can work with the data. In the App Part Page, I modified the getHostPageInfoListener function with some code to get the accountname querystring parameter from the data the host page returned, and to query the User Profile REST api to get data about that user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
var getHostPageInfoListener = function (e) {
    /// <summary>Callback function for getting the host page's info via postMessage api.</summary>
    console.log("postMessage response received: " + e.data);
    var messageData;
    try {
        messageData = JSON.parse(e.data);
    }
    catch (error) {
        console.log("Unable to parse the response from the host page.");
        return;
    }
    if (!messageData || !messageData.secretKey || messageData.secretKey !== secretKey) {
        console.log("Could not validate the message.");
        return;           
    }
    var appWebUrl = getQueryStringParameter("SPAppWebUrl");
    var requestUrl = "";
    var requestData = {};
    var accountName = getQueryStringParameter("accountname", messageData.hostPageURL);
    if (!accountName || accountName.length === 0) {
        console.log("Could not find an accountname querystring parameter, using the current user.");
        // Use the current user instead.
        requestUrl = appWebUrl + "/_api/SP.UserProfiles.PeopleManager/GetMyProperties";
    }
    else {
        requestUrl = appWebUrl + "/_api/SP.UserProfiles.PeopleManager/GetPropertiesFor(accountName=@v)";
        requestData["@v"] = "'" + accountName + "'";
    }
    jQuery("#hostpageurl").html(messageData.hostPageURL);
    jQuery.ajax({
        url: requestUrl,
        type: "GET",
        data: requestData,
        headers:{ Accept:"application/json;odata=verbose" },
        success: function (data) {
            var properties = data.d.UserProfileProperties.results;
            for (var i = 0; i < properties.length; i++) {
                if (properties[i].Key === "FirstName") {
                    jQuery("#firstname").html(properties[i].Value);
                }
                else if (properties[i].Key === "LastName") {
                    jQuery("#lastname").html(properties[i].Value);
                }
                else if (properties[i].Key === "Department") {
                    jQuery("#department").html(properties[i].Value);
                }
            }
        },
        error: function (jqxr, errorCode, errorThrown) {
            console.log(jqxr.responseText);
        }
    });
};

You can see the result below, where I am logged in as Adam Toth, but am viewing Harry Tuttle’s profile:

App Part displaying another user's profile information.

Conclusion

With a simple javascript shim in place on a host page, I’ve shown how much richer contextual data can be passed to a Client App Part. Until Microsoft implements an alternative method, the postMessage api remains a safe and viable option for tackling scenarios that sandbox or full-trust web parts have been able to do for some time.

SharePoint 2013: The search service is not able to connect to the machine that hosts the administration component.Verify that the administration component.


Hi,

Issue:

The search service is not able to connect to the machine that hosts the administration component. Verify that the administration component ‘GUID’ in search application ‘Search Service Application’ is in a good state and try again. In Farm Search Administration page when click on “Modify Topology” get error “An unhandled exception occurred in the user interface.Exception Information: Exception has been thrown by the target of an”

Cause: Search is not able to connect is because of name reasons, in this article I am explaining various the solution of this issue.

Solutions: Please find the below solutions, That one of it can resolve the issue.

Solution 1:

In the end it turns out to be that the application pool that hosts the search service application somehow doesn’t have the correct access.
You can simply change the application pool to use SharePoint Web Services System for search service applications and check.
1. Click on Start > Run > Type Inetmgr > Click OK

0094

 

 

 

 

 

 

 

 

 

 

 

2.  In IIS > Expand server > Expand sites > Expand “SharePoint Web Services”
0096

3. Now check all the GUID 1 by 1 in content view unless you find searchadmin.svc and searchservice.svc

0095

4. Right click GUID go to advance settings

0097

5. Change the application to “SharePoint Web Services” > Click OK
0098

Solution 2: Enable the timer job and do IIS reset

1. Run below PS command to know the status of timer job
Get-SPTimerJob job-application-server-admin-service
Result ==> Is Disabled: True

  1. Run below PS command to enable the service.
    Enable-SPTimerJob job-application-server-admin-service
    Result ==> IsDisabled: False
  2. Do Net Stop sptimerv4
  3. Do Net start sptimerv4
  4. DO iisreset

Solution 3:Ensure the account has full control permissions on the Search service application and IIS account used by this service application
Follow below steps
1. Open Central Admin  > Select Security > Select “Configure service accounts”
0092

2. Select the search service application

0093

3.   For “select account for this component” Select a account which has full permission

Hope that helps. Happy SharePointing 🙂

Fix for Memory leak by Noderunner.exe


Hi,

Issue: My virtual development machine is allocated 8 GB RAM out of 16 GB of Host. Still it runs very slow. In order to develop things I have to stop the Search service and memory consumption reduced to ~5GB from 6-7GB. But this is just a work around what if I need to build some module which requires Search service.

A quick investigation in Task Manager highlight Memory usage by search components are much large then other processes. Several NodeRunner.exe processes consume lots of Memory and CPU. The culprit processes are Microsoft SharePoint Search component.

image_thumb1

Although there is no problem with just killing the noderunner.exe processes in Task Manager; SharePoint creates them again almost immediately.

Cause:

The architecture of search has undergone lot of changes in SharePoint 2013. Many of the core components are replaced by the FAST Search components. Below are a few new components which are added in the new architecture

  • Crawl Component
  • Content Processing Component
  • Query Processing Component
  • Index Component
  • Analytic Processing Component

All these components run as a process called ‘noderunner.exe’. On a default single server installation of SharePoint there will five instances of noderunner.exe (one for each of the component listed above). There is another process called ‘Host Controller’, which monitors the noderunner processes. If any of the noderunner.exe fails, the host runner will restart that process.

Resolution:

1. Open SharePoint 2013 Management Shell and type in:

             Set-SPEnterpriseSearchService -PerformanceLevel Reduced

image_thumb2

2. To ensure the setting has been changed enter the following command:

Get-SPEnterpriseSearchService

image_thumb3

3. Open NodeRunner process configuration file below in Notepad

C:\Program Files\Microsoft Office Servers\15.0\Search\Runtime\1.0\noderunner.exe.config.
Update <nodeRunnerSettings memoryLimitMegabytes=”0″ />.
This is the configuration to limit NodeRunner process memory usage, replace 0 to acceptable number like 100 or 250.

image_thumb4

image_thumb6

4. Restart SharePoint Search Host Controller service. Better if it is possible to restart the server.

Conclusion:

Search has become the most integral part in SharePoint 2013 now. So, it’s not a good idea to stop search service or any of its component. But one can limit the memory usage or reduce the performance level for Search Service. By default the performance level for a Search Service is set to Maximum.

Happy SharePointing 🙂 !!

Allow anonymous access


Hi all,

As per one of my project requirement, I need to configure SharePoint 2013 sites to be accessed by anonymous users. So I had configured the anonymous access on SP 2013 web application and documenting steps below which are required to configure anonymous access to an existing SharePoint 2013 site.

1. Please navigate to the SharePoint 2013 Central Administration > Application Management section, click the “Manage web applications” link.

2. Now from the list of the web applications opened, click on one of the available web applications and find “Authentication providers” button from Ribbon. It will pop up a modal dialog showing the authentication providers available per zone is displayed. The basic scenario was set at time of web application creation is only displayed there as “Default” zone.

Untitled

3. Click the “Default” link so a new modal dialog is displayed. Just check the “Enable anonymous access” option and press the “Save” button.

02.png

4. Till this step, we have enabled the anonymous access at web application level, but in order to implement this fully, navigate to one of the site collections created under the configured web application and go to “Site Actions-> Site Settings”. Under the “Users and permissions” section, click the “People and groups” link.

03.png

5. On this screen, SharePoint 2013’s Ribbon display is an “Anonymous Access” button that allows user to configure how anonymous users can access to the site.

04.png

6. Press the “Anonymous Access” button in the Ribbon so the related configuration modal dialog is shown. In this dialog you have three configuration options, just click the first one that provides full anonymous access to the site. Press the “OK” button.

05.png

7. Navigate back to the “People and Groups” page, check there is a new group called “Anonymous users” available in the list.

06.png

8. This is the final step. To verify and finish, close all the instances of the browser and start a new instance. Type the Url of the site collection and check that user don’t need to provide credentials information since anonymous access is enabled on the entire site.

That’s all about how to enable anonymous access to a SharePoint 2013 site.

Happy SharePointing!

 

Clear SharePoint Config Cache with PowerShell


Hi,

In my previous post, I have explained about issue “An update conflict has occurred, and you must re-try this action”. That issue occurs because of cache issues. I have already explained the manual way to clear cache. In this blog, I do same thing using the poweshell script. Following code of PowerShell will clear the cache of the server:

Add-PSSnapin -Name Microsoft.SharePoint.PowerShell –erroraction SilentlyContinue

Stop-Service SPTimerV4
$folders = Get-ChildItem C:\ProgramData\Microsoft\SharePoint\Config
foreach ($folder in $folders)
{
$items = Get-ChildItem $folder.FullName -Recurse
foreach ($item in $items)
{
if ($item.Name.ToLower() -eq “cache.ini”)
{
$cachefolder = $folder.FullName
}

}
}
$cachefolderitems = Get-ChildItem $cachefolder -Recurse
foreach ($cachefolderitem in $cachefolderitems)
{
if ($cachefolderitem -like “*.xml”)
{
$cachefolderitem.Delete()
}

}

$a = Get-Content  $cachefolder\cache.ini
$a  = 1
Set-Content $a -Path $cachefolder\cache.ini

read-host “Do this on all your SharePoint Servers – and THEN press ENTER”
start-Service SPTimerV4

Thanks and Happy SharePointing 🙂

 

SharePoint: An update conflict has occurred, and you must re-try this action


Hi,

I have faced this issue while trying to modify list items of a list. This issue encounters if the file system cache content on the SharePoint server is newer than the content present in the configuration database. One have to clear the cache manually to get rid of this issue. Sometimes it get solved by restarting, if luck is with you, otherwise this issue will always bugs.

Timer service restart could be one another option to try. But recommend you must follow one of the two possible ways to solve this issue:

I. Manual Steps:

  1. Need to stop the SharePoint Timer service: Navigate to Start > Administrative Tools > Servicesor go to run(Windows+R) command and type msc.
  2. Locate the SharePoint Timer Service, and right click on this service and click on Stop
  3. Close the Services window (In case you are performing these actions on Production/Test. Do this on each front end server)
  4. In Windows Explorer, locate and then double-click the following hidden folder.

Drive:\ProgramData\Microsoft\SharePoint\Config\GUID

Note:

  • There may be two folders with a GUID name in the config directory.  One has persisted files in it.  You will be working with the one that has XML files and a cache.ini file in it. The Drive placeholder specifies the letter of the drive on which Windows is installed. By default, Windows is installed on drive C.
  • The GUID placeholder specifies the GUID folder.
  • The ProgramData folder may be hidden. To view the hidden folder, Navigaete to Tools > Folder Options > View Tab > Advanced settings. Click Show hidden files and folders under Hidden files and folders, and then click OK.
  1. Take a Backup of the ini file.
  2. Delete all the XML configuration files in the GUID folder. Do this so that you can verify that the GUID folder is replaced by new XML configuration files when the cache is rebuilt.

Note When you empty the configuration cache in the GUID folder, make sure that you do not delete the GUID folder and the Cache.ini file that is located in the GUID folder.

  1. Now delete all contents of Cache.ini. Double-click the Cache.ini file to open it. Click on the Edit menu, click Select All and click Delete.
  2. Type 1, and then click Saveon the File menu.
  3. On the Filemenu, click Exit.
  4. Start the Timer service. To do this, follow these steps: Navigate to Start > Administrative Tools > Servicesor go to run(Windows+R) command and type msc.
  5. Locate the SharePoint Timer Service, and right click on this service and click on Start

Note The file system cache is re-created after you perform this procedure. Make sure that you perform this procedure on all servers in the server farm.

  1. Make sure that the Cache.ini file has been updated. For example it should no longer be 1 if the cache has been updated.

II. Clear SharePoint Config Cache with PowerShell.

Both methods does same thing, choice is all yours depending upon the comparability, permissions, time  and of course ease.

Happy SharePointing 🙂