.NET Framework 4.7 : Get particular attribute from ReadAsStringAsync - c#

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

Related

How to create google translation using windows application without getting the error The Application Default Credentials are not available.?

I am trying to create a google api to extract text from image and later do a translation to English, my sample code bellow
try
{
var JsonFilePath = #"C:\Users\shanjeeva\source\repos\TranslatorWindowsApp\Translator-fa8e022a7ba1.json";
//Authenticate to the service by using Service Account
var credential = GoogleCredential.FromFile(JsonFilePath).CreateScoped(ImageAnnotatorClient.DefaultScopes);
var channel = new Grpc.Core.Channel(ImageAnnotatorClient.DefaultEndpoint.ToString(), credential.ToChannelCredentials());
var client = ImageAnnotatorClient.Create(); // getting an error here
var image = Image.FromFile(#"D:\Work Temp\Translate.JPG");
// Performs label detection on the image file
var response = client.DetectLabels(image);
foreach (var annotation in response)
{
if (annotation.Description != null)
Console.WriteLine(annotation.Description);
}
}
catch (AnnotateImageException ex)
{
AnnotateImageResponse response = ex.Response;
Console.WriteLine(response.Error);
}
catch (Exception ee)
{
Console.WriteLine(ee.Message);
throw;
}
}
also I have setup google cloud application, generated necessary json file eg- Translator-XXXXX.json
some suggested to setup environment variable with the key "GOOGLE_APPLICATION_CREDENTIALS" also I tried, but am getting bellow error
'The Application Default Credentials are not available. They are available if running in Google Compute Engine. Otherwise, the environment variable GOOGLE_APPLICATION_CREDENTIALS must be defined pointing to a file defining the credentials. See https://developers.google.com/accounts/docs/application-default-credentials for more information.'
Can someone please help me?
I was able to resolve with experts help, sample code bellow, added bellow code just before all other code and it works fine
try
{
var GAC = Environment.GetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS");
if (GAC == null)
{
var path = #"D:\Work Temp\translator-298603-2bb5a20655a2.json";
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", path);
}
}
catch (Exception)
{
}

Update Values in Excel Named Ranges using Microsoft Graph API

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);

dialogflow simple fulfillment webhook in c# not working

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.

How do I use the response from a postasync call?

I have a webApi set up that has a PostStudent method. The API call works fine and creates a new student in the DB, but I can't get it to return the value in the response body. I have tried returning Ok(newStudent) and Created("~/api/poststudent", newStudent) but neither of them have returned the newStudent value that I need.
I have gone through all of the response and can't find the actual newStudent object. Is it there and I am just missing it or do I have a problem with my code?
This is the PostStudent method from the API;
var newStudent = new Student
{
studentId = nextStudentId,
studentFirstName = studentEntry.StudentFirstName,
studentLastName = studentEntry.StudentLastName,
studentDOB = studentEntry.StudentDob,
studentEmergencyContactName = studentEntry.StudentEmergencyContactName,
studentEmergencyContactNum = studentEntry.StudentEmergencyContactNum,
ticketNumber = studentEntry.TicketNumber
};
db.Student.Add(newStudent);
try
{
db.SaveChanges();
}
catch (DbUpdateException)
{
if (StudentExists(newStudent.studentId))
return BadRequest("That student id already exists");
throw;
}
return Ok(newStudent.studentId);
// return Created("~/api/poststudent", newStudent);
}
This is where I call postasync and try to save the response body;
var response = client.PostAsync("api/poststudent", content);
return response.Result.Content.ReadAsStringAsync().ToString();
And this is where I want to use the value;
var newStudentId = controller.PostStudent(studentFirstName, studentLastName, studentDob, ticketNumber);
var url = "~/AddGuardian/AddGuardian/" + newStudentId;
Response.Redirect(url);
I hope someone can help me. I never thought redirecting to another page would be so damn hard!
Cheers.
You're not awaiting the async calls:
var response = await client.PostAsync("api/poststudent", content);
return (await response.Result.Content.ReadAsStringAsync()).ToString();
There are 2 official tutorials for quickstarting a ASP.NET WebApi project.
Using Web API 2 with Entity Framework 6
Calling a Web API From a .NET Client (C#)
I want to recommend to work through these. If you find your application is doing things wrong, fix your application towards these samples. If your requirements differ from what is given in the samples, you can emphasize on this in your question.

How do I include content with a GET request?

EDIT: Please note, I know the heart of the problem lies in the service I need to communicate with is not following protocol. This is software which I am not capable of touching and will not be changed anytime soon. Thus, I need help with circumventing the problem and breaking protocol. Development at its finest!
I'm attempting to communicate with an external service. Whomever made it decided to split various calls into not just different folders, but also HTTP request types. The problem here, is that I need to send a GET request that includes content.
Yes, this violates the protocol.
Yes, this works if I formulate the call using Linux commands.
Yes, this works if I manually craft the call in Fiddler (although Fiddler gets angry at the breach of protocol)
When I craft my call, it's wrapped in an async method. Sending it, however, results in an error:
Exception thrown: 'System.Net.ProtocolViolationException' in mscorlib.dll ("Cannot send a content-body with this verb-type.")
Code for the call:
/// <summary>
/// Gets a reading from a sensor
/// </summary>
/// <param name="query">Data query to set data with</param>
/// <returns></returns>
public async Task<string> GetData(string query)
{
var result = string.Empty;
try
{
// Send a GET request with a content containing the query. Don't ask, just accept it
var msg = new HttpRequestMessage(HttpMethod.Get, _dataApiUrl) { Content = new StringContent(query) };
var response = await _httpClient.SendAsync(msg).ConfigureAwait(false);
// Throws exception if baby broke
response.EnsureSuccessStatusCode();
// Convert to something slightly less useless
result = await response.Content.ReadAsStringAsync();
}
catch (Exception exc)
{
// Something broke ¯\_(ツ)_/¯
_logger.ErrorException("Something broke in GetData(). Probably a borked connection.", exc);
}
return result;
}
_httpClient is created in the constructor and is a System.Net.Http.HttpClient.
Does anyone have an idea how to override the regular protocols for the HttpClient and force it to make the call as a GET call, but with a content containing my query for the server?
To me the less devastating way to achieve that is to set ContentBodyNotAllowed field of Get KnownHttpVerb to false using reflection.
You can try with this:
public async Task<string> GetData(string query)
{
var result = string.Empty;
try
{
var KnownHttpVerbType = typeof(System.Net.AuthenticationManager).Assembly.GetTypes().Where(t => t.Name == "KnownHttpVerb").First();
var getVerb = KnownHttpVerbType.GetField("Get", BindingFlags.NonPublic | BindingFlags.Static);
var ContentBodyNotAllowedField = KnownHttpVerbType.GetField("ContentBodyNotAllowed", BindingFlags.NonPublic | BindingFlags.Instance);
ContentBodyNotAllowedField.SetValue(getVerb.GetValue(null), false);
var msg = new HttpRequestMessage(HttpMethod.Get, _dataApiUrl) { Content = new StringContent(query) };
var response = await _httpClient.SendAsync(msg).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
result = await response.Content.ReadAsStringAsync();
}
catch (Exception exc)
{
_logger.ErrorException("Something broke in GetData(). Probably a borked connection.", exc);
}
return result;
}

Categories

Resources