deserialize json into list of anonymous type - asp.net

I have a json as below :
"[{"a":"b","c":"d"},{"a":"e","c":"f"},{"a":"g","c":"h"}]"
now I want to deserilize this into a list of objects of anonymous type "foo"
var foo=new { a=string.empty , c=string.empty };
the code is :
ServiceStackJsonSerializer Jserializer = new ServiceStackJsonSerializer();
dynamic foos = Jserializer.Deserialize<List<foo.GetType()>>(jsonString);
but not working .
update :
replacing ServiceStack with JavascriptSerializer and passing dictionary[] solved the problem without need to anonymous Type
JavaScriptSerializer jSerializer = new JavaScriptSerializer();
var Foos = jSerializer.Deserialize<Dictionary<string, object>[]>(jsonString);

I don't know what the Jserializer class is, but I do know of the JavaScriptSerializer class. Unfortunately, it doesn't support deserialization into anonymous types. You'll have to create a concrete type like this:
class Foo
{
public string a { get; set; }
public string c { get; set; }
}
Using the following code worked for me:
const string json =
#"[{""a"":""b"",""c"":""d""},{""a"":""e"",""c"":""f""},{""a"":""g"",""c"":""h""}]";
var foos = new JavaScriptSerializer().Deserialize<Foo[]>(json);
the variable foos will contain an array of Foo instances.

There are multiple ways you can dynamically parse JSON with ServiceStack's JsonSerializer e.g:
var json = "[{\"a\":\"b\",\"c\":\"d\"},{\"a\":\"e\",\"c\":\"f\"},{\"a\":\"g\",\"c\":\"h\"}]";
var dictionary = json.FromJson<List<Dictionary<string, string>>>();
".NET Collections:".Print();
dictionary.PrintDump();
List<JsonObject> map = JsonArrayObjects.Parse(json);
"Dynamically with JsonObject:".Print();
map.PrintDump();
Which uses ServiceStack's T.Dump() extension method to print out:
.NET Collections:
[
{
a: b,
c: d
},
{
a: e,
c: f
},
{
a: g,
c: h
}
]
Dynamically with JsonObject:
[
{
a: b,
c: d
},
{
a: e,
c: f
},
{
a: g,
c: h
}
]

For what you are trying to do it sounds like json.net would be a better fit. See this question
Deserialize json object into dynamic object using Json.net

The below example can deserialize JSON to a list of anonymous objects using NewtonSoft.Json's DeserializeAnonymousType method.
var json = System.IO.File.ReadAllText(#"C:\TestJSONFiles\yourJSONFile.json");
var fooDefinition = new { a = "", b = 0 }; // type with fields of string, int
var fooListDefinition = Enumerable.Range(0, 0).Select(e => fooDefinition).ToList();
var foos = JsonConvert.DeserializeAnonymousType(json, fooListDefinition);

Related

Rest Assured - Json - How to create a Map<time,count> from below JSON response?

API response json donot have any array name, it only has elements as time and count.
How can I store time and count in a Map.
Below is below Response JSON:
[ { "_time": "2021-10-28T00:00:00", "count": 10030.0 }, { "_time": "2021-10-29T00:00:00", "count": 7776.0 } ]
I have tried creating two list for _time and count , then storing it in a Map.
JsonPath js = new JsonPath(res.asString());
List<Float> count = js.getList("count");
List<String> time = js.getList("_time");
Map<String,Float> map = new LinkedHashMap<String,Float>();
Iterator<String> keyIter = time.iterator();
Iterator<Float> valIter = count.iterator();
while (keyIter.hasNext() && valIter.hasNext()) {
map.put(keyIter.next(), valIter.next());
}
But is there any other optimized way to do so?
I use this way.
Step 1: Deserialize response to POJO
import lombok.Data;
#Data
public class TimeObject {
private String _time;
private double count;
}
List<TimeObject> timeObjects = JsonPath.with(res.asString()).getList("", TimeObject.class);
Step2: Use java stream to collect a Map.
Map<String, List<Double>> collect = timeObjects.stream()
.collect(groupingBy(TimeObject::get_time,
mapping(TimeObject::getCount, toList())));
System.out.println(collect);
//{2021-10-28T00:00:00=[10030.0], 2021-10-29T00:00:00=[7776.0]}

How convert IConfigurationRoot or IConfigurationSection to JObject/JSON

I have the following code in my Program.cs:
var configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("clientsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"clientsettings.{host.GetSetting("environment")}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables()
.Build();
I want to convert the result of building my configuration to JObject\Json for sending to the client. How can I do it?
and I don't want to create my custom class for my settings.
My answer: merge
public static JObject GetSettingsObject(string environmentName)
{
object[] fileNames = { "settings.json", $"settings.{environmentName}.json" };
var jObjects = new List<object>();
foreach (var fileName in fileNames)
{
var fPath = Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + fileName;
if (!File.Exists(fPath))
continue;
using (var file = new StreamReader(fPath, Encoding.UTF8))
jObjects.Add(JsonConvert.DeserializeObject(file.ReadToEnd()));
}
if (jObjects.Count == 0)
throw new InvalidOperationException();
var result = (JObject)jObjects[0];
for (var i = 1; i < jObjects.Count; i++)
result.Merge(jObjects[i], new JsonMergeSettings
{
MergeArrayHandling = MergeArrayHandling.Merge
});
return result;
}
Since configuration is actually just a key value store where the keys have a certain format to represent a path, serializing it back into a JSON is not that simple.
What you could do is recursively traverse through the configuration children and write its values to a JObject. This would look like this:
public JToken Serialize(IConfiguration config)
{
JObject obj = new JObject();
foreach (var child in config.GetChildren())
{
obj.Add(child.Key, Serialize(child));
}
if (!obj.HasValues && config is IConfigurationSection section)
return new JValue(section.Value);
return obj;
}
Note that this is extremely limited in how the output looks. For example, numbers or booleans, which are valid types in JSON, will be represented as strings. And since arrays are represented through numerical key paths (e.g. key:0 and key:1), you will get property names that are strings of indexes.
Let’s take for example the following JSON:
{
"foo": "bar",
"bar": {
"a": "string",
"b": 123,
"c": true
},
"baz": [
{ "x": 1, "y": 2 },
{ "x": 3, "y": 4 }
]
}
This will be represented in configuration through the following key paths:
"foo" -> "bar"
"bar:a" -> "string"
"bar:b" -> "123"
"bar:c" -> "true"
"baz:0:x" -> "1"
"baz:0:y" -> "2"
"baz:1:x" -> "3"
"baz:1:y" -> "4"
As such, the resulting JSON for the above Serialize method would look like this:
{
"foo": "bar",
"bar": {
"a": "string",
"b": "123",
"c": "true"
},
"baz": {
"0": { "x": "1", "y": "2" },
"1": { "x": "3", "y": "4" }
}
}
So this will not allow you to get back the original representation. That being said, when reading the resulting JSON again with Microsoft.Extensions.Configuration.Json, then it will result in the same configuration object. So you can use this to store the configuration as JSON.
If you want anything prettier than that, you will have to add logic to detect array and non-string types, since both of these are not concepts of the configuration framework.
I want to merge appsettings.json and appsettings.{host.GetSetting("environment")}.json to one object [and send that to the client]
Keep in mind that environment-specific configuration files often contain secrets that shouldn’t leave the machine. This is also especially true for environment variables. If you want to transmit the configuration values, then make sure not to include the environment variables when building the configuration.
The configuration data is represented by a flattened collection of KeyValuePair<string, string>. You could create a dictionary from it and serialize that to JSON. However, that will probably not give you the desired result:
Configuration.AsEnumerable().ToDictionary(k => k.Key, v => v.Value);
Also, please take in mind that this configuration object will contain environment variables, you definitely don't want to send these to the client.
A better option might be to first bind the configuration to your POCO's and serialize those to JSON:
var appConfig = new AppConfig();
Configuration.Bind(appConfig);
var json = JsonConvert.SerializeObject(appConfig);
public class AppConfig
{
// Your settings here
public string Foo { get; set; }
public int Bar { get; set; }
}
The resultant IConfiguration object from the Build() method will encompass all of your configuration sources, and will merge based on the priority order defined by the order in which you added your config sources.
In your case this would be:
clientsettings.json
clientsettings.env.json
Environment Variables
You wont need to worry about merging sources manually or loading the files, as its already done for you.
To improve on poke's answer, I came up with this:
private JToken Serialize(IConfiguration config)
{
JObject obj = new JObject();
foreach (var child in config.GetChildren())
{
if (child.Path.EndsWith(":0"))
{
var arr = new JArray();
foreach (var arrayChild in config.GetChildren())
{
arr.Add(Serialize(arrayChild));
}
return arr;
}
else
{
obj.Add(child.Key, Serialize(child));
}
}
if (!obj.HasValues && config is IConfigurationSection section)
{
if (bool.TryParse(section.Value, out bool boolean))
{
return new JValue(boolean);
}
else if (decimal.TryParse(section.Value, out decimal real))
{
return new JValue(real);
}
else if (long.TryParse(section.Value, out int integer))
{
return new JValue(integer);
}
return new JValue(section.Value);
}
return obj;
}
The code above accounts for data types such as boolean, long & decimal.
long & decimal are the largest data types available for integers so will encompass any smaller values like short or float.
The code will also construct your arrays properly, so you end up with a like for like representation of all of your config in one json file.
Here is Tom's solution converted to use System.Text.Json.
static internal JsonNode? Serialize(IConfiguration config)
{
JsonObject obj = new();
foreach (var child in config.GetChildren())
{
if (child.Path.EndsWith(":0"))
{
var arr = new JsonArray();
foreach (var arrayChild in config.GetChildren())
{
arr.Add(Serialize(arrayChild));
}
return arr;
}
else
{
obj.Add(child.Key, Serialize(child));
}
}
if (obj.Count() == 0 && config is IConfigurationSection section)
{
if (bool.TryParse(section.Value, out bool boolean))
{
return JsonValue.Create(boolean);
}
else if (decimal.TryParse(section.Value, out decimal real))
{
return JsonValue.Create(real);
}
else if (long.TryParse(section.Value, out long integer))
{
return JsonValue.Create(integer);
}
return JsonValue.Create(section.Value);
}
return obj;
}
// Use like this...
var json = Serialize(Config);
File.WriteAllText("out.json",
json.ToJsonString(new JsonSerializerOptions() { WriteIndented = true}));
Do you really want to sent to client all your environment variables (.AddEnvironmentVariables()), connections string and all other stuff in appsettings??? I recommend you do not do this.
Instead, make one class (say ClientConfigOptions), configure it binding using services.Configure<ClientConfigOptions>(configuration.GetSection("clientConfig")) and send it to client.
With this approach, you may also tune your ClientConfigOptions with Actions, copy some values from different appsetting paths, etc.

Recursively Create ReadOnly Object in FlowJS

In redux, the state should be immutable. I would like Flow to prevent anyone from mutating that state. So, given an object of arbitrary depth:
type object = {
a: {
b: {
d: string
}
},
c: number
}
How can I create a new type that is recursively readonly, so that I cannot do:
let TestFunction = (param: $RecursiveReadOnly<object>) => {
param.a.b.d = 'some string'
}
The builtin $ReadOnly utility of Flow will create a type like this, which isn't what is needed, because b & d are still writable:
{
+a: {
b: {
d: string
}
},
+c: number
}
I've been trying to use the $Call & $ObjMap(i), but I can't figure out how to recursively travel an object in Flow. The objective is to have this:
{
+a: {
+b: {
+d: string
}
},
+c: number
}
Thanks to kalley for his solution. From what I understood, kalley tried to make any object received by a function recursively read only. Since I really only needed known objects as parameters, this works perfectly:
// Type definition that works with arbitrary nested objects/arrays etc.
declare type RecursiveReadOnly<O: Object> = $ReadOnly<$ObjMap<O, typeof makeRecursive>>
declare type RecursiveReadOnlyArray<O: Object> = $ReadOnlyArray<$ReadOnly<$ObjMap<O, typeof makeRecursive>>>
type Recursive<O: Object> = $ObjMap<O, typeof makeRecursive>
declare function makeRecursive<F: Function>(F): F
declare function makeRecursive<A: Object[]>(A): $ReadOnlyArray<$ReadOnly<Recursive<$ElementType<A, number>>>>
declare function makeRecursive<O: Object>(O): RecursiveReadOnly<O>
declare function makeRecursive<I: string[] | boolean[] | number[]>(I): $ReadOnlyArray<$ElementType<I, number>>
declare function makeRecursive<I: string | boolean | number | void | null>(I): I
// Usage example.
type obj = {
a: {
b: {
d: string,
}
}
}
let TestFunction = (param: RecursiveReadOnly<obj>) => {
param.a.b.d = 'some string' // Flow throws an error
}

Using Moq can you verify a method call with an anonymous type?

I'm trying to verify a method call using Moq, but I can't quite get the syntax right. Currently, I've got this as my verify:
repository.Verify(x => x.ExecuteNonQuery("fav_AddFavorites", new
{
fid = 123,
inputStr = "000456"
}), Times.Once());
The code compiles, but the test fails with the error:
Expected invocation on the mock once, but was 0 times:
x => x.ExecuteNonQuery("fav_AddFavorites", new <>f__AnonymousType0<Int32, String>(123, "000456"))
No setups configured.
Performed invocations:
IRepository.ExecuteNonQuery("fav_AddFavorites", { fid = 123, inputStr = 000456 })
How can I verify the method call and match the method parameters for an anonymous type?
UPDATE
To answer the questions:
I am trying to verify both that the method was called and that the parameters are correct.
The signature of the method I'm trying to verify is:
int ExecuteNonQuery(string query, object param = null);
The setup code is simply:
repository = new Mock<IRepository>();
UPDATE 2
It looks like this is a problem with Moq and how it handles anonymous types in .Net. The code posted by Paul Matovich runs fine, however, once the code and the test are in different assemblies the test fails.
This Passes
public class Class1
{
private Class2 _Class2;
public Class1(Class2 class2)
{
_Class2 = class2;
}
public void DoSomething(string s)
{
_Class2.ExecuteNonQuery(s, new { fid = 123, inputStr = "000456" });
}
}
public class Class2
{
public virtual void ExecuteNonQuery(string s, object o)
{
}
}
/// <summary>
///A test for ExecuteNonQuery
///</summary>
[TestMethod()]
public void ExecuteNonQueryTest()
{
string testString = "Hello";
var Class2Stub = new Mock<Class2>();
Class1 target = new Class1(Class2Stub.Object);
target.DoSomething(testString);
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.Equals(new { fid = 123, inputStr = "000456" }))), Times.Once());
}
##Update##
That is strange, it doesn't work in different assemblies. Someone can give us the long definition about why the object.equals from different assemblies behaves differently, but for different assemblies, this will work, any variance in the object values will return a different hash code.
Class2Stub.Verify(x => x.ExecuteNonQuery(testString, It.Is<object>(o => o.GetHashCode() == (new { fid = 123, inputStr = "000456" }).GetHashCode())), Times.Once());
One option is to "verify" it in a Callback. Obviously this needs to be done at Setup time, e.g.:
aMock.Setup(x => x.Method(It.IsAny<object>())).Callback<object>(
(p1) =>
{
dynamic o = p1;
Assert.That(o.Name, Is.EqualTo("Bilbo"));
});
None of the answers are great when your test assembly is different than the system under test's assembly (really common). Here's my solution that uses JSON serialization and then strings comparison.
Test Helper Function:
using Newtonsoft.Json;
public static class VerifyHelper
{
public static bool AreEqualObjects(object expected, object actual)
{
var expectedJson = JsonConvert.SerializeObject(expected);
var actualJson = JsonConvert.SerializeObject(actual);
return expectedJson == actualJson;
}
}
Example System Under Test:
public void DoWork(string input)
{
var obj = new { Prop1 = input };
dependency.SomeDependencyFunction(obj);
}
Example Unit Test:
var expectedObject = new { Prop1 = "foo" };
sut.DoWork("foo");
dependency.Verify(x => x.SomeDependencyFunction(It.Is<object>(y => VerifyHelper.AreEqualObjects(expectedObject, y))), Times.Once());
This solution is really simple, and I think makes the unit test easier to understand as opposed to the other answers in this thread. However, because it using simple string comparison, the test's anonymous object has to be set up exactly the same as the system under the test's anonymous object. Ergo, let's say you only cared to verify the value of a single property, but your system under test sets additional properties on the anonymous object, your unit test will need to set all those other properties (and in the same exact order) for the helper function to return true.
I created a reusable method based on Pauls answer:
object ItIsAnonymousObject(object value)
{
return It.Is<object>(o => o.GetHashCode() == value.GetHashCode());
}
...
dependency.Verify(
x => x.SomeDependencyFunction(ItIsAnonymousObject(new { Prop1 = "foo" })),
Times.Once());
Also, this can be used for property name case-insensitive comparison:
protected object ItIsAnonymousObject(object value)
{
var options = new JsonSerializerOptions { PropertyNamingPolicy = JsonNamingPolicy.CamelCase };
return It.Is<object>(o => JsonSerializer.Serialize(o, options) == JsonSerializer.Serialize(value, options));
}

Question about using Anonymous List Types

private List<T> GetFieldList()
{
var Fields = new { DisplayName = "MCP", FieldName = "t.MCP", FieldType = 1 };
var FieldList = (new[] { Fields }).ToList();
return FieldList;
}
Should I be able to do something like this?
If I understand correctly your tag "asp.net" this construction will be used as part of data binding.
Just use non generic :
private IList GetFieldList()
{
var Fields = new { DisplayName = "MCP", FieldName = "t.MCP", FieldType = 1 };
IList FieldList = (new[] { Fields }).ToList();
return FieldList;
}
It would be nice handled by all data-bound controls.
I just realized I don't need to use an anonymous list as I know the structure of the data I'm expecting, so I'll just create a small class for it.

Resources