Finding specific values in JSON.NET with C# - c#

I've been making a Minecraft launcher. I have a long JSON file that contains all the libraries required to launch one version. A sample of this code:
{
"id": "1.6.2",
"time": "2013-08-06T14:00:00+03:00",
"releaseTime": "2013-07-05T16:09:02+03:00",
"type": "release",
"minecraftArguments": "--username ${auth_player_name} --session ${auth_session} --version ${version_name} --gameDir ${game_directory} --assetsDir ${game_assets}",
"libraries": [
{
"name": "net.sf.jopt-simple:jopt-simple:4.5"
},
{
"name": "com.paulscode:codecjorbis:20101023"
},
So you can see that there is an array called libraries. I can query the values in "name" using a foreach quite fine, but sometimes this occurs in the json:
{
"name": "org.lwjgl.lwjgl:lwjgl:2.9.0",
"rules": [
{
"action": "allow"
},
{
"action": "disallow",
"os": {
"name": "osx",
"version": "^10\\.5\\.\\d$"
}
}
]
},
So as you can see, there is an array inside called rules. I need to find the value of name inside os inside rules. Anything I've tried came up with an exception and wouldn't work. This is my code at the moment for parsing the code:
foreach (JToken lib in profilejsono["libraries"])
{
if ((lib["rules"][1]["os"].ToString() == "osx") || (lib["rules"][1]["os"].ToString() == "linux"))
{
availableLibs.Add(lib["name"].ToString());
}
}
The point of the code is not to add the library if it's for OSX or Linux (I'll add that functionality later). How do I do this?

One possible solution to your problem is to generalize the check for the OS name (and make it independant of the rules node depth). I suppose you have some library objects, because you need to deserialize the JSON input string to some object. The following code gives you the library names only for library nodes that have rule nodes with os nodes with a specified name:
JSON Test-Input file lib1.json:
{
"name": "lib1",
"rules": [
{
"action": "allow"
},
{
"action": "disallow",
"os": {
"name": "windows",
"version": "^10\\.5\\.\\d$"
}
}
]
}
JSON Test-Input file lib2.json:
{
"name": "lib2",
"rules": [
{
"action": "allow"
},
{
"action": "disallow",
"os": {
"name": "osx",
"version": "^10\\.5\\.\\d$"
}
}
]
}
JSON Test-Input file lib3.json:
{
"name": "lib3",
"rules": [
{
"action": "allow"
},
{
"action": "disallow",
"os": {
"name": "linux",
"version": "^10\\.5\\.\\d$"
}
}
]
}
JSON Test-Input file lib4.json:
{
"name": "lib4",
"rules": [
{
"action": "allow"
},
{
"action": "disallow"
}
]
}
JSON helper objects describing the library node, needed to deserialize the JSON inputs:
// helper classes describing the library object (for the JSON deserialization)
public class Library
{
public String Name { get; set; }
public Rules[] Rules { get; set; }
}
public class Rules
{
public String Action { get; set; }
public Os Os { get; set; }
}
public class Os
{
public String Name { get; set; }
public String Version { get; set; }
}
Code for fetching only matching libraries:
var jsonInput = #"d:\temp\json.net\lib{0}.json";
try
{
// load libraries / deserialize json
var libraries = new List<Library>();
Enumerable.Range(1, 4).ToList().ForEach(index =>
{
var json = File.ReadAllText(String.Format(jsonInput, index));
libraries.Add(JsonConvert.DeserializeObject<Library>(json));
});
// OS names to check if present in the current rules
var osNames = new List<String> { "osx", "linux" };
// check each library
foreach (var library in libraries)
{
// do we have rules?
if (library.Rules.Length > 0)
{
// get all non-empty OS nodes
var existingOsNodes = library.Rules.Where (r => r.Os != null).Select (r => r.Os).ToList();
// check for allowed OS name
var osIsPresent = existingOsNodes.Where (node => osNames.Contains(node.Name.ToLower())).Select (node => node.Name);
if (osIsPresent.Any())
{
Console.WriteLine(library.Name);
}
}
}
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
The output for the four given input files is:
lib2
lib3

Related

Azure.Data.Tables and Microsoft.AspNetCore.OData. Read from cosmos db and display list of entities in odata format

I want to retrieve information from cosmos db table api and I do it with the next code. Can get the info as expected but if I try to return the queryResultsMaxPerPage.AsPages()
[EnableQuery]
public async Task<IActionResult> Get([FromODataUri] ODataQueryOptions options, [FromODataUri] string continuationToken)
{
TableClient tableClient = new TableClient(conn, "Patients");
tableClient.CreateIfNotExists();
AsyncPageable<Patient> queryResultsMaxPerPage = tableClient.QueryAsync<Patient>(filter: "PartitionKey eq 'tenant-id'", maxPerPage: 3);
return Ok(queryResultsMaxPerPage.AsPages());
}
in an ODataEndpoint I get the following response:
[
{
"values": [
{
... entity
},
{
... entity
},
{
... entity
}
],
"continuationToken": "{\"token\":\"+RID:~vv0zAMD99CMFAAAAAAAAAA==#RT:1#TRC:3#ISV:2#IEO:65567#QCF:4#FPC:AQUAAAAAAAAABgAAAAAAAAA=\",\"range\":{\"min\":\"\",\"max\":\"FF\"}} NA"
},
{
"values": [
{
... entity
}
],
"continuationToken": null
}
]
Instead of that I would like to get something like this:
{
"#odata.context": "https://localhost:7151/api/v1/$metadata#Patient",
"value": [
{
... entity
},
{
... entity
},
{
... entity
}
],,
"#odata.nextLink": "https://localhost:7151/api/v1/patient?A-CONTINUATION-TOKEN-OR-SOMETHING-LIKE-THAT" <-- or something that has a continuation token or anything that can help TO PAGE/HANDLE THE RESULTS
}
Do you have any idea about it?

Message = "Unexpected character encountered while parsing value: [. Path '', line 1, position 1."

I want to show list of departments in my ASP.NET Core MVC view.
Notice that I have 3-tier layers (Data Access + API (to get data from database) + MVC (UI)).
Here is my Json Data that I got from database using a call to the API:
[
{
"id": 3,
"name": "Sales"
},
{
"id": 4,
"name": "PMO"
},
{
"id": 5,
"name": "Research And Development"
},
{
"id": 6,
"name": "Product Management"
},
{
"id": 7,
"name": "HR"
},
{
"id": 8,
"name": "Ava"
},
{
"id": 9,
"name": "IT"
}
]
Here is my C# code using HttpClient to get data from the API:
public async Task<T> GetRequest<T>(string uri)
{
try
{
var client = _httpClientFactory.CreateClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
using (HttpResponseMessage response = await client.GetAsync(uri))
{
if (response.StatusCode.ToString() == "OK")
{
_logger.LogInformation("Get Request Successed");
//response.EnsureSuccessStatusCode();
responseBody = await response.Content.ReadAsStringAsync();
}
return JsonConvert.DeserializeObject<T>(responseBody);
}
}
catch (Exception ex)
{
_logger.LogError("Failed");
return JsonConvert.DeserializeObject<T>(responseBody);
}
}
When I am trying to parse the data from json it returns an Error.
Unexpected character encountered while parsing value: [. Path '', line 1, position 1.
You can parse your string to a strongly typed Model and then de-serialize to it OR you can use dynamic and access the properties as shown below:
You can find a working example here
using System;
using Newtonsoft.Json;
using System.Collections.Generic;
public class Program
{
public static void Main()
{
var myJsonString=#"[{'id':3,'name':'Sales'},{'id':4,'name':'PMO'},{'id':5,'name':'Research And Development'},{'id':6,'name':'Product Management'},{'id':7,'name':'HR'},{'id':8,'name':'Ava'},{'id':9,'name':'IT'}]";
var result =JsonConvert.DeserializeObject<List<Root>>(myJsonString);
Console.WriteLine("Example using Model: \n");
foreach(var item in result)
{
Console.WriteLine(item.id);
Console.WriteLine(item.name);
}
Console.WriteLine("\n");
Console.WriteLine("Example using Dynamic: \n");
//Example using dynamic
var resultDynamic=JsonConvert.DeserializeObject<dynamic>(myJsonString);
foreach(var item in resultDynamic)
{
Console.WriteLine(item["id"]);
Console.WriteLine(item["name"]);
}
}
}
public class Root
{
public int id { get; set; }
public string name { get; set; }
}
Output:
Example using Model:
3
Sales
4
PMO
5
Research And Development
6
Product Management
7
HR
8
Ava
9
IT
Example using Dynamic:
3
Sales
4
PMO
5
Research And Development
6
Product Management
7
HR
8
Ava
9
IT

Azure functions - how to insert array in configuration file

I'm using the local.settings.json file to store application settings for my Azure Function, as suggested here. I can access the Values of the application settings in the following example
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"AzureWebJobsDashboard": ""
},
"ConnectionStrings": {
"SQLConnectionString": "myConnectionString"
}
}
by using ConfigurationManager.ApplicationSettings["someValue"] or the connection string by using ConfigurationManager.ConnectionStrings["SQLConnectionString"].
However, when I try to insert an array as one of the Values:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"AzureWebJobsDashboard": "",
"myArray": [
{
"key1": "value1",
"key2": "value2"
},
{
"key1": "value3",
"key2": "value4"
}
]
},
"ConnectionStrings": {
"SQLConnectionString": "myConnectionString"
}
}
I start getting exceptions (when I try to access the connection string, for instance). So my guess is that I'm not using the correct format for the array.
Can arrays be used in the local.settings.json file? And if they can, what's the correct format?
According to the azure function source code Azure.Functions.Cli/Common/SecretsManager.cs, you could find it has a AppSettingsFile class, which used to read the setting from the local.settings.json file.
Some part of the AppSettingsFile class:
public AppSettingsFile(string filePath)
{
_filePath = filePath;
try
{
var content = FileSystemHelpers.ReadAllTextFromFile(_filePath);
var appSettings = JsonConvert.DeserializeObject<AppSettingsFile>(content);
IsEncrypted = appSettings.IsEncrypted;
Values = appSettings.Values;
ConnectionStrings = appSettings.ConnectionStrings;
Host = appSettings.Host;
}
catch
{
Values = new Dictionary<string, string>();
ConnectionStrings = new Dictionary<string, string>();
IsEncrypted = true;
}
}
public bool IsEncrypted { get; set; }
public Dictionary<string, string> Values { get; set; } = new Dictionary<string, string>();
public Dictionary<string, string> ConnectionStrings { get; set; } = new Dictionary<string, string>();
According to the code, it use JsonConvert.DeserializeObject method to convert the json file to appSettings object.
But the appSettings.Values property is directory type, it doesn't support array. So I don't suggest you use array as its setting.
I suggest you could try to convert the array as two string value. This will work well.
Like this:
{
"IsEncrypted": false,
"Values": {
"AzureWebJobsStorage": "",
"AzureWebJobsDashboard": "",
"arrary1-key1": "value1",
"arrary1-key2": "value2",
"arrary2-key1": "value3",
"arrary2-key2": "value4"
},
"ConnectionStrings": {
"SQLConnectionString": "myConnectionString"
}
}

C# Specflow Object reference not set to an instance of an object in

I am trying to implement Specflow for google geo code api, however I am repeatedly getting System.NullReferenceException : Object reference not set to an instance of an object. and RootObject is always set to null. Can somebody help me?
below is my Step definition
namespace NUnit.Tests1.StepDefinition
{
[Binding]
public sealed class GoogleSteps
{
private string googleapiurl;
private RootObject root = new RootObject();
[Given(#"Google api that takes address and returns latitude and longitude")]
public void GivenGoogleApiThatTakesAddressAndReturnsLatitudeAndLongitude()
{
googleapiurl = "http://maps.googleapis.com/maps/api/geocode/json?address=";
}
[When(#"The client Gets response by ""(.*)""")]
public async Task WhenTheClientGetsResponseBy(string addr)
{
HttpClient cl = new HttpClient();
StringBuilder sb = new StringBuilder();
sb.Append(googleapiurl);
sb.Append(addr);
Uri uri = new Uri(sb.ToString());
var response = await cl.GetStringAsync(uri);
root = JsonConvert.DeserializeObject<RootObject>(response);
}
[Then(#"The ""(.*)"" and ""(.*)"" returned should be as expected")]
public void ThenTheAndReturnedShouldBeAsExpected(string exp_lat, string exp_lng)
{
var location = root.results[0].geometry.location;
var latitude = location.lat;
var longitude = location.lng;
Console.WriteLine("Testing upali");
Console.WriteLine("location: lat " + location.lat);
Console.WriteLine("location: long " + location.lng);
Assert.AreEqual(location.lat.ToString(), exp_lat);
Assert.AreEqual(location.lng.ToString(), exp_lng);
}
}
}
The Json response is :
{
"results": [
{
"address_components": [
{
"long_name": "1600",
"short_name": "1600",
"types": [
"street_number"
]
},
{
"long_name": "Amphitheatre Parkway",
"short_name": "Amphitheatre Pkwy",
"types": [
"route"
]
},
{
"long_name": "Mountain View",
"short_name": "Mountain View",
"types": [
"locality",
"political"
]
},
{
"long_name": "Santa Clara County",
"short_name": "Santa Clara County",
"types": [
"administrative_area_level_2",
"political"
]
},
{
"long_name": "California",
"short_name": "CA",
"types": [
"administrative_area_level_1",
"political"
]
},
{
"long_name": "United States",
"short_name": "US",
"types": [
"country",
"political"
]
},
{
"long_name": "94043",
"short_name": "94043",
"types": [
"postal_code"
]
}
],
"formatted_address": "1600 Amphitheatre Pkwy, Mountain View, CA 94043, USA",
"geometry": {
"location": {
"lat": 37.4223329,
"lng": -122.0844192
},
"location_type": "ROOFTOP",
"viewport": {
"northeast": {
"lat": 37.4236818802915,
"lng": -122.0830702197085
},
"southwest": {
"lat": 37.4209839197085,
"lng": -122.0857681802915
}
}
},
"place_id": "ChIJ2eUgeAK6j4ARbn5u_wAGqWA",
"types": [
"street_address"
]
}
],
"status": "OK"
}
And my RootObject class is as below:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace NUnit.Tests1.GoogleAPI
{
public class RootObject
{
public List<Result> results { get; set; }
public string status { get; set; }
}
}
Result StackTrace:
Test Name: VerifyLatitudeAndLongitude
Test FullName: NUnit.Tests1.FeatureFiles.GoogleGeoCodeFeature.VerifyLatitudeAndLongitude
Test Source: C:\Users\nandyu\documents\visual studio
2015\Projects\NUnit.Tests1\NUnit.Tests1\FeatureFiles\GoogleGeoCode.feature :
line 5
Test Outcome: Failed
Test Duration: 0:00:00.069
Result StackTrace:
at
NUnit.Tests1.StepDefinition.GoogleSteps.ThenTheAndReturnedShouldBeAsExpected(String exp_lat, String exp_lng) in C:\Users\nandyu\documents\visual studio 2015\Projects\NUnit.Tests1\NUnit.Tests1\StepDefinition\GoogleSteps.cs:line 42
at lambda_method(Closure , IContextManager , String , String )
at TechTalk.SpecFlow.Bindings.BindingInvoker.InvokeBinding(IBinding binding,
IContextManager contextManager, Object[] arguments, ITestTracer testTracer, TimeSpan& duration)
at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStepMatch(BindingMatch match, Object[] arguments)
at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.ExecuteStep(StepInstance stepInstance)
at TechTalk.SpecFlow.Infrastructure.TestExecutionEngine.OnAfterLastStep()
at TechTalk.SpecFlow.TestRunner.CollectScenarioErrors()
at NUnit.Tests1.FeatureFiles.GoogleGeoCodeFeature.ScenarioCleanup()
at
NUnit.Tests1.FeatureFiles.GoogleGeoCodeFeature.VerifyLatitudeAndLongitude()
in C:\Users\nandyu\documents\visual studio
2015\Projects\NUnit.Tests1\NUnit.Tests1\FeatureFiles\GoogleGeoCode.feature:line 8
Result Message: System.NullReferenceException : Object reference not set to an instance of an object.
Your problem is likely that you have made your step async when this is not supported by specflow, so your method
public async Task WhenTheClientGetsResponseBy(string addr)
is probably returning on this line:
var response = await cl.GetStringAsync(uri);
and specflow is not waiting on the task, so its then continuing to the next step and then your root.results[0] is not set to anything, so null reference exception
Sam Holder, you are right,
I changed the code :
var response = await cl.GetStringAsync(uri);
To:
response = cl.GetStringAsync(uri).Result;
This solved my problem.

WEB API 1 - Pass JSON ARRAY from .NET CLIENT

I am trying to create one WEB API controller (Service method) which accept an array of a class object.
And then also a .NET client which makes a call to this API method and pass JSON string (array of class object). Issue is I am not able to receive json array contents on server side. Seems some serialization/de-serialization error but I am not able to spot. Please see sample code as below:
C# class as below:
public class UserData
{
public int ID { get; set; }
public DateTime DATETIME { get; set; }
public int SEQUENCE { get; set; }
}
And then WEB API method (API Controller as below)
[HttpPost()]
public HttpResponseMessage Post([FromBody()]
IEnumerable<#UserData> RequestBody)
{
}
Json array as below
[
{
"ID": 1,
"DATE": "2014-01-01",
"SEQUENCE": 533
},
{
"ID": 2,
"DATE": "2015-01-01",
"SEQUENCE": 3233
},
{
"ID": 3,
"DATE": "2015-01-01",
"SEQUENCE": 233
}
]
And the .NET Client as below:
public void CallService(string jsonString)
{
try {
var client = new RestClient(GetBaseURLService());
var requestRest = new RestRequest("event ", Method.POST);
var RequestBody = TextBoxCreateEventJson.Text;
requestRest.AddBody(jsonString);
requestRest.RequestFormat = DataFormat.Json;
var res = client.Execute(requestRest);
} catch (Exception ex) {
}
}
And then I get null/nothing in the RequestBody.
I know something I need to do before a call to requestRest.AddBody(jsonString);
But not sure what?
In System.Web.Helpers namespace, there is a Json class which you can use in order to encode or decode. For your case,
string jsonString = Json.Encode(your array as an argument)
Use jsonString in the body of your request.

Categories