Do you know the SharePoint 2016 "Zombie ItemID Cache Bug"? - javascript

After migrating various SharePoint 2013 JavaScript apps to SharePoint 2016, I had to look at an strange phenomenon of the SharePoint 2016 Rest API:
assume you have 2 ajax calls
Upload a file --> returns spFile
get the list item for the uploaded file --> returns spItem
jQuery.ajax({
url: "/sites/mysite/_api/web/getFolderByServerRelativeUrl('/sites/mySite/myLibrary')/files/add(overwrite=true, url='test1.txt')",
type: "POST",
data: params.arraybuffer,
processData: false,
headers: { "Accept": "application/json;odata=verbose", "X-RequestDigest": params.digest, "X-HTTP-Method": "POST","If-Match": "*" },
success: function (file) {
//get listItem for uploaded file
jQuery.ajax({
url: file.d.ListItemAllFields.__deferred.uri,
type: "GET",
headers: { "accept": "application/json;odata=verbose" },
success: function (result) {
//after first upload: OK
var id = result.d.ID;
}
});
}
});
If the file has not yet existed under this URL, everything is OK. SharePoint creates a new list item, and you will get the new item with the correct ID in the second call - lets assume we get ID 1.
If a file with the same name was already existing under this url and later it was deleted, SharePoint generates a new item with a new ID. This is as expected.
BUT: In this case, the SharePoint Rest API returns the wrong list item. Instead of the new created list item (ID 2), you will get the old deleted item with ID 1.
In SharePoint 2013, this error does not occur. In SharePoint 2016 - this error only occurs in case of the same browser context for ajax call 1 and ajax call 2. Typically you are affected by this error, if you upload a file und at the same time you will update some meta values.
It seems to be a bug in SharePoint 2016. I suppose, MS have implemented a more strictly cache algorithm and was getting over the target.

Until MS will fix this bug, I have found a workaround:
Upload your file under a temporary name - jQuery.Guid.New() + myExtension
get the new item for your uploaded file
send a call to delete an possibly existing file with the real target name
rename your uploaded file into the real target name
var real_filename = 'test1.txt';
var temp_filename = jQuery.Guid.New() + '.txt';
// upload temp_filename instead real filename - fixes SharePoint 2016 ZombieId CacheBug
jQuery.ajax({
url: "/sites/mySite/_api/web/getFolderByServerRelativeUrl('/sites/mySite/myLibrary')/files/add(overwrite=true, url='" + temp_filename + "')",
type: "POST",
data: params.arraybuffer,
processData: false,
headers: { "Accept": "application/json;odata=verbose", "X-RequestDigest": params.digest, "X-HTTP-Method": "POST","If-Match": "*" },
success: function (file) {
//delete a possiblly existing file with real target name
jQuery.ajax({
url: "/sites/mySite/_api/web/GetFileByServerRelativeUrl('/sites/mySite/myLibrary/" + real_filename + "')",
type: "POST",
processData: false,
headers: { "Accept": "application/json;odata=verbose", "X-RequestDigest": params.digest, "X-HTTP-Method": "DELETE", "If-Match": "*" },
success: function () {
//target file was existing
finalize(file);
},
error: function () {
//target file was not existing
finalize(file);
}
});
}
});
function finalize(file) {
//get listItem for uploaded file
jQuery.ajax({
url: file.d.ListItemAllFields.__deferred.uri,
type: "GET",
headers: { "accept": "application/json;odata=verbose" },
success: function (result) {
var spItem = result.d;
//rename the uploaded file
jQuery.ajax({
url: spItem.__metadata.uri,
type: "POST",
data: JSON.stringify({ __metadata: { 'type': spItem.__metadata.type }, FileLeafRef: real_filename }),
headers: { "Accept": "application/json;odata=verbose", "X-RequestDigest": params.digest, "content-type": "application/json;odata=verbose", "X-HTTP-Method": "MERGE", "If-Match": "*" },
success: function () {
//file was renamed
spItem.FileLeafRef = real_filename;
defer.resolve(spItem);
},
error: function (e) {
//something went wrong
defer.resolve(null, e);
}
});
}
});
}

Related

How to get the Excel-File id using the filename in microsoft-graph api?

I am trying to get the File Id using the filename in graph API
I have tried the following thing but this is not working
https://graph.microsoft.com/v1.0/sites/ccc.sharepoint.com,dddddd,eeeeeeeeeeeeeeee/drive/root:/excelDir/filename.xlsx:/children
Got the answer
https://graph.microsoft.com/v1.0/sites/"+webAndSiteId+"/drives/"+folderID+"/root/search(q='filename.xlsx')
Below is the working javascript
var fileCollectionEndpoint = "https://graph.microsoft.com/v1.0/sites/"+webAndSiteId+"/drives/"+folderID+"/root/search(q='"+fileNamesArray[index]+"')"
$.ajax({
url: fileCollectionEndpoint,
async: false,
dataType: 'json',
type: "GET",
cache:false,
headers: {
'Authorization':'Bearer '+token,
},
success: function (json) {
console.log(json.value[0].id);
},
error:function(xhr)
{
}
});

Cannot unlocked android key with Phonegap API

Hhi, i try to unlock my android keys with the phonegap WRITE API and more precisely with this method: https://build.phonegap.com/api/v1/keys/android/257852?auth_token=mytoken
This method returns :
{
"id":257852,
"title":"****",
"platform":"android",
"created_at":"2017-07-06 01:42:56 -0700",
"last_used":"2017-07-11 06:00:33 -0700",
"link":"/api/v1/keys/android/257852",
"default":false,
"alias":"****",
"locked":true
}
The problem is that suddenly my key is not unlock as you can see in the return and also on the web interface of build.
I do this request with javascript and jquery ajax :
$.ajax({
url: "https://build.phonegap.com/api/v1/keys/android/257852",
beforeSend: function(xhr) {
xhr.setRequestHeader("Authorization", "Basic " + btoa("username:password"));
},
type: 'PUT',
dataType: 'json',
contentType: 'application/json',
processData: false,
data: '{"key_pw":"pass","keystore_pw":"pass"}',
success: function (data) {
alert(JSON.stringify(data));
},
error: function(){
alert("Cannot get data");
}
});
I do not understand what i do wrong...
Thank you for your help and sorry for my bad english !
EDIT :
Ok my bad.. i just give this to data field :
data: '{"key_pw":"pass","keystore_pw":"pass"}',
and API need something like that :
data: 'data={"key_pw":"pass","keystore_pw":"pass"}',

JSON ajax post data - get 400 bad request message

First of all. I read many questions about this problem here in stackoverflow but nothing helps me.
I've this function:
function ip_login(){
//alert(JSON.stringify(arr_login));
$.ajax({
crossdomain: true,
url: 'https://****/Token',
type: 'POST',
data: JSON.stringify(arr_login),
contentType: 'application/x-www-form-urlencoded',
dataType: 'json',
success: function (data) {
console.log(data);
}
});
}
And this is my JSON string:
{"grant_type":"password","username":"mail#mail.de","password":"blabla"}
With the google chrome extension 'postman' it works fine!
If I test my code above I got the popular 400 bad request message.
When I take the code of the extension 'postman' it doesn't work too.
This is the code of postman:
var settings = {
"async": true,
"crossDomain": true,
"url": "https://*****/Token",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"data": {
"grant_type": "password",
"username": "mail#mail.de",
"password": "blabla"
}
}
$.ajax(settings).done(function (response) {
console.log(response);
});
I can't fine my issue..
I searched on Google and SO but no reply helped me.
Edit:
This is in my console:
"NetworkError: 400 Bad Request - https://awesome-url.de/Token"
The problem is in stringifiing JSON. Server expects json but you send string(stringified JSON). Try
function ip_login(){
//alert(JSON.stringify(arr_login));
$.ajax({
crossdomain: true,
url: 'https://****/Token',
type: 'POST',
data: arr_login,
contentType: 'application/x-www-form-urlencoded',
dataType: 'json',
success: function (data) {
console.log(data);
}
});
}
Not sure if this helps, but try anyways.
When I'm sending Json, I didn't use "JSON.stringify(arr_login)"
All I did was something like "data:{arr_login:arr_login}"
This is how my variable looks like.
var req = new Object();
req["type"] = 'refresh';
req["time"] = window.page_ordertime;
This is how my ajax looks like
$.ajax( {
url:"listorder_process.php",
method: "POST",
dataType:"json",
data:{request:req}
} )

Using Dropbox v2 API from Browser

I'm trying to upload data to dropbox via webbrowser (FF 42.0, PhantomJS 1.9.8) and dropbox v2 api. My function looks like this
function(path, data, callback) {
$.ajax({
url: 'https://content.dropboxapi.com/2/files/upload',
type: 'post',
contentType: 'application/octet-stream',
beforeSend: function(jqXHR) {
jqXHR.setRequestHeader("Content-Type","application/octet-stream");
},
data: data,
headers: {
"Authorization": "Bearer " + token,
"Dropbox-API-Arg": '{"path": "' + path + ',"mode": "add","autorename": true,"mute": false}',
"Content-Type": "application/octet-stream"
},
success: function (data) {
callback(data);
}
});
}
Even I set the Content-Type at all attributes I can think of to application/octet-stream I get the following error
Error in call to API function "files/upload": Bad HTTP "Content-Type" header: "application/octet-stream
; charset=UTF-8". Expecting one of "application/octet-stream", "text/plain; charset=dropbox-cors-hack"
Taking a look at the request in Firebug shows me that the Content-Type was really set to application/octet-stream; charset=UTF-8. When trying text/plain; charset=dropbox-cors-hack as Content-Type the sent request has text/plain; charset=UTF-8, and I get the same error message.
How can I make jquery and my browser to set the headers I need.
EDIT: Same behavior in Chrome
IE works as expected
Technically, Firefox is just adhering to the W3C XMLHttpRequest spec:
http://www.w3.org/TR/XMLHttpRequest/#the-send()-method
Sending anything other than a Blob or ArrayBufferView can cause issues with browsers attempting to encode the data in UTF-8 (to follow the spec).
The right thing to do here is to avoid sending data as a String. Here are two examples of how to avoid this behavior:
// ... file selected from a file <input>
file = event.target.files[0];
$.ajax({
url: 'https://content.dropboxapi.com/2/files/upload',
type: 'post',
data: file,
processData: false,
contentType: 'application/octet-stream',
headers: {
"Authorization": "Bearer " + ACCESS_TOKEN,
"Dropbox-API-Arg": '{"path": "/test_ff_upload.txt","mode": "add","autorename": true,"mute": false}'
},
success: function (data) {
console.log(data);
}
})
Or, if you want to send up text, you can UTF-8 encode the text before uploading yourself. A modern way to do this is using TextEncoder:
var data = new TextEncoder("utf-8").encode("Test");
$.ajax({
url: 'https://content.dropboxapi.com/2/files/upload',
type: 'post',
data: data,
processData: false,
contentType: 'application/octet-stream',
headers: {
"Authorization": "Bearer " + ACCESS_TOKEN,
"Dropbox-API-Arg": '{"path": "/test_ff_upload.txt","mode": "add","autorename": true,"mute": false}'
},
success: function (data) {
console.log(data);
}
})
Try this...
private void upload(object sender, EventArgs e)
{
OAuthUtility.PutAsync
(
"https://content.dropboxapi.com/1/files_put/auto/",
new HttpParameterCollection
{
{"access_token",Properties.Settings.Default.AccessToken},
{ "path", Path.Combine(this.CurrentPath, Path.GetFileName(openFileDialog1.FileName)).Replace("\\", "/") },
{ "overwrite","false"},
{ "autorename","false"},
{openFileDialog1.OpenFile()}
},
callback : Upload_Result
);
}

Javascript with SharePoint 2013 REST Endpoint "INSERT" into List?

Here are what i'm going to use:
SharePoint 2013
Javascript
REST Endpoint
SharePoint List (called: "Announcements")
WebSite (called: "example.com")
Refs:
http://www.plusconsulting.com/blog/2013/05/crud-on-list-items-using-rest-services-jquery/
https://msdn.microsoft.com/EN-US/library/dn292552.aspx
Very simply:
How do i INSERT a new item (row) inside the List please?
I tried:
$.ajax({
url: "https://example.com/_api/web/lists/getbytitle('Announcements')/items",
type: "POST",
contentType: "application/json;odata=verbose",
data: JSON.stringify( { '__metadata': { 'type': 'SP.Data.AnnouncementListItem' }, "Title": "New Announcement!" } ),
headers: {
"Accept": "application/json;odata=verbose",
"Authorization": "Bearer " + accessToken
"X-RequestDigest": form digest value,
"IF-MATCH": etag,
},
success: function (data) {
console.log(data);
},
error: function (data) {
console.log(data);
}
});
Then i know a lot of things go wrong especially in headers section. But what does it mean by:
Authorization
accessToken
X-RequestDigest
IF-MATCH
.. and then HOW TO get these values (with JavaScript)? So that:
What are always the exact required fields there?
And how/where to get these values from?
I still can not find a simple and complete example about doing this Update / Insert properly.
So there are two ways that I have used to submit an item to a list, the jQuery library SPServices and REST API's. SPServices is really well documented here. Using REST API's is much faster and pretty easy too!
function createListItem(itemProperties, success, failure) {
$.ajax({
url: "https://example.com/_vti_bin/listdata.svc/Announcements",
type: "POST",
processData: false,
contentType: "application/json;odata=verbose",
data: JSON.stringify(itemProperties),
headers: {
"Accept": "application/json;odata=verbose"
},
success: function(data) {
success(data.d);
},
error: function(data) {
// failure(data.responseJSON.error);
alert("error");
}
});
}
First thing I am doing above is creating a function that you can call whenever you want to create a new list item. The parameter itemProperties can be populated with the fields which you need, see below.
var Title = "Title";
var Answer = "Answer";
var userid = _spPageContextInfo.userId;
var taskProperties = {
'Title': Title,
'Answer': Answer,
'UserId': userid
};
Then all we have to do is call this function with the new variable we just declared.
createListItem(taskProperties, function(task) {
alert("Thank you for your input!");
},
function(error) {
console.log(JSON.stringify(error));
}
);
Actually jsfiddle which you have posted in the previous commend is not the REST . you just use the SharePoint client object model. find below the REST API model I hope it will work
var cat = {
"__metadata": { "type": ItemType },
"Title": "GenIT-Issue",
}
$.ajax({
url: _spPageContextInfo.siteAbsoluteUrl + "/_api/web/lists/getbytitle('Tickets')/items",
type: "POST",
contentType: "application/json;odata=verbose",
data: JSON.stringify(cat),
headers: {
"Accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val()
},
success: function (data) {
},
error: function (data) {
}
});
I run this code inside my SharePoint page so there is no authentication required. it will run on current user privilege

Categories