diff --git a/Projects/Json Deserialization/JsonDeserialization.csproj b/Projects/Json Deserialization/JsonDeserialization.csproj new file mode 100644 index 0000000..318d534 --- /dev/null +++ b/Projects/Json Deserialization/JsonDeserialization.csproj @@ -0,0 +1,63 @@ + + + + + + Debug + AnyCPU + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049} + Exe + JsonDeserialization + JsonDeserialization + v4.8 + 512 + true + {A1948822-69DD-4150-919B-F3F42EFB71CC};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + packages\GHIElectronics.TinyCLR.Data.Json.2.3.0.1000\lib\net48\GHIElectronics.TinyCLR.Data.Json.dll + + + packages\GHIElectronics.TinyCLR.IO.2.3.0.1000\lib\net48\GHIElectronics.TinyCLR.IO.dll + + + packages\GHIElectronics.TinyCLR.Native.2.3.0.1000\lib\net48\GHIElectronics.TinyCLR.Native.dll + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + \ No newline at end of file diff --git a/Projects/Json Deserialization/JsonDeserialization.sln b/Projects/Json Deserialization/JsonDeserialization.sln new file mode 100644 index 0000000..9be996d --- /dev/null +++ b/Projects/Json Deserialization/JsonDeserialization.sln @@ -0,0 +1,24 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonDeserialization", "JsonDeserialization.csproj", "{8D4CEC68-E37D-457C-ACE6-AABC60C4C049}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049}.Debug|Any CPU.Deploy.0 = Debug|Any CPU + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049}.Release|Any CPU.Build.0 = Release|Any CPU + {8D4CEC68-E37D-457C-ACE6-AABC60C4C049}.Release|Any CPU.Deploy.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/Projects/Json Deserialization/Program.cs b/Projects/Json Deserialization/Program.cs new file mode 100644 index 0000000..13f05fa --- /dev/null +++ b/Projects/Json Deserialization/Program.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections; +using System.Diagnostics; +using System.Text; +using System.Threading; + +using GHIElectronics.TinyCLR.Data.Json; +using GHIElectronics.TinyCLR.Native; + +namespace JsonDeserialization +{ + internal class Program + { + // This text is a result of a call to : https://api.openweathermap.org/data/2.5/weather?lat=42.49&lon=83.11&appid={your api key here} + // Documented here : https://openweathermap.org/current + const string JsonText = "{\"coord\":{\"lon\":-83.11,\"lat\":42.49},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"base\":\"stations\",\"main\":{\"temp\":266.74,\"feels_like\":266.74,\"temp_min\":265.88,\"temp_max\":267.99,\"pressure\":1041,\"humidity\":62,\"sea_level\":1041,\"grnd_level\":1014},\"visibility\":10000,\"wind\":{\"speed\":1.03,\"deg\":0},\"clouds\":{\"all\":0},\"dt\":1734112973,\"sys\":{\"type\":2,\"id\":2043784,\"country\":\"US\",\"sunrise\":1734094446,\"sunset\":1734127192},\"timezone\":-18000,\"id\":5000500,\"name\":\"Madison Heights\",\"cod\":200}"; + +#pragma warning disable IDE1006 // Naming Styles - properties that start with lower case letter + + internal class OwxCoordinates { + public float lon { get; set; } + public float lat { get; set; } + } + + internal class OwxWeather { + public uint id { get; set; } + public string name { get; set; } + public string description { get; set; } + public string icon { get; set; } + } + + internal class OwxMain { + public float temp { get; set; } + public float feels_like { get; set; } + public float temp_min { get; set; } + public float temp_max { get; set; } + public uint pressure { get; set; } + public uint humidity { get; set; } + public uint sea_level { get; set; } + public uint grnd_level { get; set; } + } + + internal class OwxWind { + public float speed { get; set; } + public int deg { get; set; } + } + + internal class OwxSys { + public int type { get; set; } + public uint id { get; set; } + public string country { get; set; } + public uint sunrise { get; set; } + public uint sunset { get; set; } + } + + internal class OpenWeatherReport { + public OwxCoordinates coord { get; set; } + public OwxWeather[] weather { get; set; } + public string @base { get; set; } + public OwxMain main { get; set; } + public uint visibility { get; set; } + public OwxWind wind { get; set; } + public ulong dt { get; set; } + public OwxSys sys { get; set; } + public int timezone { get; set; } + public uint id { get; set; } + public string name { get; set; } + public uint cod { get; set; } + } +#pragma warning restore IDE1006 // Naming Styles - properties that start with lower case letter + + /// + /// Because TinyCLR doesn't give us enough type information about arrays, we have to have a + /// helper function that will instantiate the array and each member in the array. We will get + /// called for every type being instantiated, but we only have to return instances for arrays + /// and members in arrays, though you could also use this to return child types for polymorphic + /// members of classes. + /// + /// The full json path to the member being created. + /// The root token for the json currently being deserialized. You could inspect this to pull + /// out dynamic information (e.g., structures not known at compile time) + /// The type of the object we are deserializing into. This will be null when instantiating + /// the individual elements of an array, so you must use the path to decide what type of element to instantiate. + /// not used + /// When instantiating arrays, this will be the number of elements we need to allocate. + /// + private static object WxCreateInstance(string path, JToken root, Type baseType, string name, int length) { + // A little debug output to help you with decoding your own types... + if (baseType != null) { + Debug.Write("Base type = " + baseType.FullName + " "); + } + Debug.WriteLine("Path = " + path + " Name = " + name + " Length = " + length); + + // Allocate arrays and members of arrays (we can ignore all other cases and return null) + switch (path) { + case "/": + switch (name) { + case "weather": + // The 'weather' element at the root of the json is an array. Allocate the + // array space. Length will be >= 0 + return new OwxWeather[length]; + } + break; + case "//weather": + // This is asking us to allocate a single element to store in the 'weather' array + // at the root of the json tree. Length will be -1 and the baseType will be null. + // If TinyCLR would tell us the baseType, we wouldn't need this CreateInstance routine + // at all, but this issue dates back to the origin of netMF. + return new OwxWeather(); + } + return null; + } + + static void Main() { + var weather = (OpenWeatherReport)JsonConverter.DeserializeObject(JsonText, typeof(OpenWeatherReport), WxCreateInstance); + Debug.WriteLine("Current Temperature (K) is " + weather.main.temp + " but it feels like " + weather.main.feels_like); + } + } +} diff --git a/Projects/Json Deserialization/Properties/AssemblyInfo.cs b/Projects/Json Deserialization/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..2f10294 --- /dev/null +++ b/Projects/Json Deserialization/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JsonDeserialization")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JsonDeserialization")] +[assembly: AssemblyCopyright("Copyright © 2024")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8d4cec68-e37d-457c-ace6-aabc60c4c049")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/Projects/Json Deserialization/packages.config b/Projects/Json Deserialization/packages.config new file mode 100644 index 0000000..59d059f --- /dev/null +++ b/Projects/Json Deserialization/packages.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file