I have testdata.json with object like this:
"Entity": {
"ID": "1",
"name": "some name",
"City": "some city",
"address": "some address"
}
Here are my 2 methods for withdrawing and deserializing this entity:
public static string ReadSettings(string name)
{
var parts = name.Split('.', StringSplitOptions.RemoveEmptyEntries);
JObject jObj = GetObject();
foreach (var part in parts)
{
var token = jObj[part];
if (token == null)
{
return null;
}
else
{
return token.ToString();
}
}
return null;
}
private static JObject GetObject()
{
if (_jObject != null)
{
return _jObject;
}
var filename = Path.Combine(
Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!,
"testdata.json");
var json = File.ReadAllText(filename);
_jObject = JObject.Parse(json);
return _jObject;
}
My question is next: is there any way I can replace Entity.ID with random number (I need this in tests, where I create new Entity - every time test runs - there should be new Entity with new unique ID)?
p.s. I'm just learning C# so don't judge me hardly if it's simple question =)
I suppose the given testdata.json content is not the real thing since running JObject.Parse() on it gives an exception. However, you can navigate to a property with the string key indexer of the JObject class and change it as:
// Generate a new random value.
var random = new Random();
var randomValue = random.Next(minValue, maxValue);
// Navigate to the property and assign the random value as a string.
_jObject["Entity"]["ID"] = randomValue.ToString();
The property navigation of course needs to match the structure of your Json.
Related
For some of my unit tests I want the ability to build up particular JSON values (record albums in this case) that can be used as input for the system under test.
I have the following code:
var jsonObject = new JObject();
jsonObject.Add("Date", DateTime.Now);
jsonObject.Add("Album", "Me Against The World");
jsonObject.Add("Year", 1995);
jsonObject.Add("Artist", "2Pac");
This works fine, but I have never really like the "magic string" syntax and would prefer something closer to the expando-property syntax in JavaScript like this:
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against The World";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
Well, how about:
dynamic jsonObject = new JObject();
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against the world";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
You can use the JObject.Parse operation and simply supply single quote delimited JSON text.
JObject o = JObject.Parse(#"{
'CPU': 'Intel',
'Drives': [
'DVD read/writer',
'500 gigabyte hard drive'
]
}");
This has the nice benefit of actually being JSON and so it reads as JSON.
Or you have test data that is dynamic you can use JObject.FromObject operation and supply a inline object.
JObject o = JObject.FromObject(new
{
channel = new
{
title = "James Newton-King",
link = "http://james.newtonking.com",
description = "James Newton-King's blog.",
item =
from p in posts
orderby p.Title
select new
{
title = p.Title,
description = p.Description,
link = p.Link,
category = p.Categories
}
}
});
Json.net documentation for serialization
Neither dynamic, nor JObject.FromObject solution works when you have JSON properties that are not valid C# variable names e.g. "#odata.etag". I prefer the indexer initializer syntax in my test cases:
JObject jsonObject = new JObject
{
["Date"] = DateTime.Now,
["Album"] = "Me Against The World",
["Year"] = 1995,
["Artist"] = "2Pac"
};
Having separate set of enclosing symbols for initializing JObject and for adding properties to it makes the index initializers more readable than classic object initializers, especially in case of compound JSON objects as below:
JObject jsonObject = new JObject
{
["Date"] = DateTime.Now,
["Album"] = "Me Against The World",
["Year"] = 1995,
["Artist"] = new JObject
{
["Name"] = "2Pac",
["Age"] = 28
}
};
With object initializer syntax, the above initialization would be:
JObject jsonObject = new JObject
{
{ "Date", DateTime.Now },
{ "Album", "Me Against The World" },
{ "Year", 1995 },
{ "Artist", new JObject
{
{ "Name", "2Pac" },
{ "Age", 28 }
}
}
};
There are some environment where you cannot use dynamic (e.g. Xamarin.iOS) or cases in where you just look for an alternative to the previous valid answers.
In these cases you can do:
using Newtonsoft.Json.Linq;
JObject jsonObject =
new JObject(
new JProperty("Date", DateTime.Now),
new JProperty("Album", "Me Against The World"),
new JProperty("Year", "James 2Pac-King's blog."),
new JProperty("Artist", "2Pac")
)
More documentation here:
http://www.newtonsoft.com/json/help/html/CreatingLINQtoJSON.htm
Sooner or later you will have property with a special character. e.g. Create-Date. The hyphen won't be allowed in property name. This will break your code. In such scenario, You can either use index or combination of index and property.
dynamic jsonObject = new JObject();
jsonObject["Create-Date"] = DateTime.Now; //<-Index use
jsonObject.Album = "Me Against the world"; //<- Property use
jsonObject["Create-Year"] = 1995; //<-Index use
jsonObject.Artist = "2Pac"; //<-Property use
Simple way of creating newtonsoft JObject from Properties.
This is a Sample User Properties
public class User
{
public string Name;
public string MobileNo;
public string Address;
}
and i want this property in newtonsoft JObject is:
JObject obj = JObject.FromObject(new User()
{
Name = "Manjunath",
MobileNo = "9876543210",
Address = "Mumbai, Maharashtra, India",
});
Output will be like this:
{"Name":"Manjunath","MobileNo":"9876543210","Address":"Mumbai, Maharashtra, India"}
May I suggest using the nameof expression combined with a model for the structure you're trying to build?
Example:
record RecordAlbum(string Album, string Artist, int Year);
var jsonObject = new JObject
{
{ nameof(RecordAlbum.Album), "Me Against The World" },
{ nameof(RecordAlbum.Artist), "2Pac" },
{ nameof(RecordAlbum.Year), 1995 }
};
As an added benefit to removing the "magic string" aspect - this also will give you a little bit of refactor-ability. You can easily rename any given property name for the record and it should update the value returned by the nameof() expression.
You can use Newtonsoft library and use it as follows
using Newtonsoft.Json;
public class jb
{
public DateTime Date { set; get; }
public string Artist { set; get; }
public int Year { set; get; }
public string album { set; get; }
}
var jsonObject = new jb();
jsonObject.Date = DateTime.Now;
jsonObject.Album = "Me Against The World";
jsonObject.Year = 1995;
jsonObject.Artist = "2Pac";
System.Web.Script.Serialization.JavaScriptSerializer oSerializer =
new System.Web.Script.Serialization.JavaScriptSerializer();
string sJSON = oSerializer.Serialize(jsonObject );
I am using Json.Net to parse my JSON
This is my JSON:
"OptionType": {
"C": [
"C",
"Call"
],
"P": [
"P",
"Put"
]
}
Before this step, when processed, as a result, I would get a value from any of this.
For example Option Type: Call
Whatever value I get, I need it to be transcodified according to the above JSON.
Example: Option Type: C
First of all your sample data is not a valid JSON. You need to wrap it to the curvy braces.
If your sample is a part of the JSON object, you can map OptionType to the Dictionary<string, List<string>>.
To find valid option you will need to iterate this dictionary like in the sample below:
var valueToCheck = "Call";
string type = null;
foreach (var kvp in optionTypes)
{
if (kvp.Value.Contains(valueToCheck))
{
type = kvp.Key;
break;
}
}
Same using JObject with fixed JSON data:
var json = #"{
""OptionType"":{
""C"": [
""C"",
""Call""
],
""P"": [
""P"",
""Put""
]
}
}";
var valueToCheck = "Call";
string type = null;
var ot = JObject.Parse(json);
var objectType = ot["OptionType"];
foreach (var token in objectType)
{
var prop = token.ToObject<JProperty>();
var key = prop.Name;
var values = prop.Value.ToObject<List<string>>();
if (values.Contains(valueToCheck))
{
type = key;
break;
}
}
Code is not perfect but it is just an idea what to do.
You need to iterate over properties of JObject and then search your option type and then replace your search option with its parent key.
This is custom function can do above task.
public static JObject GetJObject(JObject jObject, List<string> optionType)
{
foreach (var type in jObject["OptionType"])
{
var key = type.ToObject<JProperty>().Name;
var values = type.ToObject<JProperty>().Value.ToObject<List<string>>();
foreach (var option in optionType)
{
if (values.Contains(option))
{
int index = values.IndexOf(option);
values.RemoveAt(index);
values.Insert(index, key);
}
}
JToken jToken = JToken.FromObject(values);
jObject.SelectToken("OptionType." + key).Replace(jToken);
}
return jObject;
}
And you can use above custom function this like
string json = File.ReadAllText(#"Path to your json file");
JObject jObject = JObject.Parse(json);
List<string> optionType = new List<string> { "Call", "Put" };
JObject result = GetJObject(jObject, optionType);
Output:
I am trying to match a complex json-object to a user-defined filter/predicate by using Json.NET and System.Linq.Dynamic. Here is my code:
var json = #"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant""}";
dynamic person = JObject.Parse(json);
var people = new[] { person };
var isMatch = people.Where("Name=#0", "Jane Doe").Any();
Console.WriteLine(isMatch);
This gives me an error on the line with the Where-statement:
No property or field 'Name' exists in type 'Object'
If I instead use an anonymous object, by replacing the second line with this, it works as it should:
var person = new { Name = "Jane Doe", Occupation = "FBI Consultant"};
Is there another way to deserialize the json string that will allow me to query it by a string predicate to check if the json object matches?
EDIT: The json-string and Where-statement is dynamic and is supplied by the user. There are lots of properties, and i do not know their names before executing the code. Both the name of the field and the value is supplied by the user.
var json = #"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant""}";
dynamic person = JObject.Parse(json);
var people = new List<object>(){ person };
var filedName = "Name";
var searchValue = "Jane Doe";
var any = people.Any(p => p.GetType().GetProperty(filedName).GetValue(p, null) as string == searchValue);
Replace your Where statement with this:
var isMatch = people.Where(x => x.Name == "Jane Doe").Any();
Which can be simplified as:
var isMatch = people.Any(x => x.Name == "Jane Doe");
This may not be what you want, but simple System.Linq can fulfill your needs easily.
For the case you want to do this dynamically:
var isMatch = people.Any(x => x.GetValue("Name") == "Jane Doe");
After reading the answers and also others posts i created this solution:
void Main()
{
var json = #"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant"", ""Info"": {""Age"":28, ""Gender"":""Female""}}";
Console.WriteLine("Match Name: " + json.JsonMatch("Name", "Jane Doe"));
Console.WriteLine("Match Age: " + json.JsonMatch("Info.Age", "28"));
}
public static bool JsonMatch(this string json, string key, string value)
{
dynamic obj = JObject.Parse(json);
var values = obj.PropertyValues();
foreach (var element in values)
{
if (element.Path == key)
{
return element.Value == value;
}
if (element.Path == null)
{
foreach (var subelement in element)
{
if (subelement.Path == key)
{
return subelement.Value == value;
}
}
}
}
return false;
}
Hope it helps somebody.
EDIT
Thank you for your comments, that is actually making a difference.
Sorry for a bit late answer, but maybe it still would be helpful.
Below complete test that works with dynamic parameter name and parameter value:
// Given
var json = #"{""Name"":""Jane Doe"",""Occupation"":""FBI Consultant""}";
var person = JObject.Parse(json);
var people = new[] {person};
// When
var isMatch = people.Any(p => p.GetValue("Name").Value<string>() == "Jane Doe");
// Then
Assert.IsTrue(isMatch);
How can I access the MongoCursor attributes in C#.
I have the following line of code:
MongoCursor results = collection.Find(searchQuery).SetLimit(10).SetFields(
Fields.Include("name1","name", "_id"));
MongoDB returns an array, each one with two attributes: name and name1. In the results View in the debugger,, I can see an array, each item in the array contains a MongoDB.Bson.BsonDocument.
I want to have a dot notation access to the attributes of each BsonDocument in the Array. How can I achieve this.?
Came across this issue when I had to work with raw BsonDocuments. This solution does allow you to use dot notation.
Not fully tested or anything, but may be useful.
void Main()
{
var example = new BsonDocument{
{ "customer", new BsonDocument { { "email" , "homerjay#simpsons.com" } }}
};
var email = example.GetPath("customer.email").AsString;
Console.WriteLine(email);
}
public static class MongoDbHelper
{
public static BsonValue GetPath(this BsonValue bson, string path)
{
if (bson.BsonType != BsonType.Document)
{
throw new Exception("Not a doc");
}
var doc = bson.AsBsonDocument;
var tokens = path.Split(".".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
if (tokens.Length == 0 )
{
return doc;
}
if (!doc.Contains(tokens[0]))
{
return BsonNull.Value;
}
if (tokens.Length > 1)
{
return GetPath(doc[tokens[0]], tokens[1]);
}
return doc[tokens[0]];
}
}
To get values out of a BsonDocument you can use the GetValue/TryGetValue methods or the indexer:
foreach (var document in results)
{
var name1 = document.GetValue("name1");
var name = document["name"];
}
List<User> list = LoadUsers();
JObject json = new JObject();
json["users"] = new JValue(list);
Doesn't seem to be working?
Error:
Could not determine JSON object type for type System.Collections.Generic.List`1
A JValue can only contain simple values like strings, ints, booleans, dates and the like. It cannot contain a complex object. I suspect what you really want is this:
List<User> list = LoadUsers();
JObject json = new JObject();
json["users"] = JToken.FromObject(list);
The above will convert the list of User objects into a JArray of JObjects representing the users, then assign that to the users property on the new JObject. You can confirm this by examining the Type property of json["users"] and see that it is Array.
In contrast, if you do json["users"] = new JValue(JsonConvert.SerializeObject(list)) as was suggested in another answer to this question (now deleted), you will probably not get the result you are looking for. That approach will serialize the list of users to a string, create a simple JValue from that, and then assign the JValue to the users property on the JObject. If you examine the Type property of json["users"], you will see that it is String. What this means is, if you later try to convert the JObject to JSON by using json.ToString(), you will get double-serialized output instead of the JSON you probably expect.
Here is a short demo to illustrate the difference:
class Program
{
static void Main(string[] args)
{
List<User> list = new List<User>
{
new User { Id = 1, Username = "john.smith" },
new User { Id = 5, Username = "steve.martin" }
};
JObject json = new JObject();
json["users"] = JToken.FromObject(list);
Console.WriteLine("First approach (" + json["users"].Type + "):");
Console.WriteLine();
Console.WriteLine(json.ToString(Formatting.Indented));
Console.WriteLine();
Console.WriteLine(new string('-', 30));
Console.WriteLine();
json["users"] = new JValue(JsonConvert.SerializeObject(list));
Console.WriteLine("Second approach (" + json["users"].Type + "):");
Console.WriteLine();
Console.WriteLine(json.ToString(Formatting.Indented));
}
class User
{
public int Id { get; set; }
public string Username { get; set; }
}
}
Output:
First approach (Array):
{
"users": [
{
"Id": 1,
"Username": "john.smith"
},
{
"Id": 5,
"Username": "steve.martin"
}
]
}
------------------------------
Second approach (String):
{
"users": "[{\"Id\":1,\"Username\":\"john.smith\"},{\"Id\":5,\"Username\":\"steve.martin\"}]"
}
I had this issue, you can now use JArray to get this done, if you just want the array items with no root name.
var json = JArray.FromObject(LoadUsers());
If you want the root name of the json array to be "users", you can use
var json = new JObject { ["users"] = JToken.FromObject(LoadUsers()) };