Is it possible to add notes to cells using Google? Apis.Sheets.v4?
It seems possible in python: Is it possible to use the Google Spreadsheet API to add a comment in a cell? but I've had no success duplicate it to c#, Insert a comment in a Google Sheet with google-sheets-api describes how to add it using an https call, but I would much rather use the google c# library than start sending HTTP calls myself if at all possible.
It would be a huge help if anyone know-how, or can point me towards a working example.
Thanks in advance.
Using Rafa Guillermos advice i got it to work.
public async void AddNote(string sheet, int column, int row, int sheetId, string noteMessage)
{
await Task.Delay(1);
var requests = new List<Request>();
// Grid range for a single cell, end column, and row have to be +1, otherwise, sheet throws error trying to write outside bounds.
var gridRange = new Google.Apis.Sheets.v4.Data.GridRange
{
EndColumnIndex = column + 1, StartColumnIndex = column, EndRowIndex = row + 1, StartRowIndex = row, SheetId = sheetId
};
// Building a request for update cells.
var request = new Google.Apis.Sheets.v4.Data.Request();
request.UpdateCells = new Google.Apis.Sheets.v4.Data.UpdateCellsRequest();
request.UpdateCells.Range = gridRange;
request.UpdateCells.Fields = "note";
request.UpdateCells.Rows = new List<Google.Apis.Sheets.v4.Data.RowData>();
request.UpdateCells.Rows.Add(new Google.Apis.Sheets.v4.Data.RowData());
request.UpdateCells.Rows[0].Values = new List<Google.Apis.Sheets.v4.Data.CellData>();
request.UpdateCells.Rows[0].Values.Add(new Google.Apis.Sheets.v4.Data.CellData());
request.UpdateCells.Rows[0].Values[0].Note = noteMessage;
requests.Add(request);
var requestBody = new Google.Apis.Sheets.v4.Data.BatchUpdateSpreadsheetRequest();
requestBody.Requests = requests;
var service = _authenticatorService.GetSheetsService(new[] { SheetsService.Scope.Spreadsheets} );
var batchRequest = service.Spreadsheets.BatchUpdate(requestBody, _spreadsheetId);
batchRequest.Execute();
}
_authenticatorService gives an authenticated sheet service to work with.
Answer:
In exactly the same way as python, you need to build your note as a batch request in C#.
Code Snippets:
You need to build your data request as list like:
List<Data.Request> requests = new List<Data.Request>();
and assign the values to the request body for the batch:
Data.BatchUpdateSpreadsheetRequest requestBody = new Data.BatchUpdateSpreadsheetRequest();
requestBody.Requests = requests;
before building the request object:
SpreadsheetsResource.BatchUpdateRequest request = sheetsService.Spreadsheets.BatchUpdate(requestBody, spreadsheetId);
and execute the request:
Data.BatchUpdateSpreadsheetResponse response = request.Execute();
More Information:
You can read about spreadsheets.batchUpdate here with a C# example code at the bottom of the page here.
A JSON representation of the request resource can be found here which follows the same structure as the answer you linked here.
References:
Sheets API v4 - spreadsheets.batchUpdate
Example code for spreadsheets.batchUpdate
Sheets API v4 - JSON Representation of Batch Request
Stack Overflow - Is it possible to use the Google Spreadsheet API to add a comment in a cell?
Related
I'm trying to add a new column to a site using MS Graph API. I followed the docs, which shows a Text column example, and that works. When I try to add a Term column I get an invalid request. Does anyone have any insight as to what I've done wrong?
See my code below.
var columnDef = new ColumnDefinition
{
DisplayName = "Tag",
EnforceUniqueValues = false,
Hidden = false,
Indexed = false,
Name = "Tag",
Term = new TermColumn
{
ShowFullyQualifiedName = false,
AllowMultipleValues = false
}
};
await graphAPIAuth.Sites[site.Id].Columns
.Request()
.AddAsync(columnDef);
The graph api doesn't currently support creating columns for any type fields other than plain text, I suggest you submit user voice to add support for other types of fields, I'll upvote for you.
I have an Excel file loaded into Office 365 that is accessible via the Microsoft Graph API with many named ranges, some are individual values, some are blocks of cells.
I can successfully update individual values using the API, but when I try to update multiple cells at the same time, I run into problems.
For this example, consider a single 3-cell array from F10:F12
I would like to populate as follows:
F10 = A
F11 = B
F12 = C
So, I create list of strings that ends up looking like this...
[ ["A"], ["B"], ["C"] ]
and I pass it to the Graph API using the following code...
public static async Task<WorkbookRange> UpdateRangeArray(string strItemId, string strSheetName, string strRangeName, List<string> strRangeValues, string strSessionId)
{
string[][] strValueArray = new string[strRangeValues.Count][];
try
{
int i = 0;
foreach (var val in strRangeValues)
{
strValueArray[i] = new string[1] { val };
i++;
}
}
var jsonValueArray = JsonConvert.SerializeObject(strValueArray);
var rangeUpdate = new Microsoft.Graph.WorkbookRange();
rangeUpdate.Values = jsonValueArray;
var result = await graphClient.Users[_strUserId].Drive.Items[strItemId].Workbook.Worksheets[strSheetName]
.Range(strRangeName)
.Request()
.Header("workbook-session-id", strSessionId)
.PatchAsync(rangeUpdate).ConfigureAwait(false);
return result;
}
So I am able to update the values in the range, EXCEPT instead of the expected values, what I get is this...
F10 = [ ["A"],["B"],["C"] ]
F11 = [ ["A"],["B"],["C"] ]
F12 = [ ["A"],["B"],["C"] ]
Instead of the Graph API putting the first value in the first cell, second value in the second cell, and so forth... It puts the entire array of data in each cell.
I assume this is some sort of formatting error, maybe my JSON is malformed or perhaps I'm submitting it using the wrong Graph API endpoint or something.
Any help would be greatly appreciated...
UPDATE 1:
I also tried doing this with the RANGE (ie - .Range("F10:F12")) instead of using the NAME and I get the same result.
UPDATE 2:
Cross-posted on GitHub in case this is a bug not just a user error.
https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/695
UPDATE 3:
I can successfully PATCH via the Graph API Explorer to the following URL...
https://graph.microsoft.com/v1.0/me/drive/items/{item-id}/workbook/worksheets/INPUTS/range(address='F10:F12')
with this body...
{"values":[["Hello"],["How"],["Are You?"]]}
...and it works.
but still can't get it to work via the MSGraph-SDK-dotnet
UPDATE 4:
I AM able to get it to work correctly using Postman and the resulting RestSharp code that works looks like this...
public static async Task TestUpdatePostman()
{
var client = new RestClient("https://graph.microsoft.com/v1.0/users/{USER-ID}/drive/items/{ITEM-ID}/workbook/worksheets/INPUTS/range(address='F10:F12')");
client.Timeout = -1;
var request = new RestRequest(Method.PATCH);
request.AddHeader("Authorization", "Bearer {INSERT-TOKEN}");
request.AddHeader("Content-Type", "application/json");
request.AddParameter("application/json", "{\"values\":[[\"Hello\"],[\"How\"],[\"Are You?\"]]}", ParameterType.RequestBody);
IRestResponse response = client.Execute(request);
Console.WriteLine(response.Content);
}
This again makes me believe there's an issue with the way the SDK wrapper implements the API call.
It might not be a SDK issue. When updating the range, rangeUpdate.Values should be a JToken type instead of a string.
Try using:
JArray jsonValueArray = JArray.FromObject(strValueArray);
I have a spreadsheet on Google Drive with 571 rows that I read from an other application. I call it using the Google.GData.Spreadsheets 2.2.0 lib and the following piece of simplified code.
static void Main(string[] args)
{
var certificate = new X509Certificate2("Key.p12", "blahblah", X509KeyStorageFlags.Exportable);
const string user = "blahblah#developer.gserviceaccount.com";
var serviceAccountCredentialInitializer =
new ServiceAccountCredential.Initializer(user)
{
Scopes = new[] { "https://spreadsheets.google.com/feeds" }
}.FromCertificate(certificate);
var credential = new ServiceAccountCredential(serviceAccountCredentialInitializer);
if (!credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Result)
throw new InvalidOperationException("Access token request failed.");
var requestFactory = new GDataRequestFactory(null);
requestFactory.CustomHeaders.Add("Authorization: Bearer " + credential.Token.AccessToken);
var service = new SpreadsheetsService(null) { RequestFactory = requestFactory };
var query = new ListQuery("https://spreadsheets.google.com/feeds/list/blahblah/1/private/full") ;
var feed = service.Query(query);
// Not all rows 571 rows are returned. Only 369 feed.Entries !?
}
My problem is that even if I have 571 rows in the document I only receive the first 369 entries back - why is that? Is there a limitation in the api for how many rows a spreadsheet can return? If so, how should I handle that?
I've double checked and the uri points to the right spreadsheet document and all the rows are on the first sheet of the document. It actually looks like the even a ordinary http get to https://spreadsheets.google.com/feeds/list/blahblah/1/private/full doesn't return all the rows?
What am I missing here?
Turned out that I had an empty row in the sheet and the API won't read new rows after that.
I am using the Google C# API for the Custom Search and have it working and returning results, however I cannot see a way to make the paging work correctly.
Looking at what I get returned, no where does it tell me how many pages there are in the result? It just has a .Start property? Which is not much good unless I know how many 'pages' of results I have?
Am I missing something stupid here? Here is an example of the code I have so far
var svc = new CustomsearchService(new BaseClientService.Initializer { ApiKey = settings.GoogleCustomSearchApi });
var listRequest = svc.Cse.List(searchTerm);
listRequest.Cx = settings.GoogleCustomSearchEngineId;
listRequest.ImgSize = CseResource.ListRequest.ImgSizeEnum.Medium;
listRequest.Num = 10;
// List to hold everything in
var resultItems = new List<Google.Apis.Customsearch.v1.Data.Result>();
// Result set 1
listRequest.Start = 1;
var search = listRequest.Execute();
resultItems.AddRange(search.Items);
I have resulted at the moment to doing two or three calls one after the other and getting a load of results back. But I would prefer to have this properly paged.
The JSON API response has totlResults field:
https://developers.google.com/custom-search/json-api/v1/reference/cse/list#response.
It should be exposed under search.Queries
Found it, its in
search.SearchInformation.TotalResults
I'm struggling with the final part of getting my first bit of code working with the AWS - I have got this far, I attached the web reference in VS and this have this
amazon.AWSECommerceService service = new amazon.AWSECommerceService();
// prepare an ItemSearch request
amazon.ItemSearchRequest request = new amazon.ItemSearchRequest();
request.SearchIndex = "DVD";
request.Title = "scream";
request.ResponseGroup = new string[] { "Small" };
amazon.ItemSearch itemSearch = new amazon.ItemSearch();
itemSearch.AssociateTag = "";
itemSearch.Request = new ItemSearchRequest[] { request };
itemSearch.AWSAccessKeyId = ConfigurationManager.AppSettings["AwsAccessKeyId"];
itemSearch.Request = new ItemSearchRequest[] { request };
ItemSearchResponse response = service.ItemSearch(itemSearch);
// write out the results
foreach (var item in response.Items[0].Item)
{
Response.Write(item.ItemAttributes.Title + "<br>");
}
I get the error
The request must contain the parameter Signature.
I know you have to 'sign' requests now, but can't figure out 'where' I would do this or how? any help greatly appreciated?
You have to add to the SOAP request headers including your Amazon access key ID, a timestamp, and the SHA256 hash of the request operation and the timestamp. To accomplish that, you would need access to the SOAP message just before it is going to be sent out. There's a walkthrough and a sample project I put together at http://flyingpies.wordpress.com/2009/08/01/17/.
For the record:
Another reason to get this error is due to keywords with spaces in it.
Example:
'http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=xxx&AssociateTag=usernetmax-20&Version=2011-08-01&Operation=ItemSearch&ResponseGroup=Medium,Offers&SearchIndex=All&Keywords=Baby
Stroller&MerchantId=All&Condition=All&Availability=Available&ItemPage=1&Timestamp=2012-05-16T02:17:32Z&Signature=ye5c2jo99cr3%2BPXVkMyXX8vMhTC21UO4XfHpA21%2BUCs%3D'
It should be:
'http://ecs.amazonaws.com/onca/xml?Service=AWSECommerceService&AWSAccessKeyId=xxx&AssociateTag=usernetmax-20&Version=2011-08-01&Operation=ItemSearch&ResponseGroup=Medium,Offers&SearchIndex=All&Keywords=Baby%20Stroller&MerchantId=All&Condition=All&Availability=Available&ItemPage=1&Timestamp=2012-05-16T02:17:32Z&Signature=ye5c2jo99cr3%2BPXVkMyXX8vMhTC21UO4XfHpA21%2BUCs%3D'
PHP solution:
$Keywords = str_replace(' ', '%20', $Keywords);
or
$Keywords = urlencode($Keywords);