This question is related to Google Sheets API (C#).
I have to write more than 1000 rows into a Google sheet, therefore I need to increase the number of rows (I got the Google.Apis.Requests.RequestError when I attempted to write 4640 rows).
Searching the Stack Overflow website resulted in information telling me that I needed to use UpdateSheetPropertiesRequest or InsertDimensionRequest and create a new request that could be in the same Spreadsheets.BatchUpdate call.
In line with this Python example, I set the properties of the InsertDimensionRequest instance and included them in my existing code (= publicly available C# code by Ian Preston).
The code then looks like this:
public void AddCells(GoogleSheetParameters googleSheetParameters, List<GoogleSheetRow> rows)
{
var requests = new BatchUpdateSpreadsheetRequest { Requests = new List<Request>() }; //Existing code
int sheetId = GetSheetId(_sheetsService, _spreadsheetId, googleSheetParameters.SheetName); //Existing code
InsertDimensionRequest insertDimensionRequest = new InsertDimensionRequest(); //Added code
insertDimensionRequest.Range.SheetId = sheetId; //Added code
insertDimensionRequest.Range.Dimension = "ROWS"; //Added code
insertDimensionRequest.Range.StartIndex = 999; //Added code
insertDimensionRequest.Range.EndIndex = 6999; //Added code
insertDimensionRequest.InheritFromBefore = false; //Added code
var request = new Request { UpdateCells = new UpdateCellsRequest { Start = gc, Fields = "*" } }; //Existing code
//some code here
var request1 = new Request { ???????? }; //code to be added - how should the request look like?
requests.Requests.Add(request); //Existing code
requests.Requests.Add(request1); //Added code
}
But I do not know how a new request can be created in C#.
My question is: How to create such an request (named as request1 in my code)?
Meanwhile, I have managed to figure out an answer.
DimensionRange dr = new DimensionRange
{
SheetId = sheetId,
Dimension = "ROWS",
StartIndex = 999,
EndIndex = 6999 // adding extra 6000 rows
};
var request1 = new Request { InsertDimension = new InsertDimensionRequest { Range = dr, InheritFromBefore = false } };
And then (the order of the requests matters):
requests.Requests.Add(request1);
requests.Requests.Add(request);
EDIT 01-06-2022: The entire code using the aforementioned snippet can be downloaded from GitHub - see the GoogleSheets project there.
It is also possible to use userEnteredValue. This clears the sheet and, for me inexplicably, sets the number of rows to an unknow value, but my 4640 rows were accepted.
EDIT 31-05-2022: If you know more about the usage of userEnteredValue, feel free to elaborate on this matter.
GridRange dr2 = new GridRange
{
SheetId = sheetId
};
var request2 = new Request { UpdateCells = new UpdateCellsRequest { Range = dr2, Fields = "userEnteredValue" } };
And then (the order of the requests probably also matters):
requests.Requests.Add(request2);
requests.Requests.Add(request);
Related
Since a few days I have been using Youtube's (Google's) API 3.0 (.NET Google API Library)
Everything was going smooth until I stumbled across a problem. I've tried many methods to figure out why I got a low amount of info from my results.
What I am trying in the code down below, is requesting the first comment on a video.
Then with that first comment (CommentThread), I am trying to retrieve all the replies of users that reacted on this comment.
I have tried getting information before, it works fine. I could loadup the entire comment section. Except for more than 5 replies per CommentThread. (CommentThread is basicly a comment under a video, where some have replies.)
This is my code, I have modified it alot of times, but from the looks of it. This one should work.
private static void searchReplies()
{
int count = 0;
YouTubeService youtube = new YouTubeService(new BaseClientService.Initializer() { ApiKey = Youtube.API.KEY });
List<string[]> comments = new List<string[]>();
var commentThreadsListRequest = youtube.CommentThreads.List("snippet,replies");
commentThreadsListRequest.VideoId = Youtube.Video.ID;
commentThreadsListRequest.Order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
commentThreadsListRequest.MaxResults = 1;
var commentThreadsListResult = commentThreadsListRequest.Execute();
foreach (var CommentThread in commentThreadsListResult.Items)
{
var commentListRequest = youtube.Comments.List("snippet");
commentListRequest.Id = CommentThread.Id;
var commentListResult = commentListRequest.Execute();
foreach (var Item in commentListResult.Items)
{
CommentThreadIDs.Add(Item.Id);
}
MessageBox.Show("COUNT:" + CommentThread.Replies.Comments.Count);
foreach (var Reply in CommentThread.Replies.Comments)
{
CommentThreadIDs.Add(Reply.Id);
}
}
}
I have checked my API and the video ID. They are all fine as I can request alot of other information.
I have tested this with several videos, but all videos where the first comment have more than 5 replies, it fails to get them all.
The result (Message Box with "Count:") I get (the amount of replies I get in CommentThread.Replies.Comments is 5. No matter what I do. Going to next page with a token does not work either as it is empty.
Does anyone know why it only returns 5 comments instead of more?
I found the answer with help of someone.
The problem was that I set the ID of a commentThread to a comment ID.
Instead I have to set the commentThread ID to the parent ID.
The following code fully replaces my old code if anyone ever needs it.
YouTubeService yts = new YouTubeService(new BaseClientService.Initializer() { ApiKey = "12345" });
var commentThreadsListRequest = yts.CommentThreads.List("snippet,replies");
commentThreadsListRequest.VideoId = "uywOqrvxsUo";
commentThreadsListRequest.Order = CommentThreadsResource.ListRequest.OrderEnum.Relevance;
commentThreadsListRequest.MaxResults = 1;
var commentThreadResult = commentThreadsListRequest.Execute().Items.First();
var commentListRequest = yts.Comments.List("snippet");
commentListRequest.Id = commentThreadResult.Id;
commentListRequest.MaxResults = 100;
var commentListResult = commentListRequest.Execute();
var comments = commentListResult.Items.Select(x => x.Snippet.TextOriginal).ToList();
I used Google docs to tried to delete some rows in table by use DeleteTableRowRequest but I met exception with specify TableStartLocation property. My code is below:
public static void DeleteRequestGDocs(List<Request> requestsList, int? index2Del)
{
Request request = new Request();
Location tableLocation = new Location();
tableLocation.SegmentId = string.Empty;
tableLocation.Index = 11;
TableCellLocation tableCellLocationDel = new TableCellLocation();
tableCellLocationDel.RowIndex = index2Del;
tableCellLocationDel.ColumnIndex = 0;
tableCellLocationDel.TableStartLocation = tableLocation;
DeleteTableRowRequest delRequest = new DeleteTableRowRequest();
delRequest.TableCellLocation = tableCellLocationDel;
request.DeleteTableRow = delRequest;
requestsList.Add(request);
}
Please help me
Update 1: When program exetute to delete. I met error "Invalid requests[0].deleteTableRow: Invalid table start location. Must specify the start index of the table." with code below
var bodyDelete = new BatchUpdateDocumentRequest();
bodyDelete.Requests = requestsDeleteList;
var batchDeleteRequest = docsService.Documents.BatchUpdate(bodyDelete, mergedFile.Id);
var resultDelete = await batchDeleteRequest.ExecuteAsync();
You should make sure that tableStartLocation in your request matches the value of startIndex for the table you are trying to access in the document you are editing.
The corresponding part of the document JSON with the startIndex should look like the following:
{
"startIndex": 12,
"endIndex": 23,
"table": {...}
},
See related issue in google tracker here: https://issuetracker.google.com/issues/158124540
I am trying to get the total count of api keys in my API gateway via SDK.
However I am unsure on the proper implementation of the parameters that the GetApiKeysRequest takes in. My main objective is to get the count of all API keys that are already existing for my account.
The code I have so far looks like this :
class Program
{
public static void Main(string[] args)
{
var awsUserAccessKey = "xxxxx";
var awsUserSecretKey = "yyyyyyyyyyy";
var regionEndpoint = "us-west-2";
var keysInRepository = new GetApiKeysRequest
{
CustomerId = "",
IncludeValues = true||false,
Limit=0,
NameQuery = "",
Position = ""
};
var client = new AmazonAPIGatewayClient(awsUserAccessKey, awsUserSecretKey, regionEndpoint);
var apiKeys =client.GetApiKeys(keysInRepository);
Console.Read();
}
}
This code throws an error saying that The security token included in the request is invalid (Amazon.APIGateway exception).I am unsure on how to set the parameters for this request.
Because the AmazonAPIGatewayClient you are using as described here takes three string arguments and the last one is awsSessionToken i think you are confusing with this one which takes as third argument RegionEndpoint
Do something like that instead :
var client = new AmazonAPIGatewayClient(awsUserAccessKey, awsUserSecretKey, RegionEndpoint.USWest2);
For someone looking for a solution to similar problems, this worked :
var awsUserAccessKey = "xxxx";
var awsUserSecretKey = "yyyyy";
var regionEndpointName = "us-west-2";
var regionEndpoint = RegionEndpoint.GetBySystemName(regionEndpointName);
var keysInRepository = new GetApiKeysRequest
{
Limit = 500
};
//define the key and its fields
var client = new AmazonAPIGatewayClient(awsUserAccessKey, awsUserSecretKey, regionEndpoint);
var apiKeys = client.GetApiKeys(keysInRepository);
Console.WriteLine("Current number of api keys:{0}", apiKeys.Items.Count);
I'm trying to query the search API of Rally, here is my c# code:
var searchRequest = new Request()
{
ArtifactName = "search",
Limit = 25,
Project = "/project/" + CurrentProject,
ProjectScopeDown = true,
ProjectScopeUp = true,
PageSize = 25,
Fetch = new List<string>() { "true" }
};
searchRequest.AddParameter("keywords", "foo");
QueryResult queryTaskResult = api.Query(searchRequest);
this works as expected and returns result, however i want to pass a parameter of compact=true, which will return slightly different data (mainly a standard web link to the item).
var searchRequest = new Request()
{
ArtifactName = "search",
Limit = 25,
Project = "/project/" + CurrentProject,
ProjectScopeDown = true,
ProjectScopeUp = true,
PageSize = 25,
Fetch = new List<string>() { "true" }
};
searchRequest.AddParameter("keywords", "foo");
///this is the new item
searchRequest.AddParameter("compact", "true");
QueryResult queryTaskResult = api.Query(searchRequest);
However when i fire this request I get the following error
Rally.RestApi.Json.DynamicJsonObject' does not contain a definition for 'Errors'
However when I try to do this request in the browser it works fine.
Any help as to what I'm doing wrong would be greatly appreciated!
Why do you want to do this?
What I want to do is build up a link to the WEB view of the object, eg:
https://rally1.rallydev.com/#/{CurrentProject}d/detail/{ObjectType}/{ObjectId}
I already know the CurrentProject, I need to know the ObjectType and the ObjectId
I have found, when i pass compact=true, the _ref provides this, '/defect/1234567' but this throws an exception.
If I do not pass compact=true, the _ref returns the API reference 'https://rally1.rallydev.com/slm/webservice/v2.x/defect/1234567'
Unfortunately the compact functionality was added to WSAPI after the .NET toolkit was created and we've never updated it to support it.
I filed a github issue here: https://github.com/RallyTools/RallyRestToolkitFor.NET/issues/37
compact=true was mainly a performance optimization to reduce the size of responses in large result sets.
Other than performance is there a reason you'd like to use it?
In ServiceNow, I am able to get only a maximum of 250 records in a SOAP request. How to get all the records?
Web Reference Url = https://*****.service-now.com/rm_story.do?WSDL
Code:
var url = "https://*****.service-now.com/rm_story.do?SOAP";
var userName = *****;
var password = *****;
var proxy = new ServiceNow_rm_story
{
Url = url,
Credentials = new NetworkCredential(userName, password)
};
try
{
var objRecord = new Namespace.WebReference.getRecords
{
// filters..
};
var recordResults = proxy.getRecords(objRecord);
}
catch (Exception ex)
{
}
In recordResults, I am getting only 250 records. How to get all the records ?
Also see this stack overflow answer which provides info.
Get ServiceNow Records Powershell - More than 250
Note that returning a large number of records can affect performance of the response and it may be more efficient to process your query in batches using offsets (i.e., get 1-100, then 101-200, ...). This can be achieved by using a sort order and offset. The ServiceNow REST Table API actually returns link headers from Get requests providing you links for the first, next and last set of records making it easy to know the url to query the next batch of records.
See: http://wiki.servicenow.com/index.php?title=Table_API#Methods
and look under 'Response Header'.
Have u tried to pass/override __limit parameter?
Google / wiki / Users manual / Release notes are always helpful
In your code snippet in line where it says //filter you should define __limit (and potentially __first_row and __last_row as explained in the example bellow)
int Skip = 0;
int Take = 250;
while (true)
{
using (var soapClient = new ServiceNowLocations.ServiceNow_cmn_location())
{
var cred = new System.Net.NetworkCredential(_user, _pass);
soapClient.Credentials = cred;
soapClient.Url = _apiUrl + "cmn_location.do?SOAP";
var getParams = new ServiceNowLocations.getRecords()
{
__first_row = Skip.ToString(),
__last_row = (Skip + Take).ToString(),
__limit = Take.ToString()
};
var records = soapClient.getRecords(getParams);
if (records != null)
{
if (records.Count() == 0)
{
break;
}
Skip += records.Count();
if (records.Count() != Take)
{
// last batch or everything in first batch
break;
}
}
else
{
// service now web service endpoint not configured correctly
break;
}
}
}
I made an library that handles interacting with ServiceNow Rest API much easier
https://emersonbottero.github.io/ServiceNow.Core/