├── .gitattributes ├── .gitignore ├── JsonCSharpClassGeneratorLib ├── CodeWriters │ ├── CSharpCodeWriter.cs │ ├── JavaCodeWriter.cs │ ├── TypeScriptCodeWriter.cs │ └── VisualBasicCodeWriter.cs ├── FieldInfo.cs ├── FodyWeavers.xml ├── ICodeWriter.cs ├── IJsonClassGeneratorConfig.cs ├── JsonClassGenerator.cs ├── JsonClassGeneratorLib.csproj ├── JsonClassHelper.cs ├── JsonType.cs ├── JsonTypeEnum.cs ├── LICENSE └── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── JsonDataContextBase ├── JsonDataContextBase.cs ├── JsonDataContextBase.csproj ├── JsonFileBase.cs ├── Properties │ └── AssemblyInfo.cs └── packages.config ├── JsonDataContextDriver ├── DevDeploy.bat ├── Extensions │ ├── Extensions.cs │ ├── FolderSelectDialog │ │ ├── FolderSelectDialog.cs │ │ ├── README.md │ │ └── Reflector.cs │ ├── LinqPadSampleCode.cs │ └── NotepadHelper.cs ├── FodyWeavers.xml ├── Inputs │ ├── IGeneratedClass.cs │ ├── IJsonInput.cs │ ├── JsonFileGeneratedClass.cs │ ├── JsonFileInput.cs │ ├── JsonInputType.cs │ ├── JsonTextGeneratedClass.cs │ ├── JsonTextInput.cs │ ├── JsonUrlGeneratedClass.cs │ └── JsonUrlInput.cs ├── JsonDataContextDriver.csproj ├── JsonDataContextDriver.sln ├── JsonDynamicDataContextDriver.cs ├── Properties │ └── AssemblyInfo.cs ├── Views │ ├── AddNewFileSourceDialog.xaml │ ├── AddNewFileSourceDialog.xaml.cs │ ├── AddNewFolderSourceDialog.xaml │ ├── AddNewFolderSourceDialog.xaml.cs │ ├── AddNewTextSourceDialog.xaml │ ├── AddNewTextSourceDialog.xaml.cs │ ├── AddNewUrlSourceDialog.xaml │ ├── AddNewUrlSourceDialog.xaml.cs │ ├── ConnectionDialog.xaml │ └── ConnectionDialog.xaml.cs └── packages.config ├── LICENSE └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studo 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | *_i.c 42 | *_p.c 43 | *_i.h 44 | *.ilk 45 | *.meta 46 | *.obj 47 | *.pch 48 | *.pdb 49 | *.pgc 50 | *.pgd 51 | *.rsp 52 | *.sbr 53 | *.tlb 54 | *.tli 55 | *.tlh 56 | *.tmp 57 | *.tmp_proj 58 | *.log 59 | *.vspscc 60 | *.vssscc 61 | .builds 62 | *.pidb 63 | *.svclog 64 | *.scc 65 | 66 | # Chutzpah Test files 67 | _Chutzpah* 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | *.cachefile 76 | 77 | # Visual Studio profiler 78 | *.psess 79 | *.vsp 80 | *.vspx 81 | 82 | # TFS 2012 Local Workspace 83 | $tf/ 84 | 85 | # Guidance Automation Toolkit 86 | *.gpState 87 | 88 | # ReSharper is a .NET coding add-in 89 | _ReSharper*/ 90 | *.[Rr]e[Ss]harper 91 | *.DotSettings.user 92 | 93 | # JustCode is a .NET coding addin-in 94 | .JustCode 95 | 96 | # TeamCity is a build add-in 97 | _TeamCity* 98 | 99 | # DotCover is a Code Coverage Tool 100 | *.dotCover 101 | 102 | # NCrunch 103 | _NCrunch_* 104 | .*crunch*.local.xml 105 | 106 | # MightyMoose 107 | *.mm.* 108 | AutoTest.Net/ 109 | 110 | # Web workbench (sass) 111 | .sass-cache/ 112 | 113 | # Installshield output folder 114 | [Ee]xpress/ 115 | 116 | # DocProject is a documentation generator add-in 117 | DocProject/buildhelp/ 118 | DocProject/Help/*.HxT 119 | DocProject/Help/*.HxC 120 | DocProject/Help/*.hhc 121 | DocProject/Help/*.hhk 122 | DocProject/Help/*.hhp 123 | DocProject/Help/Html2 124 | DocProject/Help/html 125 | 126 | # Click-Once directory 127 | publish/ 128 | 129 | # Publish Web Output 130 | *.[Pp]ublish.xml 131 | *.azurePubxml 132 | # TODO: Comment the next line if you want to checkin your web deploy settings 133 | # but database connection strings (with potential passwords) will be unencrypted 134 | *.pubxml 135 | *.publishproj 136 | 137 | # NuGet Packages 138 | *.nupkg 139 | # The packages folder can be ignored because of Package Restore 140 | **/packages/* 141 | # except build/, which is used as an MSBuild target. 142 | !**/packages/build/ 143 | # Uncomment if necessary however generally it will be regenerated when needed 144 | #!**/packages/repositories.config 145 | 146 | # Windows Azure Build Output 147 | csx/ 148 | *.build.csdef 149 | 150 | # Windows Store app package directory 151 | AppPackages/ 152 | 153 | # Others 154 | *.[Cc]ache 155 | ClientBin/ 156 | [Ss]tyle[Cc]op.* 157 | ~$* 158 | *~ 159 | *.dbmdl 160 | *.dbproj.schemaview 161 | *.pfx 162 | *.publishsettings 163 | node_modules/ 164 | bower_components/ 165 | 166 | # RIA/Silverlight projects 167 | Generated_Code/ 168 | 169 | # Backup & report files from converting an old project file 170 | # to a newer Visual Studio version. Backup files are not needed, 171 | # because we have git ;-) 172 | _UpgradeReport_Files/ 173 | Backup*/ 174 | UpgradeLog*.XML 175 | UpgradeLog*.htm 176 | 177 | # SQL Server files 178 | *.mdf 179 | *.ldf 180 | 181 | # Business Intelligence projects 182 | *.rdl.data 183 | *.bim.layout 184 | *.bim_*.settings 185 | 186 | # Microsoft Fakes 187 | FakesAssemblies/ 188 | 189 | # Node.js Tools for Visual Studio 190 | .ntvs_analysis.dat 191 | 192 | # Visual Studio 6 build log 193 | *.plg 194 | 195 | # Visual Studio 6 workspace options file 196 | *.opt 197 | 198 | *.snk -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/CodeWriters/CSharpCodeWriter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Xamasoft.JsonClassGenerator.CodeWriters 9 | { 10 | public class CSharpCodeWriter : ICodeWriter 11 | { 12 | private static HashSet _csharpKeywords = new HashSet 13 | { 14 | "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked", "class", "const", "continue", "decimal", "default", 15 | "delegate", "do", "double", "else", "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach", "goto", 16 | "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long", "namespace", "new", "null", "object", "operator", "out", 17 | "override", "params", "private", "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof", "stackalloc", 18 | "static", "string", "struct", "switch", "this", "throw", "true", "try", "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", 19 | "virtual", "void", "volatile", "while" 20 | }; 21 | 22 | public string FileExtension 23 | { 24 | get { return ".cs"; } 25 | } 26 | 27 | public string DisplayName 28 | { 29 | get { return "C#"; } 30 | } 31 | 32 | 33 | private const string NoRenameAttribute = "[Obfuscation(Feature = \"renaming\", Exclude = true)]"; 34 | private const string NoPruneAttribute = "[Obfuscation(Feature = \"trigger\", Exclude = false)]"; 35 | 36 | public string GetTypeName(JsonType type, IJsonClassGeneratorConfig config) 37 | { 38 | var arraysAsLists = !config.ExplicitDeserialization; 39 | 40 | switch (type.Type) 41 | { 42 | case JsonTypeEnum.Anything: return "object"; 43 | case JsonTypeEnum.Array: return arraysAsLists ? "IList<" + GetTypeName(type.InternalType, config) + ">" : GetTypeName(type.InternalType, config) + "[]"; 44 | case JsonTypeEnum.Dictionary: return "Dictionary"; 45 | case JsonTypeEnum.Boolean: return "bool"; 46 | case JsonTypeEnum.Float: return "double"; 47 | case JsonTypeEnum.Integer: return "int"; 48 | case JsonTypeEnum.Long: return "long"; 49 | case JsonTypeEnum.Date: return "DateTime"; 50 | case JsonTypeEnum.NonConstrained: return "object"; 51 | case JsonTypeEnum.NullableBoolean: return "bool?"; 52 | case JsonTypeEnum.NullableFloat: return "double?"; 53 | case JsonTypeEnum.NullableInteger: return "int?"; 54 | case JsonTypeEnum.NullableLong: return "long?"; 55 | case JsonTypeEnum.NullableDate: return "DateTime?"; 56 | case JsonTypeEnum.NullableSomething: return "object"; 57 | case JsonTypeEnum.Object: return type.AssignedName; 58 | case JsonTypeEnum.String: return "string"; 59 | default: throw new NotSupportedException("Unsupported json type"); 60 | } 61 | } 62 | 63 | 64 | private bool ShouldApplyNoRenamingAttribute(IJsonClassGeneratorConfig config) 65 | { 66 | return config.ApplyObfuscationAttributes && !config.ExplicitDeserialization && !config.UsePascalCase; 67 | } 68 | private bool ShouldApplyNoPruneAttribute(IJsonClassGeneratorConfig config) 69 | { 70 | return config.ApplyObfuscationAttributes && !config.ExplicitDeserialization && config.UseProperties; 71 | } 72 | 73 | public void WriteFileStart(IJsonClassGeneratorConfig config, TextWriter sw) 74 | { 75 | if (config.UseNamespaces) 76 | { 77 | foreach (var line in JsonClassGenerator.FileHeader) 78 | { 79 | sw.WriteLine("// " + line); 80 | } 81 | sw.WriteLine(); 82 | sw.WriteLine("using System;"); 83 | sw.WriteLine("using System.Collections.Generic;"); 84 | if (ShouldApplyNoPruneAttribute(config) || ShouldApplyNoRenamingAttribute(config)) 85 | sw.WriteLine("using System.Reflection;"); 86 | if (!config.ExplicitDeserialization && config.UsePascalCase) 87 | sw.WriteLine("using Newtonsoft.Json;"); 88 | sw.WriteLine("using Newtonsoft.Json.Linq;"); 89 | if (config.ExplicitDeserialization) 90 | sw.WriteLine("using JsonCSharpClassGenerator;"); 91 | if (config.SecondaryNamespace != null && config.HasSecondaryClasses && !config.UseNestedClasses) 92 | { 93 | sw.WriteLine("using {0};", config.SecondaryNamespace); 94 | } 95 | } 96 | 97 | if (config.UseNestedClasses) 98 | { 99 | sw.WriteLine(" {0} class {1}", config.InternalVisibility ? "internal" : "public", config.MainClass); 100 | sw.WriteLine(" {"); 101 | } 102 | } 103 | 104 | public void WriteFileEnd(IJsonClassGeneratorConfig config, TextWriter sw) 105 | { 106 | if (config.UseNestedClasses) 107 | { 108 | sw.WriteLine(" }"); 109 | } 110 | } 111 | 112 | 113 | public void WriteNamespaceStart(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 114 | { 115 | sw.WriteLine(); 116 | sw.WriteLine("namespace {0}", root && !config.UseNestedClasses ? config.Namespace : (config.SecondaryNamespace ?? config.Namespace)); 117 | sw.WriteLine("{"); 118 | sw.WriteLine(); 119 | } 120 | 121 | public void WriteNamespaceEnd(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 122 | { 123 | sw.WriteLine("}"); 124 | } 125 | 126 | public void WriteClass(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type) 127 | { 128 | var visibility = (config.InternalVisibility ? "internal" : "public") + (config.GeneratePartialClasses ? " partial" : ""); 129 | 130 | if (config.UseNestedClasses) 131 | { 132 | if (!type.IsRoot) 133 | { 134 | if (ShouldApplyNoRenamingAttribute(config)) sw.WriteLine(" " + NoRenameAttribute); 135 | if (ShouldApplyNoPruneAttribute(config)) sw.WriteLine(" " + NoPruneAttribute); 136 | sw.WriteLine(" {0} class {1}", visibility, type.AssignedName); 137 | sw.WriteLine(" {"); 138 | } 139 | } 140 | else 141 | { 142 | if (ShouldApplyNoRenamingAttribute(config)) sw.WriteLine(" " + NoRenameAttribute); 143 | if (ShouldApplyNoPruneAttribute(config)) sw.WriteLine(" " + NoPruneAttribute); 144 | sw.WriteLine(" {0} class {1}", visibility, type.AssignedName); 145 | sw.WriteLine(" {"); 146 | } 147 | 148 | var prefix = config.UseNestedClasses && !type.IsRoot ? " " : " "; 149 | 150 | 151 | var shouldSuppressWarning = config.InternalVisibility && !config.UseProperties && !config.ExplicitDeserialization; 152 | if (shouldSuppressWarning) 153 | { 154 | sw.WriteLine("#pragma warning disable 0649"); 155 | if (!config.UsePascalCase) sw.WriteLine(); 156 | } 157 | 158 | if (type.IsRoot && config.ExplicitDeserialization) WriteStringConstructorExplicitDeserialization(config, sw, type, prefix); 159 | 160 | if (config.ExplicitDeserialization) 161 | { 162 | if (config.UseProperties) WriteClassWithPropertiesExplicitDeserialization(sw, type, prefix); 163 | else WriteClassWithFieldsExplicitDeserialization(sw, type, prefix); 164 | } 165 | else 166 | { 167 | WriteClassMembers(config, sw, type, prefix); 168 | } 169 | 170 | if (shouldSuppressWarning) 171 | { 172 | sw.WriteLine(); 173 | sw.WriteLine("#pragma warning restore 0649"); 174 | sw.WriteLine(); 175 | } 176 | 177 | 178 | if (config.UseNestedClasses && !type.IsRoot) 179 | sw.WriteLine(" }"); 180 | 181 | if (!config.UseNestedClasses) 182 | sw.WriteLine(" }"); 183 | 184 | sw.WriteLine(); 185 | 186 | 187 | } 188 | 189 | 190 | 191 | private void WriteClassMembers(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type, string prefix) 192 | { 193 | foreach (var field in type.Fields) 194 | { 195 | if (config.UsePascalCase || config.ExamplesInDocumentation) sw.WriteLine(); 196 | 197 | if (config.ExamplesInDocumentation) 198 | { 199 | sw.WriteLine(prefix + "/// "); 200 | sw.WriteLine(prefix + "/// Examples: " + field.GetExamplesText()); 201 | sw.WriteLine(prefix + "/// "); 202 | } 203 | 204 | if (true || config.UsePascalCase) 205 | { 206 | sw.WriteLine(prefix + "[JsonProperty(\"{0}\")]", field.JsonMemberName); 207 | } 208 | 209 | if (config.UseProperties) 210 | { 211 | sw.WriteLine(prefix + "public {0} {1}{2} {{ get; set; }}", field.Type.GetTypeName(), (ShouldPrefix(field.MemberName) || field.MemberName == type.AssignedName) ? "_" : "", field.MemberName); 212 | } 213 | else 214 | { 215 | sw.WriteLine(prefix + "public {0} {1};", field.Type.GetTypeName(), field.MemberName); 216 | } 217 | } 218 | 219 | } 220 | 221 | 222 | private bool ShouldPrefix(string fieldName) 223 | { 224 | if (char.IsNumber(fieldName.ToCharArray()[0])) 225 | return true; 226 | 227 | if (_csharpKeywords.Contains(fieldName)) 228 | return true; 229 | 230 | return false; 231 | } 232 | 233 | 234 | 235 | 236 | #region Code for (obsolete) explicit deserialization 237 | private void WriteClassWithPropertiesExplicitDeserialization(TextWriter sw, JsonType type, string prefix) 238 | { 239 | 240 | sw.WriteLine(prefix + "private JObject __jobject;"); 241 | sw.WriteLine(prefix + "public {0}(JObject obj)", type.AssignedName); 242 | sw.WriteLine(prefix + "{"); 243 | sw.WriteLine(prefix + " this.__jobject = obj;"); 244 | sw.WriteLine(prefix + "}"); 245 | sw.WriteLine(); 246 | 247 | foreach (var field in type.Fields) 248 | { 249 | 250 | string variable = null; 251 | if (field.Type.MustCache) 252 | { 253 | variable = "_" + Char.ToLower(field.MemberName[0]) + field.MemberName.Substring(1); 254 | sw.WriteLine(prefix + "[System.Diagnostics.DebuggerBrowsable(System.Diagnostics.DebuggerBrowsableState.Never)]"); 255 | sw.WriteLine(prefix + "private {0} {1};", field.Type.GetTypeName(), variable); 256 | } 257 | 258 | 259 | sw.WriteLine(prefix + "public {0} {1}", field.Type.GetTypeName(), field.MemberName); 260 | sw.WriteLine(prefix + "{"); 261 | sw.WriteLine(prefix + " get"); 262 | sw.WriteLine(prefix + " {"); 263 | if (field.Type.MustCache) 264 | { 265 | sw.WriteLine(prefix + " if ({0} == null)", variable); 266 | sw.WriteLine(prefix + " {0} = {1};", variable, field.GetGenerationCode("__jobject")); 267 | sw.WriteLine(prefix + " return {0};", variable); 268 | } 269 | else 270 | { 271 | sw.WriteLine(prefix + " return {0};", field.GetGenerationCode("__jobject")); 272 | } 273 | sw.WriteLine(prefix + " }"); 274 | sw.WriteLine(prefix + "}"); 275 | sw.WriteLine(); 276 | 277 | } 278 | 279 | } 280 | 281 | 282 | private void WriteStringConstructorExplicitDeserialization(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type, string prefix) 283 | { 284 | sw.WriteLine(); 285 | sw.WriteLine(prefix + "public {1}(string json)", config.InternalVisibility ? "internal" : "public", type.AssignedName); 286 | sw.WriteLine(prefix + " : this(JObject.Parse(json))"); 287 | sw.WriteLine(prefix + "{"); 288 | sw.WriteLine(prefix + "}"); 289 | sw.WriteLine(); 290 | } 291 | 292 | private void WriteClassWithFieldsExplicitDeserialization(TextWriter sw, JsonType type, string prefix) 293 | { 294 | 295 | 296 | sw.WriteLine(prefix + "public {0}(JObject obj)", type.AssignedName); 297 | sw.WriteLine(prefix + "{"); 298 | 299 | foreach (var field in type.Fields) 300 | { 301 | sw.WriteLine(prefix + " this.{0} = {1};", field.MemberName, field.GetGenerationCode("obj")); 302 | 303 | } 304 | 305 | sw.WriteLine(prefix + "}"); 306 | sw.WriteLine(); 307 | 308 | foreach (var field in type.Fields) 309 | { 310 | sw.WriteLine(prefix + "public readonly {0} {1};", field.Type.GetTypeName(), field.MemberName); 311 | } 312 | } 313 | #endregion 314 | } 315 | } 316 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/CodeWriters/JavaCodeWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Xamasoft.JsonClassGenerator.CodeWriters 8 | { 9 | public class JavaCodeWriter : ICodeWriter 10 | { 11 | public string FileExtension 12 | { 13 | get { return ".java"; } 14 | } 15 | 16 | public string DisplayName 17 | { 18 | get { return "Java"; } 19 | } 20 | 21 | public string GetTypeName(JsonType type, IJsonClassGeneratorConfig config) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | 26 | public void WriteClass(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type) 27 | { 28 | throw new NotImplementedException(); 29 | } 30 | 31 | public void WriteFileStart(IJsonClassGeneratorConfig config, TextWriter sw) 32 | { 33 | foreach (var line in JsonClassGenerator.FileHeader) 34 | { 35 | sw.WriteLine("// " + line); 36 | } 37 | } 38 | 39 | public void WriteFileEnd(IJsonClassGeneratorConfig config, TextWriter sw) 40 | { 41 | throw new NotImplementedException(); 42 | } 43 | 44 | public void WriteNamespaceStart(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 45 | { 46 | throw new NotImplementedException(); 47 | } 48 | 49 | public void WriteNamespaceEnd(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 50 | { 51 | throw new NotImplementedException(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/CodeWriters/TypeScriptCodeWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Xamasoft.JsonClassGenerator.CodeWriters 8 | { 9 | public class TypeScriptCodeWriter : ICodeWriter 10 | { 11 | public string FileExtension 12 | { 13 | get { return ".ts"; } 14 | } 15 | 16 | public string DisplayName 17 | { 18 | get { return "TypeScript"; } 19 | } 20 | 21 | public string GetTypeName(JsonType type, IJsonClassGeneratorConfig config) 22 | { 23 | switch (type.Type) 24 | { 25 | case JsonTypeEnum.Anything: return "any"; 26 | case JsonTypeEnum.String: return "string"; 27 | case JsonTypeEnum.Boolean: return "bool"; 28 | case JsonTypeEnum.Integer: 29 | case JsonTypeEnum.Long: 30 | case JsonTypeEnum.Float: return "number"; 31 | case JsonTypeEnum.Date: return "Date"; 32 | case JsonTypeEnum.NullableInteger: 33 | case JsonTypeEnum.NullableLong: 34 | case JsonTypeEnum.NullableFloat: return "number"; 35 | case JsonTypeEnum.NullableBoolean: return "bool"; 36 | case JsonTypeEnum.NullableDate: return "Date"; 37 | case JsonTypeEnum.Object: return type.AssignedName; 38 | case JsonTypeEnum.Array: return GetTypeName(type.InternalType, config) + "[]"; 39 | case JsonTypeEnum.Dictionary: return "{ [key: string]: " + GetTypeName(type.InternalType, config) + "; }"; 40 | case JsonTypeEnum.NullableSomething: return "any"; 41 | case JsonTypeEnum.NonConstrained: return "any"; 42 | default: throw new NotSupportedException("Unsupported type"); 43 | } 44 | } 45 | 46 | public void WriteClass(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type) 47 | { 48 | var prefix = GetNamespace(config, type.IsRoot) != null ? " " : ""; 49 | var exported = !config.InternalVisibility || config.SecondaryNamespace != null; 50 | sw.WriteLine(prefix + (exported ? "export " : string.Empty) + "interface " + type.AssignedName + " {"); 51 | foreach (var field in type.Fields) 52 | { 53 | var shouldDefineNamespace = type.IsRoot && config.SecondaryNamespace != null && config.Namespace != null && (field.Type.Type == JsonTypeEnum.Object || (field.Type.InternalType != null && field.Type.InternalType.Type == JsonTypeEnum.Object)); 54 | if (config.ExamplesInDocumentation) 55 | { 56 | sw.WriteLine(); 57 | sw.WriteLine(prefix + " /**"); 58 | sw.WriteLine(prefix + " * Examples: " + field.GetExamplesText()); 59 | sw.WriteLine(prefix + " */"); 60 | } 61 | 62 | 63 | sw.WriteLine(prefix + " " + field.JsonMemberName + (IsNullable(field.Type.Type) ? "?" : "") + ": " + (shouldDefineNamespace ? config.SecondaryNamespace + "." : string.Empty) + GetTypeName(field.Type, config) + ";"); 64 | } 65 | sw.WriteLine(prefix + "}"); 66 | sw.WriteLine(); 67 | } 68 | 69 | private bool IsNullable(JsonTypeEnum type) 70 | { 71 | return 72 | type == JsonTypeEnum.NullableBoolean || 73 | type == JsonTypeEnum.NullableDate || 74 | type == JsonTypeEnum.NullableFloat || 75 | type == JsonTypeEnum.NullableInteger || 76 | type == JsonTypeEnum.NullableLong || 77 | type == JsonTypeEnum.NullableSomething; 78 | } 79 | 80 | public void WriteFileStart(IJsonClassGeneratorConfig config, TextWriter sw) 81 | { 82 | foreach (var line in JsonClassGenerator.FileHeader) 83 | { 84 | sw.WriteLine("// " + line); 85 | } 86 | sw.WriteLine(); 87 | } 88 | 89 | public void WriteFileEnd(IJsonClassGeneratorConfig config, TextWriter sw) 90 | { 91 | } 92 | 93 | private string GetNamespace(IJsonClassGeneratorConfig config, bool root) 94 | { 95 | return root ? config.Namespace : (config.SecondaryNamespace ?? config.Namespace); 96 | } 97 | 98 | public void WriteNamespaceStart(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 99 | { 100 | if (GetNamespace(config, root) != null) 101 | { 102 | 103 | sw.WriteLine("module " + GetNamespace(config, root) + " {"); 104 | sw.WriteLine(); 105 | } 106 | } 107 | 108 | public void WriteNamespaceEnd(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 109 | { 110 | if (GetNamespace(config, root) != null) 111 | { 112 | sw.WriteLine("}"); 113 | sw.WriteLine(); 114 | } 115 | } 116 | 117 | } 118 | } 119 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/CodeWriters/VisualBasicCodeWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Xamasoft.JsonClassGenerator.CodeWriters 8 | { 9 | public class VisualBasicCodeWriter : ICodeWriter 10 | { 11 | public string FileExtension 12 | { 13 | get { return ".vb"; } 14 | } 15 | 16 | public string DisplayName 17 | { 18 | get { return "Visual Basic .NET"; } 19 | } 20 | 21 | private const string NoRenameAttribute = ""; 22 | private const string NoPruneAttribute = ""; 23 | 24 | public string GetTypeName(JsonType type, IJsonClassGeneratorConfig config) 25 | { 26 | var arraysAsLists = config.ExplicitDeserialization; 27 | 28 | switch (type.Type) 29 | { 30 | case JsonTypeEnum.Anything: return "Object"; 31 | case JsonTypeEnum.Array: return arraysAsLists ? "IList(Of " + GetTypeName(type.InternalType, config) + ")" : GetTypeName(type.InternalType, config) + "()"; 32 | case JsonTypeEnum.Dictionary: return "Dictionary(Of String, " + GetTypeName(type.InternalType, config) + ")"; 33 | case JsonTypeEnum.Boolean: return "Boolean"; 34 | case JsonTypeEnum.Float: return "Double"; 35 | case JsonTypeEnum.Integer: return "Integer"; 36 | case JsonTypeEnum.Long: return "Long"; 37 | case JsonTypeEnum.Date: return "DateTime"; 38 | case JsonTypeEnum.NonConstrained: return "Object"; 39 | case JsonTypeEnum.NullableBoolean: return "Boolean?"; 40 | case JsonTypeEnum.NullableFloat: return "Double?"; 41 | case JsonTypeEnum.NullableInteger: return "Integer?"; 42 | case JsonTypeEnum.NullableLong: return "Long?"; 43 | case JsonTypeEnum.NullableDate: return "DateTime?"; 44 | case JsonTypeEnum.NullableSomething: return "Object"; 45 | case JsonTypeEnum.Object: return type.AssignedName; 46 | case JsonTypeEnum.String: return "String"; 47 | default: throw new System.NotSupportedException("Unsupported json type"); 48 | } 49 | } 50 | 51 | private bool ShouldApplyNoRenamingAttribute(IJsonClassGeneratorConfig config) 52 | { 53 | return config.ApplyObfuscationAttributes && !config.ExplicitDeserialization && !config.UsePascalCase; 54 | } 55 | private bool ShouldApplyNoPruneAttribute(IJsonClassGeneratorConfig config) 56 | { 57 | return config.ApplyObfuscationAttributes && !config.ExplicitDeserialization && config.UseProperties; 58 | } 59 | 60 | public void WriteClass(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type) 61 | { 62 | var visibility = config.InternalVisibility ? "Friend" : "Public"; 63 | 64 | if (config.UseNestedClasses) 65 | { 66 | sw.WriteLine(" {0} Partial Class {1}", visibility, config.MainClass); 67 | if (!type.IsRoot) 68 | { 69 | if (ShouldApplyNoRenamingAttribute(config)) sw.WriteLine(" " + NoRenameAttribute); 70 | if (ShouldApplyNoPruneAttribute(config)) sw.WriteLine(" " + NoPruneAttribute); 71 | sw.WriteLine(" {0} Class {1}", visibility, type.AssignedName); 72 | } 73 | } 74 | else 75 | { 76 | if (ShouldApplyNoRenamingAttribute(config)) sw.WriteLine(" " + NoRenameAttribute); 77 | if (ShouldApplyNoPruneAttribute(config)) sw.WriteLine(" " + NoPruneAttribute); 78 | sw.WriteLine(" {0} Class {1}", visibility, type.AssignedName); 79 | } 80 | 81 | var prefix = config.UseNestedClasses && !type.IsRoot ? " " : " "; 82 | 83 | WriteClassMembers(config, sw, type, prefix); 84 | 85 | if (config.UseNestedClasses && !type.IsRoot) 86 | sw.WriteLine(" End Class"); 87 | 88 | sw.WriteLine(" End Class"); 89 | sw.WriteLine(); 90 | 91 | } 92 | 93 | 94 | private void WriteClassMembers(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type, string prefix) 95 | { 96 | foreach (var field in type.Fields) 97 | { 98 | if (config.UsePascalCase || config.ExamplesInDocumentation) sw.WriteLine(); 99 | 100 | if (config.ExamplesInDocumentation) 101 | { 102 | sw.WriteLine(prefix + "''' "); 103 | sw.WriteLine(prefix + "''' Examples: " + field.GetExamplesText()); 104 | sw.WriteLine(prefix + "''' "); 105 | } 106 | 107 | 108 | if (config.UsePascalCase) 109 | { 110 | sw.WriteLine(prefix + "", field.JsonMemberName); 111 | } 112 | 113 | if (config.UseProperties) 114 | { 115 | sw.WriteLine(prefix + "Public Property {1} As {0}", field.Type.GetTypeName(), field.MemberName); 116 | } 117 | else 118 | { 119 | sw.WriteLine(prefix + "Public {1} As {0}", field.Type.GetTypeName(), field.MemberName); 120 | } 121 | } 122 | 123 | } 124 | 125 | 126 | 127 | 128 | 129 | public void WriteFileStart(IJsonClassGeneratorConfig config, TextWriter sw) 130 | { 131 | foreach (var line in JsonClassGenerator.FileHeader) 132 | { 133 | sw.WriteLine("' " + line); 134 | } 135 | sw.WriteLine(); 136 | sw.WriteLine("Imports System"); 137 | sw.WriteLine("Imports System.Collections.Generic"); 138 | if (ShouldApplyNoRenamingAttribute(config) || ShouldApplyNoPruneAttribute(config)) 139 | sw.WriteLine("Imports System.Reflection"); 140 | if (config.UsePascalCase) 141 | sw.WriteLine("Imports Newtonsoft.Json"); 142 | sw.WriteLine("Imports Newtonsoft.Json.Linq"); 143 | if (config.SecondaryNamespace != null && config.HasSecondaryClasses && !config.UseNestedClasses) 144 | { 145 | sw.WriteLine("Imports {0}", config.SecondaryNamespace); 146 | } 147 | } 148 | 149 | public void WriteFileEnd(IJsonClassGeneratorConfig config, TextWriter sw) 150 | { 151 | } 152 | 153 | 154 | public void WriteNamespaceStart(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 155 | { 156 | sw.WriteLine(); 157 | sw.WriteLine("Namespace Global.{0}", root && !config.UseNestedClasses ? config.Namespace : (config.SecondaryNamespace ?? config.Namespace)); 158 | sw.WriteLine(); 159 | } 160 | 161 | public void WriteNamespaceEnd(IJsonClassGeneratorConfig config, TextWriter sw, bool root) 162 | { 163 | 164 | sw.WriteLine("End Namespace"); 165 | 166 | } 167 | } 168 | } -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/FieldInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright © 2010 Xamasoft 2 | 3 | using Newtonsoft.Json; 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace Xamasoft.JsonClassGenerator 10 | { 11 | public class FieldInfo 12 | { 13 | 14 | public FieldInfo(IJsonClassGeneratorConfig generator, string jsonMemberName, JsonType type, bool usePascalCase, IList Examples) 15 | { 16 | this.generator = generator; 17 | this.JsonMemberName = jsonMemberName; 18 | this.MemberName = jsonMemberName; 19 | if (usePascalCase) MemberName = JsonClassGenerator.ToTitleCase(MemberName); 20 | this.Type = type; 21 | this.Examples = Examples; 22 | } 23 | private IJsonClassGeneratorConfig generator; 24 | public string MemberName { get; private set; } 25 | public string JsonMemberName { get; private set; } 26 | public JsonType Type { get; private set; } 27 | public IList Examples { get; private set; } 28 | 29 | public string GetGenerationCode(string jobject) 30 | { 31 | var field = this; 32 | if (field.Type.Type == JsonTypeEnum.Array) 33 | { 34 | var innermost = field.Type.GetInnermostType(); 35 | return string.Format("({1})JsonClassHelper.ReadArray<{5}>(JsonClassHelper.GetJToken({0}, \"{2}\"), JsonClassHelper.{3}, typeof({6}))", 36 | jobject, 37 | field.Type.GetTypeName(), 38 | field.JsonMemberName, 39 | innermost.GetReaderName(), 40 | -1, 41 | innermost.GetTypeName(), 42 | field.Type.GetTypeName() 43 | ); 44 | } 45 | else if (field.Type.Type == JsonTypeEnum.Dictionary) 46 | { 47 | 48 | return string.Format("({1})JsonClassHelper.ReadDictionary<{2}>(JsonClassHelper.GetJToken({0}, \"{3}\"))", 49 | jobject, 50 | field.Type.GetTypeName(), 51 | field.Type.InternalType.GetTypeName(), 52 | field.JsonMemberName, 53 | field.Type.GetTypeName() 54 | ); 55 | } 56 | else 57 | { 58 | return string.Format("JsonClassHelper.{1}(JsonClassHelper.GetJToken<{2}>({0}, \"{3}\"))", 59 | jobject, 60 | field.Type.GetReaderName(), 61 | field.Type.GetJTokenType(), 62 | field.JsonMemberName); 63 | } 64 | 65 | } 66 | 67 | 68 | 69 | public string GetExamplesText() 70 | { 71 | return string.Join(", ", Examples.Take(5).Select(x => JsonConvert.SerializeObject(x)).ToArray()); 72 | } 73 | 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/ICodeWriter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Text; 6 | 7 | namespace Xamasoft.JsonClassGenerator 8 | { 9 | public interface ICodeWriter 10 | { 11 | string FileExtension { get; } 12 | string DisplayName { get; } 13 | string GetTypeName(JsonType type, IJsonClassGeneratorConfig config); 14 | void WriteClass(IJsonClassGeneratorConfig config, TextWriter sw, JsonType type); 15 | void WriteFileStart(IJsonClassGeneratorConfig config, TextWriter sw); 16 | void WriteFileEnd(IJsonClassGeneratorConfig config, TextWriter sw); 17 | void WriteNamespaceStart(IJsonClassGeneratorConfig config, TextWriter sw, bool root); 18 | void WriteNamespaceEnd(IJsonClassGeneratorConfig config, TextWriter sw, bool root); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/IJsonClassGeneratorConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace Xamasoft.JsonClassGenerator 7 | { 8 | public interface IJsonClassGeneratorConfig 9 | { 10 | string Namespace { get; set; } 11 | string SecondaryNamespace { get; set; } 12 | bool UseProperties { get; set; } 13 | bool InternalVisibility { get; set; } 14 | bool ExplicitDeserialization { get; set; } 15 | bool NoHelperClass { get; set; } 16 | string MainClass { get; set; } 17 | bool UsePascalCase { get; set; } 18 | bool UseNestedClasses { get; set; } 19 | bool ApplyObfuscationAttributes { get; set; } 20 | bool SingleFile { get; set; } 21 | ICodeWriter CodeWriter { get; set; } 22 | bool HasSecondaryClasses { get; } 23 | bool AlwaysUseNullableValues { get; set; } 24 | bool UseNamespaces { get; } 25 | bool ExamplesInDocumentation { get; set; } 26 | bool GeneratePartialClasses { get; set; } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/JsonClassGenerator.cs: -------------------------------------------------------------------------------- 1 | // Copyright © 2010 Xamasoft 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Newtonsoft.Json; 8 | using Newtonsoft.Json.Linq; 9 | using System.IO; 10 | using System.Globalization; 11 | using Xamasoft.JsonClassGenerator.CodeWriters; 12 | 13 | 14 | namespace Xamasoft.JsonClassGenerator 15 | { 16 | public class JsonClassGenerator : IJsonClassGeneratorConfig 17 | { 18 | 19 | 20 | public string Example { get; set; } 21 | public string TargetFolder { get; set; } 22 | public string Namespace { get; set; } 23 | public string SecondaryNamespace { get; set; } 24 | public bool UseProperties { get; set; } 25 | public bool InternalVisibility { get; set; } 26 | public bool ExplicitDeserialization { get; set; } 27 | public bool NoHelperClass { get; set; } 28 | public string MainClass { get; set; } 29 | public bool UsePascalCase { get; set; } 30 | public bool UseNestedClasses { get; set; } 31 | public bool ApplyObfuscationAttributes { get; set; } 32 | public bool SingleFile { get; set; } 33 | public ICodeWriter CodeWriter { get; set; } 34 | public TextWriter OutputStream { get; set; } 35 | public bool AlwaysUseNullableValues { get; set; } 36 | public bool ExamplesInDocumentation { get; set; } 37 | 38 | private bool used = false; 39 | public bool UseNamespaces { get { return Namespace != null; } } 40 | 41 | public bool GeneratePartialClasses { get; set; } 42 | 43 | public void GenerateClasses() 44 | { 45 | if (CodeWriter == null) CodeWriter = new CSharpCodeWriter(); 46 | if (ExplicitDeserialization && !(CodeWriter is CSharpCodeWriter)) throw new ArgumentException("Explicit deserialization is obsolete and is only supported by the C# provider."); 47 | 48 | if (used) throw new InvalidOperationException("This instance of JsonClassGenerator has already been used. Please create a new instance."); 49 | used = true; 50 | 51 | 52 | var writeToDisk = TargetFolder != null; 53 | if (writeToDisk && !Directory.Exists(TargetFolder)) Directory.CreateDirectory(TargetFolder); 54 | 55 | 56 | JObject[] examples; 57 | var example = Example.StartsWith("HTTP/") ? Example.Substring(Example.IndexOf("\r\n\r\n")) : Example; 58 | using (var sr = new StringReader(example)) 59 | using (var reader = new JsonTextReader(sr)) 60 | { 61 | var json = JToken.ReadFrom(reader); 62 | if (json is JArray) 63 | { 64 | examples = ((JArray)json).Cast().ToArray(); 65 | } 66 | else if (json is JObject) 67 | { 68 | examples = new[] { (JObject)json }; 69 | } 70 | else 71 | { 72 | throw new Exception("Sample JSON must be either a JSON array, or a JSON object."); 73 | } 74 | } 75 | 76 | 77 | Types = new List(); 78 | Names.Add(MainClass); 79 | var rootType = new JsonType(this, examples[0]); 80 | rootType.IsRoot = true; 81 | rootType.AssignName(MainClass); 82 | GenerateClass(examples, rootType); 83 | 84 | if (writeToDisk) 85 | { 86 | 87 | var parentFolder = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location); 88 | if (writeToDisk && !NoHelperClass && ExplicitDeserialization) File.WriteAllBytes(Path.Combine(TargetFolder, "JsonClassHelper.cs"), Properties.Resources.JsonClassHelper); 89 | if (SingleFile) 90 | { 91 | WriteClassesToFile(Path.Combine(TargetFolder, MainClass + CodeWriter.FileExtension), Types); 92 | } 93 | else 94 | { 95 | 96 | foreach (var type in Types) 97 | { 98 | var folder = TargetFolder; 99 | if (!UseNestedClasses && !type.IsRoot && SecondaryNamespace != null) 100 | { 101 | var s = SecondaryNamespace; 102 | if (s.StartsWith(Namespace + ".")) s = s.Substring(Namespace.Length + 1); 103 | folder = Path.Combine(folder, s); 104 | Directory.CreateDirectory(folder); 105 | } 106 | WriteClassesToFile(Path.Combine(folder, (UseNestedClasses && !type.IsRoot ? MainClass + "." : string.Empty) + type.AssignedName + CodeWriter.FileExtension), new[] { type }); 107 | } 108 | } 109 | } 110 | else if (OutputStream != null) 111 | { 112 | WriteClassesToFile(OutputStream, Types); 113 | } 114 | 115 | } 116 | 117 | private void WriteClassesToFile(string path, IEnumerable types) 118 | { 119 | using (var sw = new StreamWriter(path, false, Encoding.UTF8)) 120 | { 121 | WriteClassesToFile(sw, types); 122 | } 123 | } 124 | 125 | private void WriteClassesToFile(TextWriter sw, IEnumerable types) 126 | { 127 | var inNamespace = false; 128 | var rootNamespace = false; 129 | 130 | CodeWriter.WriteFileStart(this, sw); 131 | foreach (var type in types) 132 | { 133 | if (UseNamespaces && inNamespace && rootNamespace != type.IsRoot && SecondaryNamespace != null) { CodeWriter.WriteNamespaceEnd(this, sw, rootNamespace); inNamespace = false; } 134 | if (UseNamespaces && !inNamespace) { CodeWriter.WriteNamespaceStart(this, sw, type.IsRoot); inNamespace = true; rootNamespace = type.IsRoot; } 135 | CodeWriter.WriteClass(this, sw, type); 136 | } 137 | if (UseNamespaces && inNamespace) CodeWriter.WriteNamespaceEnd(this, sw, rootNamespace); 138 | CodeWriter.WriteFileEnd(this, sw); 139 | } 140 | 141 | 142 | private void GenerateClass(JObject[] examples, JsonType type) 143 | { 144 | var jsonFields = new Dictionary(); 145 | var fieldExamples = new Dictionary>(); 146 | 147 | var first = true; 148 | 149 | foreach (var obj in examples) 150 | { 151 | foreach (var prop in obj.Properties()) 152 | { 153 | JsonType fieldType; 154 | var currentType = new JsonType(this, prop.Value); 155 | var propName = prop.Name; 156 | if (jsonFields.TryGetValue(propName, out fieldType)) 157 | { 158 | 159 | var commonType = fieldType.GetCommonType(currentType); 160 | 161 | jsonFields[propName] = commonType; 162 | } 163 | else 164 | { 165 | var commonType = currentType; 166 | if (first) commonType = commonType.MaybeMakeNullable(this); 167 | else commonType = commonType.GetCommonType(JsonType.GetNull(this)); 168 | jsonFields.Add(propName, commonType); 169 | fieldExamples[propName] = new List(); 170 | } 171 | var fe = fieldExamples[propName]; 172 | var val = prop.Value; 173 | if (val.Type == JTokenType.Null || val.Type == JTokenType.Undefined) 174 | { 175 | if (!fe.Contains(null)) 176 | { 177 | fe.Insert(0, null); 178 | } 179 | } 180 | else 181 | { 182 | var v = val.Type == JTokenType.Array || val.Type == JTokenType.Object ? val : val.Value(); 183 | if (!fe.Any(x => v.Equals(x))) 184 | fe.Add(v); 185 | } 186 | } 187 | first = false; 188 | } 189 | 190 | if (UseNestedClasses) 191 | { 192 | foreach (var field in jsonFields) 193 | { 194 | Names.Add(field.Key.ToLower()); 195 | } 196 | } 197 | 198 | foreach (var field in jsonFields) 199 | { 200 | var fieldType = field.Value; 201 | if (fieldType.Type == JsonTypeEnum.Object) 202 | { 203 | var subexamples = new List(examples.Length); 204 | foreach (var obj in examples) 205 | { 206 | JToken value; 207 | if (obj.TryGetValue(field.Key, out value)) 208 | { 209 | if (value.Type == JTokenType.Object) 210 | { 211 | subexamples.Add((JObject)value); 212 | } 213 | } 214 | } 215 | 216 | fieldType.AssignName(CreateUniqueClassName(field.Key)); 217 | GenerateClass(subexamples.ToArray(), fieldType); 218 | } 219 | 220 | if (fieldType.InternalType != null && fieldType.InternalType.Type == JsonTypeEnum.Object) 221 | { 222 | var subexamples = new List(examples.Length); 223 | foreach (var obj in examples) 224 | { 225 | JToken value; 226 | if (obj.TryGetValue(field.Key, out value)) 227 | { 228 | if (value.Type == JTokenType.Array) 229 | { 230 | foreach (var item in (JArray)value) 231 | { 232 | if (!(item is JObject)) throw new NotSupportedException("Arrays of non-objects are not supported yet."); 233 | subexamples.Add((JObject)item); 234 | } 235 | 236 | } 237 | else if (value.Type == JTokenType.Object) 238 | { 239 | foreach (var item in (JObject)value) 240 | { 241 | if (!(item.Value is JObject)) throw new NotSupportedException("Arrays of non-objects are not supported yet."); 242 | 243 | subexamples.Add((JObject)item.Value); 244 | } 245 | } 246 | } 247 | } 248 | 249 | field.Value.InternalType.AssignName(CreateUniqueClassNameFromPlural(field.Key)); 250 | GenerateClass(subexamples.ToArray(), field.Value.InternalType); 251 | } 252 | } 253 | 254 | 255 | type.Fields = jsonFields.Select(x => new FieldInfo(this, x.Key, x.Value, UsePascalCase, fieldExamples[x.Key])).ToArray(); 256 | 257 | Types.Add(type); 258 | 259 | } 260 | 261 | public IList Types { get; private set; } 262 | private HashSet Names = new HashSet(); 263 | 264 | private string CreateUniqueClassName(string name) 265 | { 266 | name = ToTitleCase(name); 267 | 268 | var finalName = name; 269 | var i = 2; 270 | while (Names.Any(x => x.Equals(finalName, StringComparison.OrdinalIgnoreCase))) 271 | { 272 | finalName = name + i.ToString(); 273 | i++; 274 | } 275 | 276 | Names.Add(finalName); 277 | return finalName; 278 | } 279 | 280 | private string CreateUniqueClassNameFromPlural(string plural) 281 | { 282 | plural = ToTitleCase(plural); 283 | return CreateUniqueClassName(plural); 284 | } 285 | 286 | 287 | 288 | internal static string ToTitleCase(string str) 289 | { 290 | var sb = new StringBuilder(str.Length); 291 | var flag = true; 292 | 293 | for (int i = 0; i < str.Length; i++) 294 | { 295 | var c = str[i]; 296 | if (char.IsLetterOrDigit(c) || c == '_') 297 | { 298 | sb.Append(flag ? char.ToUpper(c) : c); 299 | flag = false; 300 | } 301 | else 302 | { 303 | flag = true; 304 | } 305 | } 306 | 307 | return sb.ToString(); 308 | } 309 | 310 | public bool HasSecondaryClasses 311 | { 312 | get { return Types.Count > 1; } 313 | } 314 | 315 | public static readonly string[] FileHeader = new[] { 316 | "Generated by Xamasoft JSON Class Generator", 317 | "http://www.xamasoft.com/json-class-generator" 318 | }; 319 | } 320 | } 321 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/JsonClassGeneratorLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F} 8 | Library 9 | Properties 10 | Xamasoft.JsonClassGenerator 11 | Xamasoft.JsonClassGenerator 12 | v4.0 13 | 512 14 | 15 | b1dffd59 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | true 38 | 39 | 40 | JsonDataContextDriver.snk 41 | 42 | 43 | 44 | False 45 | ..\JsonDataContextDriver\packages\Newtonsoft.Json.6.0.8\lib\net40\Newtonsoft.Json.dll 46 | 47 | 48 | 49 | 50 | ..\JsonDataContextDriver\packages\PropertyChanged.Fody.1.50.1\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll 51 | False 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | True 74 | True 75 | Resources.resx 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | ResXFileCodeGenerator 86 | Resources.Designer.cs 87 | Designer 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 98 | 99 | 100 | 101 | 108 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/JsonClassHelper.cs: -------------------------------------------------------------------------------- 1 | // JSON C# Class Generator 2 | // http://www.xamasoft.com/json-class-generator 3 | 4 | using System; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | using Newtonsoft.Json.Linq; 9 | 10 | namespace JsonCSharpClassGenerator 11 | { 12 | internal static class JsonClassHelper 13 | { 14 | 15 | public static T GetJToken(JObject obj, string field) where T : JToken 16 | { 17 | JToken value; 18 | if (obj.TryGetValue(field, out value)) return GetJToken(value); 19 | else return null; 20 | } 21 | 22 | private static T GetJToken(JToken token) where T : JToken 23 | { 24 | if (token == null) return null; 25 | if (token.Type == JTokenType.Null) return null; 26 | if (token.Type == JTokenType.Undefined) return null; 27 | return (T)token; 28 | } 29 | 30 | public static string ReadString(JToken token) 31 | { 32 | var value = GetJToken(token); 33 | if (value == null) return null; 34 | return (string)value.Value; 35 | } 36 | 37 | 38 | public static bool ReadBoolean(JToken token) 39 | { 40 | var value = GetJToken(token); 41 | if (value == null) throw new Newtonsoft.Json.JsonSerializationException(); 42 | return Convert.ToBoolean(value.Value); 43 | 44 | } 45 | 46 | public static bool? ReadNullableBoolean(JToken token) 47 | { 48 | var value = GetJToken(token); 49 | if (value == null) return null; 50 | return Convert.ToBoolean(value.Value); 51 | } 52 | 53 | 54 | public static int ReadInteger(JToken token) 55 | { 56 | var value = GetJToken(token); 57 | if (value == null) throw new Newtonsoft.Json.JsonSerializationException(); 58 | return Convert.ToInt32((long)value.Value); 59 | 60 | } 61 | 62 | public static int? ReadNullableInteger(JToken token) 63 | { 64 | var value = GetJToken(token); 65 | if (value == null) return null; 66 | return Convert.ToInt32((long)value.Value); 67 | 68 | } 69 | 70 | 71 | 72 | public static long ReadLong(JToken token) 73 | { 74 | var value = GetJToken(token); 75 | if (value == null) throw new Newtonsoft.Json.JsonSerializationException(); 76 | return Convert.ToInt64(value.Value); 77 | 78 | } 79 | 80 | public static long? ReadNullableLong(JToken token) 81 | { 82 | var value = GetJToken(token); 83 | if (value == null) return null; 84 | return Convert.ToInt64(value.Value); 85 | } 86 | 87 | 88 | public static double ReadFloat(JToken token) 89 | { 90 | var value = GetJToken(token); 91 | if (value == null) throw new Newtonsoft.Json.JsonSerializationException(); 92 | return Convert.ToDouble(value.Value); 93 | 94 | } 95 | 96 | public static double? ReadNullableFloat(JToken token) 97 | { 98 | var value = GetJToken(token); 99 | if (value == null) return null; 100 | return Convert.ToDouble(value.Value); 101 | 102 | } 103 | 104 | 105 | 106 | 107 | public static DateTime ReadDate(JToken token) 108 | { 109 | var value = GetJToken(token); 110 | if (value == null) throw new Newtonsoft.Json.JsonSerializationException(); 111 | return Convert.ToDateTime(value.Value); 112 | 113 | } 114 | 115 | public static DateTime? ReadNullableDate(JToken token) 116 | { 117 | var value = GetJToken(token); 118 | if (value == null) return null; 119 | return Convert.ToDateTime(value.Value); 120 | 121 | } 122 | 123 | public static object ReadObject(JToken token) 124 | { 125 | var value = GetJToken(token); 126 | if (value == null) return null; 127 | if (value.Type == JTokenType.Object) return value; 128 | if (value.Type == JTokenType.Array) return ReadArray(value, ReadObject); 129 | 130 | var jvalue = value as JValue; 131 | if (jvalue != null) return jvalue.Value; 132 | 133 | return value; 134 | } 135 | 136 | public static T ReadStronglyTypedObject(JToken token) where T : class 137 | { 138 | var value = GetJToken(token); 139 | if (value == null) return null; 140 | return (T)Activator.CreateInstance(typeof(T), new object[] { token }); 141 | 142 | } 143 | 144 | 145 | public delegate T ValueReader(JToken token); 146 | 147 | 148 | 149 | public static T[] ReadArray(JToken token, ValueReader reader) 150 | { 151 | var value = GetJToken(token); 152 | if (value == null) return null; 153 | 154 | var array = new T[value.Count]; 155 | for (int i = 0; i < array.Length; i++) 156 | { 157 | array[i] = reader(value[i]); 158 | } 159 | return array; 160 | 161 | } 162 | 163 | 164 | 165 | public static Dictionary ReadDictionary(JToken token) 166 | { 167 | var value = GetJToken(token); 168 | if (value == null) return null; 169 | 170 | var dict = new Dictionary(); 171 | 172 | return dict; 173 | } 174 | 175 | public static Array ReadArray(JArray jArray, ValueReader reader, Type type) 176 | { 177 | if (jArray == null) return null; 178 | 179 | var elemType = type.GetElementType(); 180 | 181 | var array = Array.CreateInstance(elemType, jArray.Count); 182 | for (int i = 0; i < array.Length; i++) 183 | { 184 | if (elemType.IsArray) 185 | { 186 | array.SetValue(ReadArray(GetJToken(jArray[i]), reader, elemType), i); 187 | } 188 | else 189 | { 190 | array.SetValue(reader(jArray[i]), i); 191 | } 192 | 193 | } 194 | return array; 195 | 196 | } 197 | } 198 | } 199 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/JsonType.cs: -------------------------------------------------------------------------------- 1 | // Copyright © 2010 Xamasoft 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using Newtonsoft.Json.Linq; 8 | using System.Globalization; 9 | 10 | namespace Xamasoft.JsonClassGenerator 11 | { 12 | public class JsonType 13 | { 14 | 15 | 16 | private JsonType(IJsonClassGeneratorConfig generator) 17 | { 18 | this.generator = generator; 19 | } 20 | 21 | public JsonType(IJsonClassGeneratorConfig generator, JToken token) 22 | : this(generator) 23 | { 24 | 25 | Type = GetFirstTypeEnum(token); 26 | 27 | if (Type == JsonTypeEnum.Array) 28 | { 29 | var array = (JArray)token; 30 | InternalType = GetCommonType(generator, array.ToArray()); 31 | } 32 | } 33 | 34 | internal static JsonType GetNull(IJsonClassGeneratorConfig generator) 35 | { 36 | return new JsonType(generator, JsonTypeEnum.NullableSomething); 37 | } 38 | 39 | private IJsonClassGeneratorConfig generator; 40 | 41 | internal JsonType(IJsonClassGeneratorConfig generator, JsonTypeEnum type) 42 | : this(generator) 43 | { 44 | this.Type = type; 45 | } 46 | 47 | 48 | public static JsonType GetCommonType(IJsonClassGeneratorConfig generator, JToken[] tokens) 49 | { 50 | 51 | if (tokens.Length == 0) return new JsonType(generator, JsonTypeEnum.NonConstrained); 52 | 53 | var common = new JsonType(generator, tokens[0]).MaybeMakeNullable(generator); 54 | 55 | for (int i = 1; i < tokens.Length; i++) 56 | { 57 | var current = new JsonType(generator, tokens[i]); 58 | common = common.GetCommonType(current); 59 | } 60 | 61 | return common; 62 | 63 | } 64 | 65 | internal JsonType MaybeMakeNullable(IJsonClassGeneratorConfig generator) 66 | { 67 | if (!generator.AlwaysUseNullableValues) return this; 68 | return this.GetCommonType(JsonType.GetNull(generator)); 69 | } 70 | 71 | 72 | public JsonTypeEnum Type { get; private set; } 73 | public JsonType InternalType { get; private set; } 74 | public string AssignedName { get; private set; } 75 | 76 | 77 | public void AssignName(string name) 78 | { 79 | if (char.IsNumber(name.ToCharArray()[0])) 80 | name = "_" + name; 81 | 82 | AssignedName = name; 83 | } 84 | 85 | 86 | 87 | public bool MustCache 88 | { 89 | get 90 | { 91 | switch (Type) 92 | { 93 | case JsonTypeEnum.Array: return true; 94 | case JsonTypeEnum.Object: return true; 95 | case JsonTypeEnum.Anything: return true; 96 | case JsonTypeEnum.Dictionary: return true; 97 | case JsonTypeEnum.NonConstrained: return true; 98 | default: return false; 99 | } 100 | } 101 | } 102 | 103 | public string GetReaderName() 104 | { 105 | if (Type == JsonTypeEnum.Anything || Type == JsonTypeEnum.NullableSomething || Type == JsonTypeEnum.NonConstrained) 106 | { 107 | return "ReadObject"; 108 | } 109 | if (Type == JsonTypeEnum.Object) 110 | { 111 | return string.Format("ReadStronglyTypedObject<{0}>", AssignedName); 112 | } 113 | else if (Type == JsonTypeEnum.Array) 114 | { 115 | return string.Format("ReadArray<{0}>", InternalType.GetTypeName()); 116 | } 117 | else 118 | { 119 | return string.Format("Read{0}", Enum.GetName(typeof(JsonTypeEnum), Type)); 120 | } 121 | } 122 | 123 | public JsonType GetInnermostType() 124 | { 125 | if (Type != JsonTypeEnum.Array) throw new InvalidOperationException(); 126 | if (InternalType.Type != JsonTypeEnum.Array) return InternalType; 127 | return InternalType.GetInnermostType(); 128 | } 129 | 130 | 131 | public string GetTypeName() 132 | { 133 | return generator.CodeWriter.GetTypeName(this, generator); 134 | } 135 | 136 | public string GetJTokenType() 137 | { 138 | switch (Type) 139 | { 140 | case JsonTypeEnum.Boolean: 141 | case JsonTypeEnum.Integer: 142 | case JsonTypeEnum.Long: 143 | case JsonTypeEnum.Float: 144 | case JsonTypeEnum.Date: 145 | case JsonTypeEnum.NullableBoolean: 146 | case JsonTypeEnum.NullableInteger: 147 | case JsonTypeEnum.NullableLong: 148 | case JsonTypeEnum.NullableFloat: 149 | case JsonTypeEnum.NullableDate: 150 | case JsonTypeEnum.String: 151 | return "JValue"; 152 | case JsonTypeEnum.Array: 153 | return "JArray"; 154 | case JsonTypeEnum.Dictionary: 155 | return "JObject"; 156 | case JsonTypeEnum.Object: 157 | return "JObject"; 158 | default: 159 | return "JToken"; 160 | 161 | } 162 | } 163 | 164 | public JsonType GetCommonType(JsonType type2) 165 | { 166 | var commonType = GetCommonTypeEnum(this.Type, type2.Type); 167 | 168 | if (commonType == JsonTypeEnum.Array) 169 | { 170 | if (type2.Type == JsonTypeEnum.NullableSomething) return this; 171 | if (this.Type == JsonTypeEnum.NullableSomething) return type2; 172 | var commonInternalType = InternalType.GetCommonType(type2.InternalType).MaybeMakeNullable(generator); 173 | if (commonInternalType != InternalType) return new JsonType(generator, JsonTypeEnum.Array) { InternalType = commonInternalType }; 174 | } 175 | 176 | 177 | //if (commonType == JsonTypeEnum.Dictionary) 178 | //{ 179 | // var commonInternalType = InternalType.GetCommonType(type2.InternalType); 180 | // if (commonInternalType != InternalType) return new JsonType(JsonTypeEnum.Dictionary) { InternalType = commonInternalType }; 181 | //} 182 | 183 | 184 | if (this.Type == commonType) return this; 185 | return new JsonType(generator, commonType).MaybeMakeNullable(generator); 186 | } 187 | 188 | 189 | private static bool IsNull(JsonTypeEnum type) 190 | { 191 | return type == JsonTypeEnum.NullableSomething; 192 | } 193 | 194 | 195 | 196 | private JsonTypeEnum GetCommonTypeEnum(JsonTypeEnum type1, JsonTypeEnum type2) 197 | { 198 | if (type1 == JsonTypeEnum.NonConstrained) return type2; 199 | if (type2 == JsonTypeEnum.NonConstrained) return type1; 200 | 201 | switch (type1) 202 | { 203 | case JsonTypeEnum.Boolean: 204 | if (IsNull(type2)) return JsonTypeEnum.NullableBoolean; 205 | if (type2 == JsonTypeEnum.Boolean) return type1; 206 | break; 207 | case JsonTypeEnum.NullableBoolean: 208 | if (IsNull(type2)) return type1; 209 | if (type2 == JsonTypeEnum.Boolean) return type1; 210 | break; 211 | case JsonTypeEnum.Integer: 212 | if (IsNull(type2)) return JsonTypeEnum.NullableInteger; 213 | if (type2 == JsonTypeEnum.Float) return JsonTypeEnum.Float; 214 | if (type2 == JsonTypeEnum.Long) return JsonTypeEnum.Long; 215 | if (type2 == JsonTypeEnum.Integer) return type1; 216 | break; 217 | case JsonTypeEnum.NullableInteger: 218 | if (IsNull(type2)) return type1; 219 | if (type2 == JsonTypeEnum.Float) return JsonTypeEnum.NullableFloat; 220 | if (type2 == JsonTypeEnum.Long) return JsonTypeEnum.NullableLong; 221 | if (type2 == JsonTypeEnum.Integer) return type1; 222 | break; 223 | case JsonTypeEnum.Float: 224 | if (IsNull(type2)) return JsonTypeEnum.NullableFloat; 225 | if (type2 == JsonTypeEnum.Float) return type1; 226 | if (type2 == JsonTypeEnum.Integer) return type1; 227 | if (type2 == JsonTypeEnum.Long) return type1; 228 | break; 229 | case JsonTypeEnum.NullableFloat: 230 | if (IsNull(type2)) return type1; 231 | if (type2 == JsonTypeEnum.Float) return type1; 232 | if (type2 == JsonTypeEnum.Integer) return type1; 233 | if (type2 == JsonTypeEnum.Long) return type1; 234 | break; 235 | case JsonTypeEnum.Long: 236 | if (IsNull(type2)) return JsonTypeEnum.NullableLong; 237 | if (type2 == JsonTypeEnum.Float) return JsonTypeEnum.Float; 238 | if (type2 == JsonTypeEnum.Integer) return type1; 239 | break; 240 | case JsonTypeEnum.NullableLong: 241 | if (IsNull(type2)) return type1; 242 | if (type2 == JsonTypeEnum.Float) return JsonTypeEnum.NullableFloat; 243 | if (type2 == JsonTypeEnum.Integer) return type1; 244 | if (type2 == JsonTypeEnum.Long) return type1; 245 | break; 246 | case JsonTypeEnum.Date: 247 | if (IsNull(type2)) return JsonTypeEnum.NullableDate; 248 | if (type2 == JsonTypeEnum.Date) return JsonTypeEnum.Date; 249 | break; 250 | case JsonTypeEnum.NullableDate: 251 | if (IsNull(type2)) return type1; 252 | if (type2 == JsonTypeEnum.Date) return type1; 253 | break; 254 | case JsonTypeEnum.NullableSomething: 255 | if (IsNull(type2)) return type1; 256 | if (type2 == JsonTypeEnum.String) return JsonTypeEnum.String; 257 | if (type2 == JsonTypeEnum.Integer) return JsonTypeEnum.NullableInteger; 258 | if (type2 == JsonTypeEnum.Float) return JsonTypeEnum.NullableFloat; 259 | if (type2 == JsonTypeEnum.Long) return JsonTypeEnum.NullableLong; 260 | if (type2 == JsonTypeEnum.Boolean) return JsonTypeEnum.NullableBoolean; 261 | if (type2 == JsonTypeEnum.Date) return JsonTypeEnum.NullableDate; 262 | if (type2 == JsonTypeEnum.Array) return JsonTypeEnum.Array; 263 | if (type2 == JsonTypeEnum.Object) return JsonTypeEnum.Object; 264 | break; 265 | case JsonTypeEnum.Object: 266 | if (IsNull(type2)) return type1; 267 | if (type2 == JsonTypeEnum.Object) return type1; 268 | if (type2 == JsonTypeEnum.Dictionary) throw new ArgumentException(); 269 | break; 270 | case JsonTypeEnum.Dictionary: 271 | throw new ArgumentException(); 272 | //if (IsNull(type2)) return type1; 273 | //if (type2 == JsonTypeEnum.Object) return type1; 274 | //if (type2 == JsonTypeEnum.Dictionary) return type1; 275 | // break; 276 | case JsonTypeEnum.Array: 277 | if (IsNull(type2)) return type1; 278 | if (type2 == JsonTypeEnum.Array) return type1; 279 | break; 280 | case JsonTypeEnum.String: 281 | if (IsNull(type2)) return type1; 282 | if (type2 == JsonTypeEnum.String) return type1; 283 | break; 284 | } 285 | 286 | return JsonTypeEnum.Anything; 287 | 288 | } 289 | 290 | private static bool IsNull(JTokenType type) 291 | { 292 | return type == JTokenType.Null || type == JTokenType.Undefined; 293 | } 294 | 295 | 296 | 297 | private static JsonTypeEnum GetFirstTypeEnum(JToken token) 298 | { 299 | var type = token.Type; 300 | if (type == JTokenType.Integer) 301 | { 302 | if ((long)((JValue)token).Value < int.MaxValue) return JsonTypeEnum.Integer; 303 | else return JsonTypeEnum.Long; 304 | 305 | } 306 | switch (type) 307 | { 308 | case JTokenType.Array: return JsonTypeEnum.Array; 309 | case JTokenType.Boolean: return JsonTypeEnum.Boolean; 310 | case JTokenType.Float: return JsonTypeEnum.Float; 311 | case JTokenType.Null: return JsonTypeEnum.NullableSomething; 312 | case JTokenType.Undefined: return JsonTypeEnum.NullableSomething; 313 | case JTokenType.String: return JsonTypeEnum.String; 314 | case JTokenType.Object: return JsonTypeEnum.Object; 315 | case JTokenType.Date: return JsonTypeEnum.Date; 316 | 317 | default: return JsonTypeEnum.Anything; 318 | 319 | } 320 | } 321 | 322 | 323 | public IList Fields { get; internal set; } 324 | public bool IsRoot { get; internal set; } 325 | } 326 | } 327 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/JsonTypeEnum.cs: -------------------------------------------------------------------------------- 1 | // Copyright © 2010 Xamasoft 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | 8 | namespace Xamasoft.JsonClassGenerator 9 | { 10 | public enum JsonTypeEnum 11 | { 12 | Anything, 13 | String, 14 | Boolean, 15 | Integer, 16 | Long, 17 | Float, 18 | Date, 19 | NullableInteger, 20 | NullableLong, 21 | NullableFloat, 22 | NullableBoolean, 23 | NullableDate, 24 | Object, 25 | Array, 26 | Dictionary, 27 | NullableSomething, 28 | NonConstrained 29 | 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/LICENSE: -------------------------------------------------------------------------------- 1 | Microsoft Reciprocal License (MS-RL) 2 | 3 | This license governs use of the accompanying software. If you use the software, you accept this license. If you do not accept the license, do not use the software. 4 | 5 | 1. Definitions 6 | The terms "reproduce," "reproduction," "derivative works," and "distribution" have the same meaning here as under U.S. copyright law. 7 | A "contribution" is the original software, or any additions or changes to the software. 8 | A "contributor" is any person that distributes its contribution under this license. 9 | "Licensed patents" are a contributor's patent claims that read directly on its contribution. 10 | 11 | 2. Grant of Rights 12 | (A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. 13 | (B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. 14 | 15 | 3. Conditions and Limitations 16 | (A) Reciprocal Grants- For any file you distribute that contains code from the software (in source code or binary format), you must provide recipients the source code to that file along with a copy of this license, which license will govern that file. You may license other files that are entirely your own work and do not contain code from the software under any terms you choose. 17 | (B) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. 18 | (C) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. 19 | (D) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. 20 | (E) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. 21 | (F) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. 22 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Json Class Generator")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Xamasoft")] 12 | [assembly: AssemblyProduct("Json Class Generator")] 13 | [assembly: AssemblyCopyright("Copyright © Xamasoft 2010-2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("d85f4fb4-29b8-4315-ad2d-74f24098c968")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.5.0.0")] 36 | [assembly: AssemblyFileVersion("1.5.0.0")] 37 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.30319.34014 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace Xamasoft.JsonClassGenerator.Properties { 12 | using System; 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources { 26 | 27 | private static global::System.Resources.ResourceManager resourceMan; 28 | 29 | private static global::System.Globalization.CultureInfo resourceCulture; 30 | 31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 32 | internal Resources() { 33 | } 34 | 35 | /// 36 | /// Returns the cached ResourceManager instance used by this class. 37 | /// 38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 39 | internal static global::System.Resources.ResourceManager ResourceManager { 40 | get { 41 | if (object.ReferenceEquals(resourceMan, null)) { 42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Xamasoft.JsonClassGenerator.Properties.Resources", typeof(Resources).Assembly); 43 | resourceMan = temp; 44 | } 45 | return resourceMan; 46 | } 47 | } 48 | 49 | /// 50 | /// Overrides the current thread's CurrentUICulture property for all 51 | /// resource lookups using this strongly typed resource class. 52 | /// 53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 54 | internal static global::System.Globalization.CultureInfo Culture { 55 | get { 56 | return resourceCulture; 57 | } 58 | set { 59 | resourceCulture = value; 60 | } 61 | } 62 | 63 | /// 64 | /// Looks up a localized resource of type System.Byte[]. 65 | /// 66 | internal static byte[] JsonClassHelper { 67 | get { 68 | object obj = ResourceManager.GetObject("JsonClassHelper", resourceCulture); 69 | return ((byte[])(obj)); 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /JsonCSharpClassGeneratorLib/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | text/microsoft-resx 91 | 92 | 93 | 1.3 94 | 95 | 96 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 97 | 98 | 99 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 100 | 101 | 102 | ..\jsonclasshelper.cs;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 103 | 104 | -------------------------------------------------------------------------------- /JsonDataContextBase/JsonDataContextBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Net; 7 | using System.Runtime.CompilerServices; 8 | using System.Runtime.InteropServices.ComTypes; 9 | using System.Security.Policy; 10 | using Newtonsoft.Json; 11 | 12 | 13 | namespace JsonDataContext 14 | { 15 | public class JsonDataContextBase 16 | { 17 | public Dictionary _jsonTextInputs = new Dictionary(); 18 | 19 | protected IEnumerable GetFileJsonInput(string filePath) 20 | { 21 | var stream = File.OpenRead(filePath); 22 | 23 | return ReadFromJsonStream(stream); 24 | } 25 | 26 | protected IEnumerable GetTextJsonInput(string key) 27 | { 28 | var json = ""; 29 | 30 | if (!_jsonTextInputs.TryGetValue(key, out json)) 31 | throw new Exception(String.Format("Could not find json data for key '{0}'", key)); 32 | 33 | if (!json.Trim().StartsWith("[")) 34 | json = String.Format("[{0}]", json.Trim()); 35 | 36 | var stream = ToStream(json); 37 | 38 | return ReadFromJsonStream(stream); 39 | } 40 | 41 | protected IEnumerable GetUrlParameterlessInput(string url, List> headers) 42 | { 43 | var req = (HttpWebRequest) HttpWebRequest.Create(url); 44 | req.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; 45 | 46 | foreach (var h in headers) 47 | { 48 | var name = h.Item1; 49 | var val = h.Item2; 50 | 51 | switch (name.ToLower()) 52 | { 53 | case "accept": 54 | req.Accept = val; 55 | break; 56 | case "user-agent": 57 | req.UserAgent = val; 58 | break; 59 | default: 60 | req.Headers.Add(String.Format("{0}:{1}", name, val)); 61 | break; 62 | } 63 | } 64 | 65 | _globalWebRequestIntercept?.Invoke(req); 66 | GetSpecificWebRequestIntercept()?.Invoke(req); 67 | 68 | var stream = req.GetResponse().GetResponseStream(); 69 | 70 | return ReadFromJsonStream(stream); 71 | } 72 | 73 | private static IEnumerable ReadFromJsonStream(Stream stream) 74 | { 75 | using (var sr = new StreamReader(stream)) 76 | { 77 | using (var reader = new JsonTextReader(sr)) 78 | { 79 | var serializer = new JsonSerializer(); 80 | 81 | if (!reader.Read()) 82 | throw new InvalidDataException("Could not interpret input as JSON"); 83 | 84 | // not an array 85 | if (reader.TokenType != JsonToken.StartArray) 86 | { 87 | var item = serializer.Deserialize(reader); 88 | yield return item; 89 | yield break; 90 | } 91 | 92 | // yes an array 93 | while (reader.Read()) 94 | { 95 | if (reader.TokenType == JsonToken.EndArray) break; 96 | var item = serializer.Deserialize(reader); 97 | yield return item; 98 | } 99 | } 100 | } 101 | } 102 | 103 | protected static Stream ToStream(string str) 104 | { 105 | var stream = new MemoryStream(); 106 | var writer = new StreamWriter(stream); 107 | writer.Write(str); 108 | writer.Flush(); 109 | stream.Position = 0; 110 | return stream; 111 | } 112 | 113 | public void SetGlobalWebRequestIntercept(Action intercept) 114 | { 115 | _globalWebRequestIntercept = intercept; 116 | } 117 | 118 | public void RemoveGlobalWebRequestIntercept() 119 | { 120 | _globalWebRequestIntercept = request => { }; 121 | } 122 | 123 | public Action GetSpecificWebRequestIntercept() 124 | { 125 | Action intercept = null; 126 | _webRequestIntercepts.TryGetValue(typeof (T), out intercept); 127 | 128 | return intercept; 129 | } 130 | 131 | public void SetSpecificWebRequestIntercept(Action intercept) 132 | { 133 | _webRequestIntercepts[typeof(T)] = intercept; 134 | } 135 | 136 | public void RemoveSpecificWebRequestIntercept() 137 | { 138 | if (_webRequestIntercepts.ContainsKey(typeof (T))) 139 | _webRequestIntercepts.Remove(typeof (T)); 140 | } 141 | public void RemoveAllSpecificWebRequestIntercepts() 142 | { 143 | _webRequestIntercepts.Clear(); 144 | } 145 | 146 | public List>> GetSpecificWebRequestIntercepts() 147 | { 148 | return _webRequestIntercepts.ToList(); 149 | } 150 | 151 | private Action _globalWebRequestIntercept = request => { }; 152 | private readonly Dictionary> _webRequestIntercepts = new Dictionary>(); 153 | } 154 | } -------------------------------------------------------------------------------- /JsonDataContextBase/JsonDataContextBase.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {687D854F-DB1B-4FF4-8EFD-91483341A150} 8 | Library 9 | Properties 10 | JsonDataContextBase 11 | JsonDataContextBase 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | true 35 | 36 | 37 | JsonDataContextDriver.snk 38 | 39 | 40 | 41 | ..\JsonDataContextDriver\packages\Newtonsoft.Json.6.0.8\lib\net40\Newtonsoft.Json.dll 42 | True 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 69 | -------------------------------------------------------------------------------- /JsonDataContextBase/JsonFileBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace JsonDataContext 8 | { 9 | public class JsonFileBase 10 | { 11 | private static List _cachedData; 12 | public static bool ShouldCacheData; 13 | 14 | public static void InvalidateCache() 15 | { 16 | _cachedData = null; 17 | } 18 | 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /JsonDataContextBase/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("JsonDataContextBase")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("JsonDataContextBase")] 13 | [assembly: AssemblyCopyright("Copyright © 2015")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("1c974a5e-8835-44a7-93e7-9ca4bfcd9c83")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("0.0.1")] 36 | [assembly: AssemblyFileVersion("0.0.1")] 37 | -------------------------------------------------------------------------------- /JsonDataContextBase/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /JsonDataContextDriver/DevDeploy.bat: -------------------------------------------------------------------------------- 1 |  2 | taskkill /f /im:LINQPad.exe 3 | xcopy /i/y *.* "%programdata%\LINQPad\Drivers\DataContext\4.0\JsonDataContextDriver (ed22602f98bb09d6)\" 4 | powershell start-process "C:\Users\rdavis\Dropbox\code\LINQPad4\LINQPad.exe" 5 | rem powershell start-process "C:\Users\rdavis\Desktop\LINQPad4\LINQPad.exe" 6 | exit 0 7 | -------------------------------------------------------------------------------- /JsonDataContextDriver/Extensions/Extensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading.Tasks; 5 | 6 | namespace JsonDataContextDriver 7 | { 8 | public static class Extensions 9 | { 10 | public static string ReplaceAll(this string s, IEnumerable> replacements) 11 | { 12 | if (String.IsNullOrEmpty(s)) 13 | return s; 14 | 15 | foreach (var repl in replacements) 16 | s = s.Replace(repl.Item1, repl.Item2); 17 | 18 | return s; 19 | } 20 | 21 | public static IEnumerable DoEach(this IEnumerable items, Action action) 22 | { 23 | foreach (var item in items) 24 | { 25 | action(item); 26 | yield return item; 27 | } 28 | } 29 | 30 | public static string SanitiseClassName(this string originalName) 31 | { 32 | var replacers = new[] { "\n", "'", " ", "*", "/", "-", "(", ")", ".", "!", "?", "#", ":", "+", "{", "}", "&", "," }; 33 | var tuples = replacers.Select(r => Tuple.Create(r, "_")).ToList(); 34 | 35 | var newName = originalName.ReplaceAll(tuples); 36 | if (char.IsNumber(newName[0])) 37 | newName = "_" + newName; 38 | 39 | return newName; 40 | } 41 | } 42 | 43 | 44 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Extensions/FolderSelectDialog/FolderSelectDialog.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Windows.Forms; 3 | 4 | // ------------------------------------------------------------------ 5 | // Wraps System.Windows.Forms.OpenFileDialog to make it present 6 | // a vista-style dialog. 7 | // ------------------------------------------------------------------ 8 | 9 | namespace FolderSelect 10 | { 11 | /// 12 | /// Wraps System.Windows.Forms.OpenFileDialog to make it present 13 | /// a vista-style dialog. 14 | /// 15 | public class FolderSelectDialog 16 | { 17 | // Wrapped dialog 18 | private System.Windows.Forms.OpenFileDialog ofd = null; 19 | 20 | /// 21 | /// Default constructor 22 | /// 23 | public FolderSelectDialog() 24 | { 25 | ofd = new System.Windows.Forms.OpenFileDialog(); 26 | 27 | ofd.Filter = "Folders|\n"; 28 | ofd.AddExtension = false; 29 | ofd.CheckFileExists = false; 30 | ofd.DereferenceLinks = true; 31 | ofd.Multiselect = false; 32 | } 33 | 34 | #region Properties 35 | 36 | /// 37 | /// Gets/Sets the initial folder to be selected. A null value selects the current directory. 38 | /// 39 | public string InitialDirectory 40 | { 41 | get { return ofd.InitialDirectory; } 42 | set { ofd.InitialDirectory = value == null || value.Length == 0 ? Environment.CurrentDirectory : value; } 43 | } 44 | 45 | /// 46 | /// Gets/Sets the title to show in the dialog 47 | /// 48 | public string Title 49 | { 50 | get { return ofd.Title; } 51 | set { ofd.Title = value == null ? "Select a folder" : value; } 52 | } 53 | 54 | /// 55 | /// Gets the selected folder 56 | /// 57 | public string FileName 58 | { 59 | get { return ofd.FileName; } 60 | } 61 | 62 | #endregion 63 | 64 | #region Methods 65 | 66 | /// 67 | /// Shows the dialog 68 | /// 69 | /// True if the user presses OK else false 70 | public bool ShowDialog() 71 | { 72 | return ShowDialog(IntPtr.Zero); 73 | } 74 | 75 | /// 76 | /// Shows the dialog 77 | /// 78 | /// Handle of the control to be parent 79 | /// True if the user presses OK else false 80 | public bool ShowDialog(IntPtr hWndOwner) 81 | { 82 | bool flag = false; 83 | 84 | if (Environment.OSVersion.Version.Major >= 6) 85 | { 86 | var r = new Reflector("System.Windows.Forms"); 87 | 88 | uint num = 0; 89 | Type typeIFileDialog = r.GetType("FileDialogNative.IFileDialog"); 90 | object dialog = r.Call(ofd, "CreateVistaDialog"); 91 | r.Call(ofd, "OnBeforeVistaDialog", dialog); 92 | 93 | uint options = (uint) r.CallAs(typeof (System.Windows.Forms.FileDialog), ofd, "GetOptions"); 94 | options |= (uint) r.GetEnum("FileDialogNative.FOS", "FOS_PICKFOLDERS"); 95 | r.CallAs(typeIFileDialog, dialog, "SetOptions", options); 96 | 97 | object pfde = r.New("FileDialog.VistaDialogEvents", ofd); 98 | object[] parameters = new object[] {pfde, num}; 99 | r.CallAs2(typeIFileDialog, dialog, "Advise", parameters); 100 | num = (uint) parameters[1]; 101 | try 102 | { 103 | int num2 = (int) r.CallAs(typeIFileDialog, dialog, "Show", hWndOwner); 104 | flag = 0 == num2; 105 | } 106 | finally 107 | { 108 | r.CallAs(typeIFileDialog, dialog, "Unadvise", num); 109 | GC.KeepAlive(pfde); 110 | } 111 | } 112 | else 113 | { 114 | var fbd = new FolderBrowserDialog(); 115 | fbd.Description = this.Title; 116 | fbd.SelectedPath = this.InitialDirectory; 117 | fbd.ShowNewFolderButton = false; 118 | if (fbd.ShowDialog(new WindowWrapper(hWndOwner)) != DialogResult.OK) return false; 119 | ofd.FileName = fbd.SelectedPath; 120 | flag = true; 121 | } 122 | 123 | return flag; 124 | } 125 | 126 | #endregion 127 | } 128 | 129 | /// 130 | /// Creates IWin32Window around an IntPtr 131 | /// 132 | public class WindowWrapper : System.Windows.Forms.IWin32Window 133 | { 134 | /// 135 | /// Constructor 136 | /// 137 | /// Handle to wrap 138 | public WindowWrapper(IntPtr handle) 139 | { 140 | _hwnd = handle; 141 | } 142 | 143 | /// 144 | /// Original ptr 145 | /// 146 | public IntPtr Handle 147 | { 148 | get { return _hwnd; } 149 | } 150 | 151 | private IntPtr _hwnd; 152 | } 153 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Extensions/FolderSelectDialog/README.md: -------------------------------------------------------------------------------- 1 | From http://www.lyquidity.com/devblog/?p=136 2 | -------------------------------------------------------------------------------- /JsonDataContextDriver/Extensions/FolderSelectDialog/Reflector.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reflection; 3 | 4 | namespace FolderSelect 5 | { 6 | /// 7 | /// This class is from the Front-End for Dosbox and is used to present a 'vista' dialog box to select folders. 8 | /// Being able to use a vista style dialog box to select folders is much better then using the shell folder browser. 9 | /// http://code.google.com/p/fed/ 10 | /// 11 | /// Example: 12 | /// var r = new Reflector("System.Windows.Forms"); 13 | /// 14 | public class Reflector 15 | { 16 | #region variables 17 | 18 | private string m_ns; 19 | private Assembly m_asmb; 20 | 21 | #endregion 22 | 23 | #region Constructors 24 | 25 | /// 26 | /// Constructor 27 | /// 28 | /// The namespace containing types to be used 29 | public Reflector(string ns) 30 | : this(ns, ns) 31 | { 32 | } 33 | 34 | /// 35 | /// Constructor 36 | /// 37 | /// A specific assembly name (used if the assembly name does not tie exactly with the namespace) 38 | /// The namespace containing types to be used 39 | public Reflector(string an, string ns) 40 | { 41 | m_ns = ns; 42 | m_asmb = null; 43 | foreach (AssemblyName aN in Assembly.GetExecutingAssembly().GetReferencedAssemblies()) 44 | { 45 | if (aN.FullName.StartsWith(an)) 46 | { 47 | m_asmb = Assembly.Load(aN); 48 | break; 49 | } 50 | } 51 | } 52 | 53 | #endregion 54 | 55 | #region Methods 56 | 57 | /// 58 | /// Return a Type instance for a type 'typeName' 59 | /// 60 | /// The name of the type 61 | /// A type instance 62 | public Type GetType(string typeName) 63 | { 64 | Type type = null; 65 | string[] names = typeName.Split('.'); 66 | 67 | if (names.Length > 0) 68 | type = m_asmb.GetType(m_ns + "." + names[0]); 69 | 70 | for (int i = 1; i < names.Length; ++i) 71 | { 72 | type = type.GetNestedType(names[i], BindingFlags.NonPublic); 73 | } 74 | return type; 75 | } 76 | 77 | /// 78 | /// Create a new object of a named type passing along any params 79 | /// 80 | /// The name of the type to create 81 | /// 82 | /// An instantiated type 83 | public object New(string name, params object[] parameters) 84 | { 85 | Type type = GetType(name); 86 | 87 | ConstructorInfo[] ctorInfos = type.GetConstructors(); 88 | foreach (ConstructorInfo ci in ctorInfos) 89 | { 90 | try 91 | { 92 | return ci.Invoke(parameters); 93 | } 94 | catch 95 | { 96 | } 97 | } 98 | 99 | return null; 100 | } 101 | 102 | /// 103 | /// Calls method 'func' on object 'obj' passing parameters 'parameters' 104 | /// 105 | /// The object on which to excute function 'func' 106 | /// The function to execute 107 | /// The parameters to pass to function 'func' 108 | /// The result of the function invocation 109 | public object Call(object obj, string func, params object[] parameters) 110 | { 111 | return Call2(obj, func, parameters); 112 | } 113 | 114 | /// 115 | /// Calls method 'func' on object 'obj' passing parameters 'parameters' 116 | /// 117 | /// The object on which to excute function 'func' 118 | /// The function to execute 119 | /// The parameters to pass to function 'func' 120 | /// The result of the function invocation 121 | public object Call2(object obj, string func, object[] parameters) 122 | { 123 | return CallAs2(obj.GetType(), obj, func, parameters); 124 | } 125 | 126 | /// 127 | /// Calls method 'func' on object 'obj' which is of type 'type' passing parameters 'parameters' 128 | /// 129 | /// The type of 'obj' 130 | /// The object on which to excute function 'func' 131 | /// The function to execute 132 | /// The parameters to pass to function 'func' 133 | /// The result of the function invocation 134 | public object CallAs(Type type, object obj, string func, params object[] parameters) 135 | { 136 | return CallAs2(type, obj, func, parameters); 137 | } 138 | 139 | /// 140 | /// Calls method 'func' on object 'obj' which is of type 'type' passing parameters 'parameters' 141 | /// 142 | /// The type of 'obj' 143 | /// The object on which to excute function 'func' 144 | /// The function to execute 145 | /// The parameters to pass to function 'func' 146 | /// The result of the function invocation 147 | public object CallAs2(Type type, object obj, string func, object[] parameters) 148 | { 149 | MethodInfo methInfo = type.GetMethod(func, 150 | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 151 | return methInfo.Invoke(obj, parameters); 152 | } 153 | 154 | /// 155 | /// Returns the value of property 'prop' of object 'obj' 156 | /// 157 | /// The object containing 'prop' 158 | /// The property name 159 | /// The property value 160 | public object Get(object obj, string prop) 161 | { 162 | return GetAs(obj.GetType(), obj, prop); 163 | } 164 | 165 | /// 166 | /// Returns the value of property 'prop' of object 'obj' which has type 'type' 167 | /// 168 | /// The type of 'obj' 169 | /// The object containing 'prop' 170 | /// The property name 171 | /// The property value 172 | public object GetAs(Type type, object obj, string prop) 173 | { 174 | PropertyInfo propInfo = type.GetProperty(prop, 175 | BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); 176 | return propInfo.GetValue(obj, null); 177 | } 178 | 179 | /// 180 | /// Returns an enum value 181 | /// 182 | /// The name of enum type 183 | /// The name of the value 184 | /// The enum value 185 | public object GetEnum(string typeName, string name) 186 | { 187 | Type type = GetType(typeName); 188 | FieldInfo fieldInfo = type.GetField(name); 189 | return fieldInfo.GetValue(null); 190 | } 191 | 192 | #endregion 193 | } 194 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Extensions/LinqPadSampleCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Reflection; 6 | using LINQPad.Extensibility.DataContext; 7 | 8 | namespace JsonDataContextDriver 9 | { 10 | public static class LinqPadSampleCode 11 | { 12 | // These methods taken from the Static/Universal LINQPad context driver sample 13 | 14 | public static List GetSchema(Type customType) 15 | { 16 | // Return the objects with which to populate the Schema Explorer by reflecting over customType. 17 | 18 | // We'll start by retrieving all the properties of the custom type that implement IEnumerable: 19 | var topLevelProps = 20 | ( 21 | from prop in customType.GetProperties() 22 | where prop.PropertyType != typeof (string) 23 | 24 | // Display all properties of type IEnumerable (except for string!) 25 | let ienumerableOfT = prop.PropertyType.GetInterface("System.Collections.Generic.IEnumerable`1") 26 | 27 | where ienumerableOfT != null || prop.PropertyType.Name == "IEnumerable`1" // why? 28 | orderby prop.Name 29 | 30 | select new ExplorerItem(prop.Name, ExplorerItemKind.QueryableObject, ExplorerIcon.Table) 31 | { 32 | IsEnumerable = true, 33 | ToolTipText = prop.PropertyType.Name, 34 | 35 | // Store the entity type to the Tag property. We'll use it later. 36 | Tag = prop.PropertyType.GetGenericArguments()[0] 37 | } 38 | ).ToList(); 39 | 40 | // Create a lookup keying each element type to the properties of that type. This will allow 41 | // us to build hyperlink targets allowing the user to click between associations: 42 | var elementTypeLookup = topLevelProps.ToLookup(tp => (Type) tp.Tag); 43 | 44 | // Populate the columns (properties) of each entity: 45 | foreach (ExplorerItem table in topLevelProps) 46 | table.Children = ((Type) table.Tag) 47 | .GetProperties() 48 | .Select(childProp => GetChildItem(elementTypeLookup, childProp)) 49 | .OrderBy(childItem => childItem.Kind) 50 | .ToList(); 51 | 52 | return topLevelProps; 53 | } 54 | 55 | private static ExplorerItem GetChildItem(ILookup elementTypeLookup, PropertyInfo childProp) 56 | { 57 | // If the property's type is in our list of entities, then it's a Many:1 (or 1:1) reference. 58 | // We'll assume it's a Many:1 (we can't reliably identify 1:1s purely from reflection). 59 | if (elementTypeLookup.Contains(childProp.PropertyType)) 60 | return new ExplorerItem(childProp.Name, ExplorerItemKind.ReferenceLink, ExplorerIcon.ManyToOne) 61 | { 62 | HyperlinkTarget = elementTypeLookup[childProp.PropertyType].First(), 63 | // FormatTypeName is a helper method that returns a nicely formatted type name. 64 | ToolTipText = childProp.PropertyType.Name 65 | }; 66 | 67 | // Is the property's type a collection of entities? 68 | Type ienumerableOfT = childProp.PropertyType.GetInterface("System.Collections.Generic.IEnumerable`1"); 69 | if (ienumerableOfT != null) 70 | { 71 | Type elementType = ienumerableOfT.GetGenericArguments()[0]; 72 | if (elementTypeLookup.Contains(elementType)) 73 | return new ExplorerItem(childProp.Name, ExplorerItemKind.CollectionLink, ExplorerIcon.OneToMany) 74 | { 75 | HyperlinkTarget = elementTypeLookup[elementType].First(), 76 | ToolTipText = elementType.Name 77 | }; 78 | } 79 | 80 | // Ordinary property: 81 | return new ExplorerItem(childProp.Name + " (" + (childProp.PropertyType.Name) + ")", 82 | ExplorerItemKind.Property, ExplorerIcon.Column); 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Extensions/NotepadHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace JsonDataContextDriver 7 | { 8 | using System; 9 | using System.Runtime.InteropServices; 10 | using System.Diagnostics; 11 | 12 | // http://stackoverflow.com/a/14295249 13 | namespace Notepad 14 | { 15 | public static class NotepadHelper 16 | { 17 | [DllImport("user32.dll", EntryPoint = "SetWindowText")] 18 | private static extern int SetWindowText(IntPtr hWnd, string text); 19 | 20 | [DllImport("user32.dll", EntryPoint = "FindWindowEx")] 21 | private static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow); 22 | 23 | [DllImport("User32.dll", EntryPoint = "SendMessage")] 24 | private static extern int SendMessage(IntPtr hWnd, int uMsg, int wParam, string lParam); 25 | 26 | public static void ShowMessage(string message = null, string title = null) 27 | { 28 | Process notepad = Process.Start(new ProcessStartInfo("notepad.exe")); 29 | if (notepad != null) 30 | { 31 | notepad.WaitForInputIdle(); 32 | 33 | if (!string.IsNullOrEmpty(title)) 34 | SetWindowText(notepad.MainWindowHandle, title); 35 | 36 | if (!string.IsNullOrEmpty(message)) 37 | { 38 | IntPtr child = FindWindowEx(notepad.MainWindowHandle, new IntPtr(0), "Edit", null); 39 | SendMessage(child, 0x000C, 0, message); 40 | } 41 | } 42 | } 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /JsonDataContextDriver/FodyWeavers.xml: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/IGeneratedClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace JsonDataContextDriver 4 | { 5 | public interface IGeneratedClass 6 | { 7 | string Namespace { get; set; } 8 | string ClassName { get; set; } 9 | string ClassDefinition { get; set; } 10 | bool Success { get; set; } 11 | Exception Error { get; set; } 12 | 13 | IJsonInput OriginalInput { get; set; } 14 | } 15 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/IJsonInput.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using LINQPad.Extensibility.DataContext; 3 | 4 | namespace JsonDataContextDriver 5 | { 6 | public interface IJsonInput 7 | { 8 | void GenerateClasses(string nameSpace); 9 | 10 | List GeneratedClasses { get; } 11 | List ExplorerItems { get; } 12 | List NamespacesToAdd { get; } 13 | List ContextProperties { get; } 14 | List Errors { get; } 15 | } 16 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonFileGeneratedClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace JsonDataContextDriver 4 | { 5 | public class JsonFileGeneratedClass : IGeneratedClass 6 | { 7 | public JsonFileGeneratedClass(JsonFileInput input) 8 | { 9 | OriginalInput = input; 10 | } 11 | 12 | public string Namespace { get; set; } 13 | public string ClassName { get; set; } 14 | public string DataFilePath { get; set; } 15 | public string ClassDefinition { get; set; } 16 | public bool Success { get; set; } 17 | public Exception Error { get; set; } 18 | 19 | public JsonFileInput OriginalInput { get; set; } 20 | IJsonInput IGeneratedClass.OriginalInput 21 | { 22 | get { return OriginalInput; } 23 | set { OriginalInput = (JsonFileInput) value; } 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonFileInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Runtime.Serialization; 6 | using System.Threading.Tasks; 7 | using System.Windows; 8 | using System.Windows.Input; 9 | using System.Windows.Media; 10 | using JsonDataContextDriver; 11 | using LINQPad.Extensibility.DataContext; 12 | using Newtonsoft.Json; 13 | using Newtonsoft.Json.Linq; 14 | using PropertyChanged; 15 | using Xamasoft.JsonClassGenerator; 16 | 17 | namespace JsonDataContextDriver 18 | { 19 | [ImplementPropertyChanged] 20 | public class JsonFileInput : IJsonInput 21 | { 22 | public string InputPath { get; set; } 23 | 24 | public string Mask { get; set; } 25 | 26 | public bool Recursive { get; set; } 27 | 28 | public int NumRowsToSample { get; set; } 29 | 30 | public JsonInputType InputType 31 | { 32 | get 33 | { 34 | if (string.IsNullOrWhiteSpace(InputPath)) 35 | return JsonInputType.Nothing; 36 | if (File.Exists(InputPath)) 37 | return JsonInputType.File; 38 | if (Directory.Exists(InputPath)) 39 | return JsonInputType.Directory; 40 | return JsonInputType.Invalid; 41 | } 42 | } 43 | 44 | public bool IsDirectory 45 | { 46 | get { return InputType == JsonInputType.Directory; } 47 | } 48 | 49 | public JsonFileInput() 50 | { 51 | NumRowsToSample = 50; 52 | NamespacesToAdd = new List(); 53 | } 54 | 55 | public override string ToString() 56 | { 57 | switch (InputType) 58 | { 59 | case JsonInputType.File: 60 | return String.Format("{1}: {0}", InputPath, Path.GetFileNameWithoutExtension(InputPath)); 61 | case JsonInputType.Directory: 62 | return String.Format("Search Folder: {0}", Path.Combine(InputPath, Mask ?? "*.*") + (Recursive ? " + subfolders" : "")); 63 | default: 64 | return "ERR"; 65 | } 66 | } 67 | 68 | public void GenerateClasses(string nameSpace) 69 | { 70 | var numSamples = NumRowsToSample; 71 | 72 | _generatedClasses = 73 | GetInputFiles() 74 | .Select(f => 75 | { 76 | // TODO: Be a better error handler 77 | try 78 | { 79 | var fs = new FileStream(f, FileMode.Open); 80 | var sr = new StreamReader(fs); 81 | var jtr = new JsonTextReader(sr); 82 | 83 | var examples = 84 | Enumerable 85 | .Range(0, numSamples) 86 | .Select(_ => 87 | { 88 | while (jtr.Read()) 89 | if (jtr.TokenType == JsonToken.StartObject) 90 | return JObject.Load(jtr).ToString(); 91 | return null; 92 | }) 93 | .Where(json => json != null); 94 | 95 | var examplesJson = String.Format("[{0}]", String.Join(",\r\n", examples)); 96 | 97 | jtr.Close(); 98 | sr.Close(); 99 | fs.Close(); 100 | 101 | var className = Path.GetFileNameWithoutExtension(f).SanitiseClassName(); 102 | var finalNamespace = nameSpace + "." + className + "Input"; 103 | var outputStream = new MemoryStream(); 104 | var outputWriter = new StreamWriter(outputStream); 105 | 106 | var jsg = new JsonClassGenerator 107 | { 108 | Example = examplesJson, 109 | Namespace = finalNamespace, 110 | MainClass = className, 111 | OutputStream = outputWriter, 112 | NoHelperClass = true, 113 | UseProperties = true, 114 | GeneratePartialClasses = true 115 | }; 116 | 117 | jsg.GenerateClasses(); 118 | 119 | outputWriter.Flush(); 120 | outputStream.Seek(0, SeekOrigin.Begin); 121 | 122 | var classDef = new StreamReader(outputStream) 123 | .ReadToEnd() 124 | .Replace("IList<", "List<"); 125 | 126 | classDef = 127 | classDef.Substring(classDef.IndexOf(String.Format("namespace {0}", nameSpace), 128 | StringComparison.Ordinal)); 129 | 130 | NamespacesToAdd.Add(finalNamespace); 131 | 132 | return new JsonFileGeneratedClass(this) 133 | { 134 | Namespace = finalNamespace, 135 | ClassName = className, 136 | DataFilePath = f, 137 | ClassDefinition = classDef, 138 | Success = true 139 | }; 140 | } 141 | catch (Exception e) 142 | { 143 | return new JsonFileGeneratedClass(this) 144 | { 145 | DataFilePath = f, 146 | Success = false, 147 | Error = e 148 | }; 149 | } 150 | }) 151 | .ToList(); 152 | } 153 | 154 | private List GetInputFiles() 155 | { 156 | switch (InputType) 157 | { 158 | case JsonInputType.File: 159 | return new List { InputPath }; 160 | case JsonInputType.Directory: 161 | return 162 | Directory.GetFiles(InputPath, Mask, 163 | Recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly).ToList(); 164 | default: 165 | return new List(); 166 | } 167 | } 168 | 169 | private List _generatedClasses = new List(); 170 | public List GeneratedClasses { get { return _generatedClasses.OfType().ToList(); } } 171 | public List ExplorerItems { get; set; } 172 | public List NamespacesToAdd { get; set; } 173 | 174 | public List ContextProperties => _generatedClasses 175 | .Where(c=> c.Success) 176 | .Select(c => 177 | String.Format( 178 | "public IEnumerable<{0}.{1}> {2}s {{ get {{ return GetFileJsonInput<{0}.{1}>(@\"{3}\"); }} }}", 179 | c.Namespace, c.ClassName, c.ClassName, c.DataFilePath)) 180 | .ToList(); 181 | 182 | public List Errors => _generatedClasses 183 | .Where(c=> !c.Success) 184 | .Select(e => String.Format(" {0} - {1}", e.DataFilePath, e.Error.Message)) 185 | .ToList(); 186 | } 187 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonInputType.cs: -------------------------------------------------------------------------------- 1 | namespace JsonDataContextDriver 2 | { 3 | public enum JsonInputType 4 | { 5 | Nothing, 6 | File, 7 | Directory, 8 | Invalid 9 | } 10 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonTextGeneratedClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace JsonDataContextDriver 4 | { 5 | public class JsonTextGeneratedClass : IGeneratedClass 6 | { 7 | public JsonTextGeneratedClass(JsonTextInput input) 8 | { 9 | Input = input; 10 | } 11 | 12 | public string Namespace { get; set; } 13 | public string ClassName { get; set; } 14 | public string ClassDefinition { get; set; } 15 | public bool Success { get; set; } 16 | public Exception Error { get; set; } 17 | 18 | public JsonTextInput Input { get; set; } 19 | IJsonInput IGeneratedClass.OriginalInput 20 | { 21 | get { return Input; } 22 | set { Input = (JsonTextInput)value; } 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonTextInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Dynamic; 4 | using System.IO; 5 | using System.Runtime.Serialization; 6 | using LINQPad.Extensibility.DataContext; 7 | using Newtonsoft.Json; 8 | using PropertyChanged; 9 | using Xamasoft.JsonClassGenerator; 10 | using JsonDataContextDriver; 11 | 12 | namespace JsonDataContextDriver 13 | { 14 | [ImplementPropertyChanged] 15 | public class JsonTextInput : IJsonInput 16 | { 17 | public string InputGuid { get; set; } 18 | public string Name { get; set; } 19 | public string Json { get; set; } 20 | 21 | private JsonTextGeneratedClass _generatedClass; 22 | 23 | public JsonTextInput() 24 | { 25 | InputGuid = Guid.NewGuid().ToString(); 26 | NamespacesToAdd = new List(); 27 | } 28 | 29 | public override string ToString() 30 | { 31 | var summary = ""; 32 | try { summary = String.Format(" : {0} rows of json text", JsonConvert.DeserializeObject>(Json).Count); } catch { } 33 | 34 | return String.Format("{0}{1}", Name, summary); 35 | } 36 | 37 | public void GenerateClasses(string nameSpace) 38 | { 39 | try 40 | { 41 | var className = Name.SanitiseClassName(); 42 | 43 | var finalNamespace = nameSpace + "." + className + "Input"; 44 | var outputStream = new MemoryStream(); 45 | var outputWriter = new StreamWriter(outputStream); 46 | 47 | var jsg = new JsonClassGenerator 48 | { 49 | Example = Json, 50 | Namespace = finalNamespace, 51 | MainClass = className, 52 | OutputStream = outputWriter, 53 | NoHelperClass = true, 54 | UseProperties = true, 55 | GeneratePartialClasses = true 56 | }; 57 | 58 | jsg.GenerateClasses(); 59 | 60 | outputWriter.Flush(); 61 | outputStream.Seek(0, SeekOrigin.Begin); 62 | 63 | var classDef = new StreamReader(outputStream) 64 | .ReadToEnd() 65 | .Replace("IList<", "List<"); 66 | 67 | classDef = 68 | classDef.Substring(classDef.IndexOf(String.Format("namespace {0}", nameSpace), 69 | StringComparison.Ordinal)); 70 | 71 | NamespacesToAdd.Add(finalNamespace); 72 | 73 | _generatedClass = new JsonTextGeneratedClass(this) 74 | { 75 | Namespace = finalNamespace, 76 | ClassName = className, 77 | ClassDefinition = classDef, 78 | Success = true 79 | }; 80 | } 81 | catch (Exception e) 82 | { 83 | _generatedClass = new JsonTextGeneratedClass(this) 84 | { 85 | Success = false, 86 | Error = e 87 | }; 88 | } 89 | } 90 | 91 | [JsonIgnore] 92 | public List GeneratedClasses { get { return new List {_generatedClass}; } } 93 | [JsonIgnore] 94 | public List ExplorerItems { get; set; } 95 | [JsonIgnore] 96 | public List NamespacesToAdd { get; set; } 97 | 98 | [JsonIgnore] 99 | public List ContextProperties => new List 100 | { 101 | String.Format("public IEnumerable<{0}.{1}> {1} {{ get {{ return GetTextJsonInput<{0}.{1}>(\"{2}\"); }}}}", _generatedClass.Namespace, _generatedClass.ClassName, InputGuid) 102 | }; 103 | 104 | [JsonIgnore] 105 | public List Errors { get { return _generatedClass == null || _generatedClass.Success ? new List() : new List { _generatedClass.Error.Message }; } } 106 | } 107 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonUrlGeneratedClass.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace JsonDataContextDriver 4 | { 5 | public class JsonUrlGeneratedClass : IGeneratedClass 6 | { 7 | public JsonUrlGeneratedClass(JsonUrlInput input) 8 | { 9 | OriginalInput = input; 10 | } 11 | 12 | public string OriginalName { get; set; } 13 | public string Url { get; set; } 14 | 15 | public string Namespace { get; set; } 16 | public string ClassName { get; set; } 17 | public string ClassDefinition { get; set; } 18 | public bool Success { get; set; } 19 | public Exception Error { get; set; } 20 | 21 | public JsonUrlInput OriginalInput; 22 | IJsonInput IGeneratedClass.OriginalInput 23 | { 24 | get { return OriginalInput; } 25 | set { OriginalInput = (JsonUrlInput) value; } 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Inputs/JsonUrlInput.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom; 3 | using System.CodeDom.Compiler; 4 | using System.Collections.Generic; 5 | using System.Collections.ObjectModel; 6 | using System.IO; 7 | using System.Linq; 8 | using System.Net; 9 | using System.Web; 10 | using LINQPad.Extensibility.DataContext; 11 | using Newtonsoft.Json; 12 | using PropertyChanged; 13 | using Xamasoft.JsonClassGenerator; 14 | 15 | namespace JsonDataContextDriver 16 | { 17 | [ImplementPropertyChanged] 18 | public class JsonUrlInput : IJsonInput 19 | { 20 | public string Name { get; set; } 21 | public string Url { get; set; } 22 | public ObservableCollection Headers { get; set; } 23 | 24 | public bool GenerateAsMethod { get; set; } 25 | 26 | public JsonUrlInput() 27 | { 28 | NamespacesToAdd = new List(); 29 | Headers = new ObservableCollection(); 30 | Errors = new List(); 31 | } 32 | 33 | public void GenerateClasses(string nameSpace) 34 | { 35 | try 36 | { 37 | var req = (HttpWebRequest) HttpWebRequest.Create(Url); 38 | req.AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip; 39 | req.UserAgent = @"Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/41.0.2228.0 Safari/537.36"; 40 | 41 | var examplesJson = ""; 42 | using (var sr = new StreamReader(req.GetResponse().GetResponseStream())) 43 | examplesJson = sr.ReadToEnd(); 44 | 45 | var className = Name.SanitiseClassName(); 46 | var finalNamespace = nameSpace + "." + className + "Input"; 47 | var outputStream = new MemoryStream(); 48 | var outputWriter = new StreamWriter(outputStream); 49 | 50 | var jsg = new JsonClassGenerator 51 | { 52 | Example = examplesJson, 53 | Namespace = finalNamespace, 54 | MainClass = className, 55 | OutputStream = outputWriter, 56 | NoHelperClass = true, 57 | UseProperties = true, 58 | GeneratePartialClasses = true 59 | }; 60 | 61 | jsg.GenerateClasses(); 62 | 63 | outputWriter.Flush(); 64 | outputStream.Seek(0, SeekOrigin.Begin); 65 | 66 | var classDef = new StreamReader(outputStream) 67 | .ReadToEnd() 68 | .Replace("IList<", "List<"); 69 | 70 | classDef = 71 | classDef.Substring(classDef.IndexOf(String.Format("namespace {0}", nameSpace), 72 | StringComparison.Ordinal)); 73 | 74 | NamespacesToAdd.Add(finalNamespace); 75 | 76 | GeneratedClasses = new List 77 | { 78 | new JsonUrlGeneratedClass(this) 79 | { 80 | Namespace = finalNamespace, 81 | ClassName = className, 82 | Url = Url, 83 | ClassDefinition = classDef, 84 | Success = true 85 | } 86 | }; 87 | } 88 | catch (Exception e) 89 | { 90 | GeneratedClasses = new List 91 | { 92 | new JsonUrlGeneratedClass(this) 93 | { 94 | Url = Url, 95 | Success = false, 96 | Error = e 97 | } 98 | }; 99 | } 100 | 101 | } 102 | 103 | [JsonIgnore] 104 | public List GeneratedClasses { get; set; } 105 | 106 | [JsonIgnore] 107 | public List ExplorerItems => 108 | GeneratedClasses 109 | .OfType() 110 | .Where(c => c.OriginalInput.GenerateAsMethod) 111 | .Select( 112 | c => new ExplorerItem(GetNameForMethod(c), ExplorerItemKind.QueryableObject, ExplorerIcon.Box) 113 | { 114 | Children = new List { 115 | new ExplorerItem("Parameters", ExplorerItemKind.Category, ExplorerIcon.Schema) 116 | { 117 | Children = c.OriginalInput.GetUrlQueryStringParameters() 118 | .Select(p=> new ExplorerItem(p.Item1, ExplorerItemKind.Parameter, ExplorerIcon.Parameter)) 119 | .ToList() 120 | }, 121 | } 122 | }) 123 | .ToList(); 124 | 125 | [JsonIgnore] 126 | public List NamespacesToAdd { get; set; } 127 | 128 | [JsonIgnore] 129 | public List ContextProperties => 130 | GeneratedClasses 131 | .OfType() 132 | .Select(GetContextMethod) 133 | .ToList(); 134 | 135 | [JsonIgnore] 136 | public List Errors { get; set; } 137 | 138 | private static string GetContextMethod(JsonUrlGeneratedClass c) 139 | { 140 | var hs = c.OriginalInput 141 | .Headers 142 | .Select(h => String.Format("Tuple.Create({0},{1})", ToLiteral(h.Name), ToLiteral(h.Value))); 143 | 144 | var hsParam = String.Format("new List> {{ {0} }}", String.Join(", ", hs)); 145 | 146 | if (c.OriginalInput.GenerateAsMethod) 147 | { 148 | var ns = c.Namespace; 149 | var name = GetNameForMethod(c); 150 | var cls = c.ClassName; 151 | 152 | var url = c.Url; 153 | var ps = c.OriginalInput.GetUrlQueryStringParameters(); 154 | 155 | var args = String.Join(", ", ps.Select(p => String.Format("string {0} = {1}", p.Item1, ToLiteral(p.Item2)))); 156 | var prototype = String.Format("public IEnumerable<{0}.{1}> {2}({3})", ns, cls, name, args); 157 | 158 | var methodBody = 159 | String.Format("var _____uri = new UriBuilder(@\"{0}\");\r\n", url) + 160 | String.Format("var _____q = HttpUtility.ParseQueryString(_____uri.Query);\r\n\r\n") + 161 | String.Join(Environment.NewLine, ps.Select(q => String.Format("_____q[\"{0}\"] = {0};", q.Item1))) + "\r\n\r\n" + 162 | String.Format("_____uri.Query = _____q.ToString();\r\n\r\n") + 163 | 164 | String.Format("return GetUrlParameterlessInput<{0}.{1}>(_____uri.ToString(), {2});", ns, cls, hsParam); 165 | 166 | return String.Format("{0}\r\n{{\r\n{1}\r\n}}", prototype, methodBody); 167 | } 168 | else 169 | return String.Format( 170 | "public IEnumerable<{0}.{1}> {2}s {{ get {{ return GetUrlParameterlessInput<{0}.{1}>(@\"{3}\", {4}); }} }}", 171 | c.Namespace, c.ClassName, c.ClassName, c.Url, hsParam); 172 | } 173 | 174 | private List> GetUrlQueryStringParameters() 175 | { 176 | var uri = new UriBuilder(Url); 177 | var pcol = HttpUtility.ParseQueryString(uri.Query); 178 | var ps = pcol 179 | .AllKeys 180 | .Select(k => Tuple.Create(k, pcol[k])) 181 | .ToList(); 182 | return ps; 183 | } 184 | 185 | private static string GetNameForMethod(JsonUrlGeneratedClass c) 186 | { 187 | return String.Format("Get{0}", c.ClassName.SanitiseClassName()); 188 | } 189 | 190 | private static string ToLiteral(string input) 191 | { 192 | using (var writer = new StringWriter()) 193 | { 194 | using (var provider = CodeDomProvider.CreateProvider("CSharp")) 195 | { 196 | provider.GenerateCodeFromExpression(new CodePrimitiveExpression(input), writer, new CodeGeneratorOptions { IndentString = "\t" }); 197 | var literal = writer.ToString(); 198 | literal = literal.Replace(string.Format("\" +{0}\t\"", Environment.NewLine), ""); 199 | return literal; 200 | } 201 | } 202 | } 203 | 204 | public override string ToString() 205 | { 206 | var uri = new Uri(Url); 207 | 208 | return GenerateAsMethod 209 | ? String.Format("{0}: {1} with parameters ({2})", this.Name, uri.Host+uri.AbsolutePath, 210 | String.Join(", ", GetUrlQueryStringParameters().Select(p => p.Item1))) 211 | : String.Format("{0}: {1}", this.Name, this.Url); 212 | } 213 | } 214 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/JsonDataContextDriver.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7} 8 | Library 9 | Properties 10 | JsonDataContextDriver 11 | JsonDataContextDriver 12 | v4.0 13 | 512 14 | 15 | 0d46b64e 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | false 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | false 35 | 36 | 37 | true 38 | 39 | 40 | JsonDataContextDriver.snk 41 | 42 | 43 | 44 | ..\..\..\..\Dropbox\code\LINQPad4\LINQPad.exe 45 | False 46 | 47 | 48 | False 49 | packages\Newtonsoft.Json.6.0.8\lib\net40\Newtonsoft.Json.dll 50 | 51 | 52 | 53 | 54 | False 55 | packages\PropertyChanged.Fody.1.50.1\Lib\portable-net4+sl4+wp8+win8+wpa81+MonoAndroid16+MonoTouch40\PropertyChanged.dll 56 | False 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.dll 72 | 73 | 74 | packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.Themes.Aero.dll 75 | 76 | 77 | packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.Themes.Metro.dll 78 | 79 | 80 | packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.AvalonDock.Themes.VS2010.dll 81 | 82 | 83 | packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.DataGrid.dll 84 | 85 | 86 | False 87 | packages\Extended.Wpf.Toolkit.2.4\lib\net40\Xceed.Wpf.Toolkit.dll 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | AddNewUrlSourceDialog.xaml 98 | 99 | 100 | AddNewTextSourceDialog.xaml 101 | 102 | 103 | AddNewFolderSourceDialog.xaml 104 | 105 | 106 | AddNewFileSourceDialog.xaml 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | ConnectionDialog.xaml 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | MSBuild:Compile 126 | Designer 127 | 128 | 129 | MSBuild:Compile 130 | Designer 131 | 132 | 133 | MSBuild:Compile 134 | Designer 135 | 136 | 137 | Designer 138 | MSBuild:Compile 139 | 140 | 141 | MSBuild:Compile 142 | Designer 143 | 144 | 145 | 146 | 147 | Always 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | {7bef7eaa-de37-40fb-bd33-3def0685031f} 156 | JsonClassGeneratorLib 157 | 158 | 159 | {687d854f-db1b-4ff4-8efd-91483341a150} 160 | JsonDataContextBase 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | DevDeploy.bat 172 | 173 | 174 | 175 | 176 | This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 177 | 178 | 179 | 180 | 187 | -------------------------------------------------------------------------------- /JsonDataContextDriver/JsonDataContextDriver.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 2013 4 | VisualStudioVersion = 12.0.31101.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonDataContextDriver", "JsonDataContextDriver.csproj", "{32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonClassGeneratorLib", "..\JsonCSharpClassGeneratorLib\JsonClassGeneratorLib.csproj", "{7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E1C35EA5-F959-4CA9-85E5-8654158C43C4}" 11 | ProjectSection(SolutionItems) = preProject 12 | ..\.gitignore = ..\.gitignore 13 | ..\LICENSE = ..\LICENSE 14 | ..\README.md = ..\README.md 15 | EndProjectSection 16 | EndProject 17 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "JsonDataContextBase", "..\JsonDataContextBase\JsonDataContextBase.csproj", "{687D854F-DB1B-4FF4-8EFD-91483341A150}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Ad-Hoc|Any CPU = Ad-Hoc|Any CPU 22 | Ad-Hoc|iPhone = Ad-Hoc|iPhone 23 | Ad-Hoc|iPhoneSimulator = Ad-Hoc|iPhoneSimulator 24 | Ad-Hoc|Mixed Platforms = Ad-Hoc|Mixed Platforms 25 | AppStore|Any CPU = AppStore|Any CPU 26 | AppStore|iPhone = AppStore|iPhone 27 | AppStore|iPhoneSimulator = AppStore|iPhoneSimulator 28 | AppStore|Mixed Platforms = AppStore|Mixed Platforms 29 | Debug|Any CPU = Debug|Any CPU 30 | Debug|iPhone = Debug|iPhone 31 | Debug|iPhoneSimulator = Debug|iPhoneSimulator 32 | Debug|Mixed Platforms = Debug|Mixed Platforms 33 | Release|Any CPU = Release|Any CPU 34 | Release|iPhone = Release|iPhone 35 | Release|iPhoneSimulator = Release|iPhoneSimulator 36 | Release|Mixed Platforms = Release|Mixed Platforms 37 | EndGlobalSection 38 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 39 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU 40 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU 41 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU 42 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU 43 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU 44 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU 45 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.AppStore|Any CPU.ActiveCfg = Release|Any CPU 46 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.AppStore|Any CPU.Build.0 = Release|Any CPU 47 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.AppStore|iPhone.ActiveCfg = Release|Any CPU 48 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU 49 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU 50 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU 51 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 52 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Debug|Any CPU.Build.0 = Debug|Any CPU 53 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Debug|iPhone.ActiveCfg = Debug|Any CPU 54 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 55 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 56 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 57 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Release|Any CPU.ActiveCfg = Release|Any CPU 58 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Release|Any CPU.Build.0 = Release|Any CPU 59 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Release|iPhone.ActiveCfg = Release|Any CPU 60 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 61 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 62 | {32EA56C9-D3C7-47F6-AB9F-FD41CC0045C7}.Release|Mixed Platforms.Build.0 = Release|Any CPU 63 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU 64 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU 65 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU 66 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU 67 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU 68 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU 69 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.AppStore|Any CPU.ActiveCfg = Release|Any CPU 70 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.AppStore|Any CPU.Build.0 = Release|Any CPU 71 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.AppStore|iPhone.ActiveCfg = Release|Any CPU 72 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU 73 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU 74 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU 75 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 76 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Debug|Any CPU.Build.0 = Debug|Any CPU 77 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Debug|iPhone.ActiveCfg = Debug|Any CPU 78 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 79 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 80 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 81 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Release|Any CPU.ActiveCfg = Release|Any CPU 82 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Release|Any CPU.Build.0 = Release|Any CPU 83 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Release|iPhone.ActiveCfg = Release|Any CPU 84 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 85 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 86 | {7BEF7EAA-DE37-40FB-BD33-3DEF0685031F}.Release|Mixed Platforms.Build.0 = Release|Any CPU 87 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU 88 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU 89 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU 90 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU 91 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU 92 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU 93 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.AppStore|Any CPU.ActiveCfg = Release|Any CPU 94 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.AppStore|Any CPU.Build.0 = Release|Any CPU 95 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.AppStore|iPhone.ActiveCfg = Release|Any CPU 96 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU 97 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU 98 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU 99 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 100 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Debug|Any CPU.Build.0 = Debug|Any CPU 101 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Debug|iPhone.ActiveCfg = Debug|Any CPU 102 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU 103 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 104 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 105 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Release|Any CPU.ActiveCfg = Release|Any CPU 106 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Release|Any CPU.Build.0 = Release|Any CPU 107 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Release|iPhone.ActiveCfg = Release|Any CPU 108 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU 109 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 110 | {687D854F-DB1B-4FF4-8EFD-91483341A150}.Release|Mixed Platforms.Build.0 = Release|Any CPU 111 | EndGlobalSection 112 | GlobalSection(SolutionProperties) = preSolution 113 | HideSolutionNode = FALSE 114 | EndGlobalSection 115 | EndGlobal 116 | -------------------------------------------------------------------------------- /JsonDataContextDriver/JsonDynamicDataContextDriver.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.CodeDom.Compiler; 3 | using System.Collections.Generic; 4 | using System.IO; 5 | using System.Linq; 6 | using System.Reflection; 7 | using System.Text; 8 | using System.Web; 9 | using System.Windows.Input; 10 | using JsonDataContext; 11 | using JsonDataContextDriver.Notepad; 12 | using LINQPad.Extensibility.DataContext; 13 | using Microsoft.CSharp; 14 | using Newtonsoft.Json; 15 | using Newtonsoft.Json.Linq; 16 | using Xamasoft.JsonClassGenerator; 17 | using MessageBox = System.Windows.MessageBox; 18 | 19 | namespace JsonDataContextDriver 20 | { 21 | public class JsonDynamicDataContextDriver : DynamicDataContextDriver 22 | { 23 | public override string Name 24 | { 25 | get { return "JSON DataContext Provider"; } 26 | } 27 | 28 | public override string Author 29 | { 30 | get { return "Ryan Davis"; } 31 | } 32 | 33 | public override string GetConnectionDescription(IConnectionInfo cxInfo) 34 | { 35 | return String.IsNullOrWhiteSpace(cxInfo.DisplayName) ? "Unnamed JSON Data Context" : cxInfo.DisplayName; 36 | } 37 | 38 | public override bool ShowConnectionDialog(IConnectionInfo cxInfo, bool isNewConnection) 39 | { 40 | var dialog = new ConnectionDialog(); 41 | dialog.SetContext(cxInfo, isNewConnection); 42 | 43 | var result = dialog.ShowDialog(); 44 | return result == true; 45 | } 46 | 47 | public override IEnumerable GetAssembliesToAdd(IConnectionInfo cxInfo) 48 | { 49 | return base.GetAssembliesToAdd(cxInfo) 50 | .Concat(new[] {typeof (JsonDataContextBase).Assembly.Location, typeof(HttpUtility).Assembly.Location}); 51 | } 52 | 53 | public override IEnumerable GetNamespacesToAdd(IConnectionInfo cxInfo) 54 | { 55 | return base.GetNamespacesToAdd(cxInfo) 56 | .Concat(_nameSpacesToAdd) 57 | .Distinct(); 58 | } 59 | 60 | private List _nameSpacesToAdd = new List(); 61 | 62 | 63 | public override List GetSchemaAndBuildAssembly(IConnectionInfo cxInfo, 64 | AssemblyName assemblyToBuild, ref string nameSpace, 65 | ref string typeName) 66 | { 67 | _nameSpacesToAdd = new List(); 68 | 69 | var xInputs = cxInfo.DriverData.Element("inputDefs"); 70 | if (xInputs == null) 71 | return new List(); 72 | 73 | var jss = new JsonSerializerSettings {TypeNameHandling = TypeNameHandling.All}; 74 | var inputDefs = JsonConvert.DeserializeObject>(xInputs.Value, jss).ToList(); 75 | 76 | var ns = nameSpace; 77 | 78 | // generate class definitions 79 | var classDefinitions = 80 | inputDefs 81 | .AsParallel() 82 | .SelectMany(i => 83 | { 84 | i.GenerateClasses(ns); 85 | return i.GeneratedClasses; 86 | }) 87 | .ToList(); 88 | 89 | // add namespaces 90 | _nameSpacesToAdd.AddRange(inputDefs.SelectMany(i=>i.NamespacesToAdd)); 91 | _nameSpacesToAdd.AddRange(classDefinitions.Select(c=> c.Namespace)); 92 | 93 | // remove the error'd inputs 94 | var classGenErrors = inputDefs.SelectMany(i => i.Errors).ToList(); 95 | 96 | classDefinitions = 97 | classDefinitions 98 | .Where(c => c.Success) 99 | .ToList(); 100 | 101 | // resolve duplicates 102 | classDefinitions 103 | .GroupBy(c => c.ClassName) 104 | .Where(c => c.Count() > 1) 105 | .SelectMany(cs => cs.Select((c, i) => new {Class = c, Index = i + 1}).Skip(1)) 106 | .ToList() 107 | .ForEach(c => c.Class.ClassName += "_" + c.Index); 108 | 109 | // create code to compile 110 | var usings = "using System;\r\n" + 111 | "using System.Collections.Generic;\r\n" + 112 | "using System.IO;\r\n" + 113 | "using Newtonsoft.Json;\r\n" + 114 | "using System.Web;\r\n" + 115 | "using JsonDataContext;\r\n"; 116 | 117 | usings += String.Join("\r\n", classDefinitions.Select(c => String.Format("using {0};", c.Namespace))); 118 | 119 | var contextProperties = 120 | inputDefs.SelectMany(i => i.ContextProperties); 121 | 122 | var context = 123 | String.Format("namespace {1} {{\r\n\r\n public class {2} : JsonDataContextBase {{\r\n\r\n\t\t{0}\r\n\r\n}}\r\n\r\n}}", 124 | String.Join("\r\n\r\n\t\t", contextProperties), nameSpace, typeName); 125 | var code = String.Join("\r\n", classDefinitions.Select(c => c.ClassDefinition)); 126 | 127 | var contextWithCode = String.Join("\r\n\r\n", usings, context, code); 128 | 129 | var provider = new CSharpCodeProvider(); 130 | var parameters = new CompilerParameters 131 | { 132 | IncludeDebugInformation = true, 133 | OutputAssembly = assemblyToBuild.CodeBase, 134 | ReferencedAssemblies = 135 | { 136 | typeof (JsonDataContextBase).Assembly.Location, 137 | typeof (JsonConvert).Assembly.Location, 138 | 139 | typeof (UriBuilder).Assembly.Location, 140 | typeof (HttpUtility).Assembly.Location 141 | } 142 | }; 143 | 144 | var result = provider.CompileAssemblyFromSource(parameters, contextWithCode); 145 | 146 | if (!result.Errors.HasErrors) 147 | { 148 | // Pray to the gods of UX for redemption.. 149 | // We Can Do Better 150 | if (classGenErrors.Any()) 151 | MessageBox.Show(String.Format("Couldn't process {0} inputs:\r\n{1}", classGenErrors.Count, 152 | String.Join(Environment.NewLine, classGenErrors))); 153 | 154 | return 155 | LinqPadSampleCode.GetSchema(result.CompiledAssembly.GetType(String.Format("{0}.{1}", nameSpace, typeName))) 156 | .Concat(inputDefs.SelectMany(i=>i.ExplorerItems??new List())) 157 | .ToList(); 158 | } 159 | else 160 | { 161 | // compile failed, this is Bad 162 | var sb = new StringBuilder(); 163 | sb.AppendLine("Could not generate a typed context for the given inputs. The compiler returned the following errors:\r\n"); 164 | 165 | foreach (var err in result.Errors) 166 | sb.AppendFormat(" - {0}\r\n", err); 167 | 168 | if (classGenErrors.Any()) 169 | { 170 | sb.AppendLine("\r\nThis may have been caused by the following class generation errors:\r\n"); 171 | sb.AppendLine(String.Join(Environment.NewLine, String.Join(Environment.NewLine, classGenErrors))); 172 | } 173 | 174 | MessageBox.Show(sb.ToString()); 175 | 176 | NotepadHelper.ShowMessage(contextWithCode, "Generated source code"); 177 | 178 | throw new Exception("Could not generate a typed context for the given inputs"); 179 | } 180 | } 181 | 182 | public override void InitializeContext(IConnectionInfo cxInfo, object context, QueryExecutionManager executionManager) 183 | { 184 | 185 | base.InitializeContext(cxInfo, context, executionManager); 186 | 187 | var ctx = (JsonDataContextBase) context; 188 | 189 | var xInputs = cxInfo.DriverData.Element("inputDefs"); 190 | if (xInputs == null) 191 | return; 192 | 193 | var jss = new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.All }; 194 | var inputs = JsonConvert.DeserializeObject>(xInputs.Value, jss).ToList(); 195 | 196 | inputs 197 | .OfType() 198 | .ToList() 199 | .ForEach(c=> ctx._jsonTextInputs.Add(c.InputGuid, c.Json)); 200 | } 201 | } 202 | } -------------------------------------------------------------------------------- /JsonDataContextDriver/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | 9 | [assembly: AssemblyTitle("JsonDynamicDataContextDriver")] 10 | [assembly: AssemblyDescription("")] 11 | [assembly: AssemblyConfiguration("")] 12 | [assembly: AssemblyCompany("")] 13 | [assembly: AssemblyProduct("JsonDynamicDataContextDriver")] 14 | [assembly: AssemblyCopyright("Copyright © 2015")] 15 | [assembly: AssemblyTrademark("")] 16 | [assembly: AssemblyCulture("")] 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | 22 | [assembly: ComVisible(false)] 23 | 24 | // The following GUID is for the ID of the typelib if this project is exposed to COM 25 | 26 | [assembly: Guid("c470c330-a9d7-4329-b559-42cecdff6676")] 27 | 28 | // Version information for an assembly consists of the following four values: 29 | // 30 | // Major Version 31 | // Minor Version 32 | // Build Number 33 | // Revision 34 | // 35 | // You can specify all the values or you can default the Build and Revision Numbers 36 | // by using the '*' as shown below: 37 | // [assembly: AssemblyVersion("1.0.*")] 38 | 39 | [assembly: AssemblyVersion("0.0.4")] 40 | [assembly: AssemblyFileVersion("0.0.4")] -------------------------------------------------------------------------------- /JsonDataContextDriver/Views/AddNewFileSourceDialog.xaml: -------------------------------------------------------------------------------- 1 |  9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 |