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);
Related
I am having some issues finding information about adding some logic field in my RestRequest using V 107. I am trying to add a filter to my GET query
dl_document_indexed_date gt '2020-12-07T08:30:42.483Z'
There are a few other queries in the call which i am using Dictionary<string, string> to store them, and it works great however it only works if i am looking for something equal to, as adding it to the parameters it seems by default its equal to and i am not finding any way to add any other logic, gt/ge/lt/le etc. using the older version i would just append the url adding the logic i need, but i am not seeing a way to append the url either. Looking over their documentation i either missed it, cant find it, or its not there. Any help would be greatly appreciated! My method looks like this
public static async Task<string> GET_API(String RequestUrl, string RequestObject, Dictionary<string, string> parameters)
{
var request = new RestRequest(RequestObject);
var options = new RestClientOptions(RequestUrl)
{
ThrowOnAnyError = true,
Timeout = -1
};
var client = new RestClient(options);
client.Authenticator = new OAuth2AuthorizationRequestHeaderAuthenticator("Bearer " + TokenManager.GetAccessTokenString("TRN"));
foreach (var parameter in parameters)
{
request.AddQueryParameter(parameter.Key, parameter.Value);
}
var response = await client.GetAsync(request);
return response.Content.ToString();
}
I send the BaseURL , the RequestObject would be table i am calling in the base URL, and my dictionary item contains the Field name, and the field values that i am dynamically generating on another method that would append the string. and example would be
parameters.Add("dl_document_name", "TableA");
which would append the URL with dl_document_name eq 'TableA'
it would call the API after i add the OAuth Token i create and return the data i need and send it back. or another option i guess could be appending the string with the logic i need to return the data
You should use OData, it's easy to implement and it has different kind of filters, you also can set which filters are usable and which aren't.
https://www.odata.org/
I figured out a work around, if i only have one i can add it to the first parameter and adding the filter as the first key, which will work unless i have multiple conditions that are not eq
parameters.Add("filter","dl_document_indexed_date gt '2020-12-07T08:30:42.483Z'");
I'm sure there are some posts talking about it but so far, nothing works in my case.
I get data from an api and I read it within a console application in C# for testing purpose.
My end goal is to call the data from the API and store the attributes ("analyst" for ex) somewhere where I could pick some of them and dysplay them within a winform app' (I think mostly through a Datagridview than a webbrowser but I'm not sure). I understand I need Json.net but as I use the ReadAsStringAsync() method I'm not sure about the object type I use anymore. Here is my code:
// Get the response from the API
using (var client = new HttpClient())
{
try
{
var response = client.SendAsync(httpRequestMessage).Result;
//Console.WriteLine(response.ToString());
HttpContent responseContent = response.Content;
var responsedata = responseContent.ReadAsStringAsync();
//Console.WriteLine(responseContent);
string data = responsedata.Result;
var BS = JsonConvert.DeserializeObject<dynamic>(data);
string analyst = BS.analyst;
Console.WriteLine(analyst);
Console.ReadKey();
}
catch (HttpRequestException e)
{
Console.WriteLine("\nException Caught!");
Console.WriteLine($"Message: {e.Message}");
}
}
I got an object "data" like this :
{
"result":
{
"3_yr_proj_eps_cagr_prcntg": 47.0,
"analyst": "Jones Dow",
"analyst_email": "Dow.Jones#Theprovider.com",
"business_summary": "<p>COMPANY OVERVIEW. Dow Inc. was formed on April 1, 2019, following the spin- off of the company from DowDupont".
}
}
And I just want to display "analyst" into my datagridview when I click on a button but so far my variable "analyst" is null meaning the porgramm does not see the value "Jones Dow"...
I'm kind of lost within all the information I could read about the topic, any help would be appreciated.
Thanks
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?
I am very new to dialogflow and WebAPIs, and having trouble with a simple dialogflow fulfillment webhook written in C# and hosted on Azure. I am using dialogflow V2.0 API version.
Currently my fulfillment works and returns a simple response but has no regard to the intent and parameters. I am trying to now parse the JSON get the intent do a simple select case and return the value of the parameters recevied. And this is giving me lot of trouble. The webhook link, my code and the error message returned in the "catch" block are given below
public JsonResult Post(string value)
{
try
{
dynamic obj = JsonConvert.DeserializeObject(value);
string Location = string.Empty;
switch (obj.intent.displayName)
{
case "getstock":
Location = obj.outContexts[0].parameters[0].Location;
break;
}
WebhookResponse r = new WebhookResponse();
r.fulfillmentText = string.Format("The stock at {0} is valuing Rs. 31 Lakhs \n And consists of items such as slatwall, grid and new pillar. The detailed list of the same has been email to you", Location);
r.source = "API.AI";
Response.ContentType = "application/json";
return Json(r);
} catch(Exception e)
{
WebhookResponse err = new WebhookResponse();
err.fulfillmentText = e.Message;
return Json(err);
}
}
The error message :
Value cannot be null.
Parameter name: value
The above function is called via POST, you can use POSTMAN and you will get the JSON response.
Moreover i am using ASP.Net Web Api with Visual Studio 2017 with Controllers
First install the nuget package Google.Apis.Dialogflow.v2 and its dependencies. It'll save you a lot of work later on as it has dialogflow response/request c# objects which will make navigating the object graph easier.
Second add the using for the package using Google.Apis.Dialogflow.v2.Data;
Change your method to something like
public GoogleCloudDialogflowV2WebhookResponse Post(GoogleCloudDialogflowV2WebhookRequest obj)
{
string Location = string.Empty;
switch (obj.QueryResult.Intent.DisplayName)
{
case "getstock":
Location = obj.QueryResult.Parameters["Location"].ToString();
break;
}
var response = new GoogleCloudDialogflowV2WebhookResponse()
{
FulfillmentText = $"The stock at {Location} is valuing Rs. 31 Lakhs \n And consists of items such as slatwall, grid and new pillar. The detailed list of the same has been email to you",
Source = "API.AI"
};
return response;
}
I think your main issue in your code is "obj.outContexts[0]" outContexts isn't where you'll find your parameters, and unless you've setup an output content this will be null. You need to look in queryResult for your parameters.
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);