C# Bungie API ExpandoObject issue - c#

I seem to be facing some issue when trying to read the JSON response from Bungie API, the below method usually works but for some reason i am now getting error message.
Function Code
public async Task<List<string>> GetMemberID(string MembersName)
{
List<string> MembershipID = new List<string>();
HttpResponseMessage response = await client.GetAsync(StaticObjects.bungieBasePath + $#"/User/SearchUsers/?q={MembersName}");
if (response.IsSuccessStatusCode)
{
try
{
Console.WriteLine(await response.Content.ReadAsStringAsync());
dynamic content = response.Content.ReadAsAsync<ExpandoObject>().Result;
foreach (dynamic user in content.Response.results)
{
MembershipID.Add(user.membershipId);
}
}
catch
{
throw new ArgumentException("The member could not be found.");
}
}
else
{
throw new ArgumentException("An error occurred retrieving the members information.");
}
return MembershipID;
}
Command Code
[Command("invite")]
[RequireContext(ContextType.Guild, ErrorMessage = "This command is specific to a particular server so you must send it from a channel within that server")]
public async Task JoinDateAsync([Remainder]string MemberName)
{
using (Context.Channel.EnterTypingState())
if (!Context.IsPrivate) await Context.Message.DeleteAsync();
if (StaticObjects.CheckUserIsAdmin(Context))
{
List<string> MembershipID = await StaticObjects._bungie.GetMemberID(MemberName);
}
}
The first part all works fine and i can see the JSON Response in the console however when i try to pull out the "membershipId" i then get an error in the console and cannot figure out where i'm going wrong.
Any help would be appreciated.

I spotted my issue, the JSON response was slightly different. After i removed one word it now works.
From
foreach (dynamic user in content.Response.results)
To
foreach (dynamic user in content.Response)

Related

How to resolve "Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied." error?

I am using neo4jclient graph database with .net core API. I have to add the health checks. I have created my own health check using Ihealthcheck interface. below is my healthcheck class
public class DatabaseHealthCheck : IHealthCheck
{
public DatabaseHealthCheck(IGraphClient graphClient)
{
_graphClient = graphClient;
}
private readonly IGraphClient _graphClient;
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
try
{
var result = await _graphClient.Cypher.Match(#"show databases")
.Return((n) => n.As<DatabaseDetail>()).ResultsAsync;
foreach (var res in result)
{
if (res.currentStatus == "Online")
{
return await Task.FromResult(
HealthCheckResult.Healthy("Healthy"));
}
}
}
catch (Exception ex)
{
return new HealthCheckResult(status: context.Registration.FailureStatus, exception: ex);
}
return HealthCheckResult.Healthy();
// return await Task.FromResult(
// new HealthCheckResult(context.Registration.FailureStatus,
// "Unhealthy"));
}
}
With this health check I want to get the database details and then check the status of database weather it is online or not but I am getting the below error
Neo4j returned a valid response, however Neo4jClient was unable to deserialize into the object structure you supplied.
Can anyone help me ?
The query you're writing will not return anything, what you're actually executing is:
MATCH (show databases)
RETURN n
You can see this if you change your code to look like this:
var query = _graphClient.Cypher.Match(#"show databases")
.Return((n) => n.As<string>());
var text = query.Query.DebugQueryText;
var result = await query.ResultsAsync;
If you put a breakpoint in so you can see what the text variable will be you'll be able to see it.
Now! I can't think how to get what you want when you're using the GraphClient - it might be possible with the BoltGraphClient - but the error you're getting implies you're using the former.
IF you were on the BoltGraphClient, you could access the Driver and execute:
var session = ((BoltGraphClient)_graphClient).Driver.AsyncSession(d => d.WithDatabase("system"));
var cursor = await session.RunAsync("SHOW DATABASES");
while (await cursor.FetchAsync())
{
var name = cursor.Current.Values["name"].As<string>();
var status = cursor.Current.Values["currentStatus"].As<string>();
Console.WriteLine($"{name} is {status.ToUpperInvariant()}");
}
I don't know any other work around with the http GraphClient - it would need to be added to the client. In theory - it's not a complex PR to do if you wanted to.

Correct way to use Async/Await

I've been working for a few days on a performance problem.
Before I delve deeper I want to quickly explain how the specific service work.
I have a main Service that get a request and send requests to other micro-services but the single Entry Point for the user is to Main service, I thinks is more simple to understand with this image:
After the Main service get request from API he do some logic, query the Db and then get a list, every item on the list has Id, to get enrichment about every item the main service create request to one of the micro-service.
For example John request main service, main service get from Db a list of 90 items then the main service will create 90 calls to micro service and return to John single response that include 90 items.
Now the question is only about the right way to create async call to micro service.
This how I develop this part:
GetDetailsAsync(Id, result.Items, request.SystemComponentId);
private static void GetDetailsAsync(string Id, List<MainItem> items, int systemId)
{
var getDetailsTasks = new List<Task>();
foreach (MainItem single in items)
{
getDetailsTasks.Add(SetSingleDetailsAsync(Id, single, systemId));
}
Task.WhenAll(getDetailsTasks);
}
private static async Task SetSingleDetailsAsync(string Id, MainItem single, int systemId)
{
single.ActivityExtendedDetails = await ProcessItemDetailsRequest.GetItemDetailsAsync(Id, single.TypeId,
single.ItemId, systemId);
}
public static Task<JObject> GetItemDetailsAsync(string id, short type,
string itemId, int systemId)
{
var typeList = ActivityTypeDetails.GetActivityTypes();
var url = GetActivityUrl(id, type, itemId, typeList);
if (url == null)
{
throw new Failure($"No url defined for type {type}");
}
try
{
JObject res;
using (var stream = client.GetStreamAsync(url).Result)
using (var sr = new StreamReader(stream))
using (var reader = new JsonTextReader(sr))
{
var serializer = new JsonSerializer();
res = serializer.Deserialize<JObject>(reader);
}
return Task.FromResult(res);
}
catch(Exception ex)
{
Logger.Warn(
$"The uri {url} threw exception {ex.Message}.");
//[Todo]throw exception
return null;
}
}
This code run and the result is not good enough, the CPU rises very quickly and becomes very high, I think that I has a problem on GetItemDetailsAsync func because I use client.GetStreamAsync(url).Result
when using .Result it's block until the task is completed.
So I do some minor change on GetItemDetailsAsync to try to be really async:
public static async Task<JObject> GetItemDetailsAsync(string id, short type,
string itemId, int systemId)
{
var typeList = ActivityTypeDetails.GetActivityTypes();
var url = GetActivityUrl(id, type, itemId, typeList);
if (url == null)
{
throw new Failure($"No url defined for type {type}");
}
try
{
JObject res;
using (var stream = await client.GetStreamAsync(url))
using (var sr = new StreamReader(stream))
using (var reader = new JsonTextReader(sr))
{
var serializer = new JsonSerializer();
res = serializer.Deserialize<JObject>(reader);
}
return res;
}
catch(Exception ex)
{
Logger.Warn(
$"The uri {url} threw exception {ex.Message}.");
//[Todo]throw exception
return null;
}
}
But now I get null where I supposed to get the data that come from Async function.
I try to debugging and I noticed something weird, everything happen likes as I would expect: the methods was called, request to micro-service was executed and get response but the response from the End-Point(which is found on main-service) return before the async method return from micro-service, that cause that I get null instead of my expected data.
I thinks that maybe I don't use correctly async\await and would be happy if anyone could explain how this behavior happens

How do I await a Windows.Web.Http.HttpClient.GetAsync()? Getting Intellisense error

Edit: I am already using the Microsoft.Bcl.Async nuget package in my project, but the error persists.
I am writing an asnyc "make sure the URL is accessible" method using the following code:
public async Task<ConnectivityMonitorResult> TestModeUrlCheck(string url)
{
try
{
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.Expired);
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.InvalidName);
using (var httpClient = new Windows.Web.Http.HttpClient(filter))
{
var resp = await httpClient.GetAsync(new Uri(url), Windows.Web.Http.HttpCompletionOption.ResponseHeadersRead);
if (resp.IsSuccessStatusCode)
return new ConnectivityMonitorResult(ConnectivityType.Connected);
else
return new ConnectivityMonitorResult(ConnectivityType.NotConnected);
}
}
catch(Exception ex)
{
return new ConnectivityMonitorResult(ConnectivityType.NotConnected, "Unhandled error: " + ex.Message);
}
}
This method will be for the "Test Mode" of my app. (The production Check method will fail with bad SSL certs). It will be hitting local dev servers with self-signed certs.
Problem is that this code won't build because of the following error on the var resp = await line:
'IAsyncOperationWithProgress' does
not contain a definition for 'GetAwaiter' and the best extension
method overload 'AwaitExtensions.GetAwaiter(Task)' requires a receiver
of type 'Task'
I have not been able to figure how to properly construct the GetAsync() call to get this to work.
Update
This is for a Windows 8 app using the portable class libraries. I am using await in other places in the project. And I have the Microsoft.Bcl and Microsoft.Bcl.Async Nuget packages already added to my project.
Update
I tried updating the code to this:
public async Task<ConnectivityMonitorResult> TestModeUrlCheck(string url)
{
try
{
var filter = new HttpBaseProtocolFilter();
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.Expired);
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.Untrusted);
filter.IgnorableServerCertificateErrors.Add(Windows.Security.Cryptography.Certificates.ChainValidationResult.InvalidName);
using (var httpClient = new Windows.Web.Http.HttpClient(filter))
{
var resp = await Test(httpClient, url);
if (resp.IsSuccessStatusCode)
return new ConnectivityMonitorResult(ConnectivityType.Connected);
else
return new ConnectivityMonitorResult(ConnectivityType.NotConnected);
}
}
catch(Exception ex)
{
return new ConnectivityMonitorResult(ConnectivityType.NotConnected, "Unhandled error: " + ex.Message);
}
}
private async Task<Windows.Web.Http.HttpResponseMessage> Test(Windows.Web.Http.HttpClient client, string apiUrl)
{
var asyncOp = client.GetAsync(new Uri(apiUrl), Windows.Web.Http.HttpCompletionOption.ResponseHeadersRead);
return await Task.Run(() => asyncOp.GetResults());
}
It compiled, but I got the runtime error:
WinRT information: A method was called at an unexpected time.
I solved this by updating the target of the project. The other projects in the solution were targeting Windows8.1, whereas this one was targeting Windows8. When I updated the target, the errors went away and the app built and ran.

Google Directory API - How to get the resulting deserialized objects of a BatchRequest

i am trying to speed up some google directory api calls in the .net client library with BatchRequests
lets say i have the following batchRequest (which consists only of one
request for simplicity):
static async Task BatchRequesting()
{
var batchReq = new BatchRequest(_dirservices[0]);
var r = _dirservices[0].Users.Get("user#domain.com");
batchReq.Queue<UsersResource.GetRequest>(r,
(contentReq, error, j, message) =>
{
... what to do here?
});
await batchReq.ExecuteAsync();
}
how do i get the resulting deserialized response object in the callback (which would be a User object in my case)
Do i have to handle the message.Content object (HttpContent) myself with all the json deserializing?
I found the solution. I used the wrong generic parameter. My Code example has to be like this:
static async Task BatchRequesting()
{
var batchReq = new BatchRequest(_directoryService);
var request = _directoryService.Users.Get("user#domain.com");
batchReq.Queue<User>(request,
(returnedUser, error, j, message) =>
{
if (error != null)
{
Console.WriteLine(error.Message);
}
else
{
... work with returnedUser
}
});
await batchReq.ExecuteAsync();
}

Can't return HTTP status and data from a method after using httpClient.GetAsync()

I am having issues with the following code. I am retrieving a JSON object as a string and then wish to return this from my method so it can be used elsewhere. When I do however I get the message:
'filmsGlossary.searchQueries.returnJson(object); returns void, a return keyword must not be followed by an object expression'
public async void returnJson(object term)
{
//Set Variables
var searchFormat = "&format=json";
var termValue = term;
var httpClient = new HttpClient();
try
{
//Set web service URL format
string baseURI = "http://localhost/filmgloss/webService/web-service.php?termName=";
string userURI = baseURI + termValue + searchFormat;
//Send URL to web service and retrieve response code.
var response = await httpClient.GetAsync(userURI);
response.EnsureSuccessStatusCode();
var content = await response.Content.ReadAsStringAsync();
return content.ToString();
}
catch (HttpRequestException hre)
{
}
catch (Exception ex)
{
}
}
Originally I was only returning
return content;
However after reading it seemed that the issue might be that I needed to change this to:
return content.ToString();
However this did not help. I also read that I could change it to a synchronous, rather than asynchronous method and change the method to be 'public string' however I am only just learning c# and don't yet fully understand the implications of this (or how to do it).
Is it possible to resolve this error within the code I already have?
I would also like to understand the cause of the issue rather than just know the solution.
Thanks.
You really should paste the error messages that you are getting.
Why does your function declaration return void? It should return Task<string>.
public async Task<string> returnJson(object term)
Also in the body you should return the Task, like this:
await response.Content.ReadAsStringAsync();

Categories