diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs
index a1141baaec9c3..4d5b00d6e6c33 100644
--- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs
+++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net461.cs
@@ -111,6 +111,8 @@ namespace Azure.Core.Dynamic
public static partial class BinaryDataExtensions
{
public static dynamic ToDynamic(this System.BinaryData data) { throw null; }
+ public static dynamic ToDynamic(this System.BinaryData data, Azure.Core.Dynamic.DynamicJsonNameMapping propertyNameCasing) { throw null; }
+ public static dynamic ToDynamic(this System.BinaryData data, Azure.Core.Dynamic.DynamicJsonOptions options) { throw null; }
}
public abstract partial class DynamicData
{
@@ -151,6 +153,20 @@ public void Reset() { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
}
+ public enum DynamicJsonNameMapping
+ {
+ None = 0,
+ PascalCaseGetters = 1,
+ PascalCaseGettersCamelCaseSetters = 2,
+ }
+ [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
+ public partial struct DynamicJsonOptions
+ {
+ private int _dummyPrimitive;
+ public static readonly Azure.Core.Dynamic.DynamicJsonOptions AzureDefault;
+ public DynamicJsonOptions() { throw null; }
+ public Azure.Core.Dynamic.DynamicJsonNameMapping PropertyNameCasing { get { throw null; } set { } }
+ }
}
namespace Azure.Core.Json
{
diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs
index a1141baaec9c3..4d5b00d6e6c33 100644
--- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs
+++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.net6.0.cs
@@ -111,6 +111,8 @@ namespace Azure.Core.Dynamic
public static partial class BinaryDataExtensions
{
public static dynamic ToDynamic(this System.BinaryData data) { throw null; }
+ public static dynamic ToDynamic(this System.BinaryData data, Azure.Core.Dynamic.DynamicJsonNameMapping propertyNameCasing) { throw null; }
+ public static dynamic ToDynamic(this System.BinaryData data, Azure.Core.Dynamic.DynamicJsonOptions options) { throw null; }
}
public abstract partial class DynamicData
{
@@ -151,6 +153,20 @@ public void Reset() { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
}
+ public enum DynamicJsonNameMapping
+ {
+ None = 0,
+ PascalCaseGetters = 1,
+ PascalCaseGettersCamelCaseSetters = 2,
+ }
+ [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
+ public partial struct DynamicJsonOptions
+ {
+ private int _dummyPrimitive;
+ public static readonly Azure.Core.Dynamic.DynamicJsonOptions AzureDefault;
+ public DynamicJsonOptions() { throw null; }
+ public Azure.Core.Dynamic.DynamicJsonNameMapping PropertyNameCasing { get { throw null; } set { } }
+ }
}
namespace Azure.Core.Json
{
diff --git a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs
index a1141baaec9c3..4d5b00d6e6c33 100644
--- a/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs
+++ b/sdk/core/Azure.Core.Experimental/api/Azure.Core.Experimental.netstandard2.0.cs
@@ -111,6 +111,8 @@ namespace Azure.Core.Dynamic
public static partial class BinaryDataExtensions
{
public static dynamic ToDynamic(this System.BinaryData data) { throw null; }
+ public static dynamic ToDynamic(this System.BinaryData data, Azure.Core.Dynamic.DynamicJsonNameMapping propertyNameCasing) { throw null; }
+ public static dynamic ToDynamic(this System.BinaryData data, Azure.Core.Dynamic.DynamicJsonOptions options) { throw null; }
}
public abstract partial class DynamicData
{
@@ -151,6 +153,20 @@ public void Reset() { }
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { throw null; }
}
}
+ public enum DynamicJsonNameMapping
+ {
+ None = 0,
+ PascalCaseGetters = 1,
+ PascalCaseGettersCamelCaseSetters = 2,
+ }
+ [System.Runtime.InteropServices.StructLayoutAttribute(System.Runtime.InteropServices.LayoutKind.Sequential)]
+ public partial struct DynamicJsonOptions
+ {
+ private int _dummyPrimitive;
+ public static readonly Azure.Core.Dynamic.DynamicJsonOptions AzureDefault;
+ public DynamicJsonOptions() { throw null; }
+ public Azure.Core.Dynamic.DynamicJsonNameMapping PropertyNameCasing { get { throw null; } set { } }
+ }
}
namespace Azure.Core.Json
{
diff --git a/sdk/core/Azure.Core.Experimental/src/BinaryDataExtensions.cs b/sdk/core/Azure.Core.Experimental/src/BinaryDataExtensions.cs
index 5cb815aecd7b6..78cf716765df9 100644
--- a/sdk/core/Azure.Core.Experimental/src/BinaryDataExtensions.cs
+++ b/sdk/core/Azure.Core.Experimental/src/BinaryDataExtensions.cs
@@ -16,7 +16,23 @@ public static class BinaryDataExtensions
///
public static dynamic ToDynamic(this BinaryData data)
{
- return new DynamicJson(MutableJsonDocument.Parse(data).RootElement);
+ return new DynamicJson(MutableJsonDocument.Parse(data).RootElement, new DynamicJsonOptions());
+ }
+
+ ///
+ /// Return the content of the BinaryData as a dynamic type.
+ ///
+ public static dynamic ToDynamic(this BinaryData data, DynamicJsonNameMapping propertyNameCasing)
+ {
+ return new DynamicJson(MutableJsonDocument.Parse(data).RootElement, new DynamicJsonOptions() { PropertyNameCasing = propertyNameCasing });
+ }
+
+ ///
+ /// Return the content of the BinaryData as a dynamic type.
+ ///
+ public static dynamic ToDynamic(this BinaryData data, DynamicJsonOptions options)
+ {
+ return new DynamicJson(MutableJsonDocument.Parse(data).RootElement, options);
}
}
}
diff --git a/sdk/core/Azure.Core.Experimental/src/DynamicJson.cs b/sdk/core/Azure.Core.Experimental/src/DynamicJson.cs
index fc547b908857f..11ec432fed4a7 100644
--- a/sdk/core/Azure.Core.Experimental/src/DynamicJson.cs
+++ b/sdk/core/Azure.Core.Experimental/src/DynamicJson.cs
@@ -24,10 +24,12 @@ public sealed partial class DynamicJson : DynamicData, IDisposable
private static readonly MethodInfo SetViaIndexerMethod = typeof(DynamicJson).GetMethod(nameof(SetViaIndexer), BindingFlags.NonPublic | BindingFlags.Instance)!;
private MutableJsonElement _element;
+ private DynamicJsonOptions _options;
- internal DynamicJson(MutableJsonElement element)
+ internal DynamicJson(MutableJsonElement element, DynamicJsonOptions options = default)
{
_element = element;
+ _options = options;
}
internal override void WriteTo(Stream stream)
@@ -39,14 +41,46 @@ internal override void WriteTo(Stream stream)
private object? GetProperty(string name)
{
+ Argument.AssertNotNullOrEmpty(name, nameof(name));
+
if (_element.TryGetProperty(name, out MutableJsonElement element))
{
return new DynamicJson(element);
}
+ if (PascalCaseGetters() && char.IsUpper(name[0]))
+ {
+ if (_element.TryGetProperty(GetAsCamelCase(name), out element))
+ {
+ return new DynamicJson(element);
+ }
+ }
+
return null;
}
+ private bool PascalCaseGetters()
+ {
+ return
+ _options.PropertyNameCasing == DynamicJsonNameMapping.PascalCaseGetters ||
+ _options.PropertyNameCasing == DynamicJsonNameMapping.PascalCaseGettersCamelCaseSetters;
+ }
+
+ private bool CamelCaseSetters()
+ {
+ return _options.PropertyNameCasing == DynamicJsonNameMapping.PascalCaseGettersCamelCaseSetters;
+ }
+
+ private static string GetAsCamelCase(string value)
+ {
+ if (value.Length < 2)
+ {
+ return value.ToLowerInvariant();
+ }
+
+ return $"{char.ToLowerInvariant(value[0])}{value.Substring(1)}";
+ }
+
private object? GetViaIndexer(object index)
{
switch (index)
@@ -67,6 +101,37 @@ private IEnumerable GetEnumerable()
private object? SetProperty(string name, object value)
{
+ Argument.AssertNotNullOrEmpty(name, nameof(name));
+
+ if (_options.PropertyNameCasing == DynamicJsonNameMapping.None)
+ {
+ _element = _element.SetProperty(name, value);
+ return null;
+ }
+
+ if (!char.IsUpper(name[0]))
+ {
+ // Lookup name is camelCase, so set unchanged.
+ _element = _element.SetProperty(name, value);
+ return null;
+ }
+
+ // Other mappings have PascalCase getters, and lookup name is PascalCase.
+ // So, if it exists in either form, we'll set it in that form.
+ if (_element.TryGetProperty(name, out MutableJsonElement element))
+ {
+ element.Set(value);
+ return null;
+ }
+
+ if (_element.TryGetProperty(GetAsCamelCase(name), out element))
+ {
+ element.Set(value);
+ return null;
+ }
+
+ // It's a new property, so set according to the mapping.
+ name = CamelCaseSetters() ? GetAsCamelCase(name) : name;
_element = _element.SetProperty(name, value);
// Binding machinery expects the call site signature to return an object
diff --git a/sdk/core/Azure.Core.Experimental/src/DynamicJsonNameMapping.cs b/sdk/core/Azure.Core.Experimental/src/DynamicJsonNameMapping.cs
new file mode 100644
index 0000000000000..71a0d290c454a
--- /dev/null
+++ b/sdk/core/Azure.Core.Experimental/src/DynamicJsonNameMapping.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Azure.Core.Dynamic
+{
+ ///
+ /// Options for setting new DynamicJson properties.
+ ///
+ public enum DynamicJsonNameMapping
+ {
+ ///
+ /// Properties are accessed and written in the JSON buffer with the same casing as the DynamicJson property.
+ ///
+ None = 0,
+
+ ///
+ /// A "PascalCase" DynamicJson property can be used to read and set "camelCase" properties that exist in the JSON buffer.
+ /// New properties are written to the JSON buffer with the same casing as the DynamicJson property.
+ ///
+ PascalCaseGetters = 1,
+
+ ///
+ /// Default settings for Azure services.
+ /// A "PascalCase" DynamicJson property can be used to read and set "camelCase" properties that exist in the JSON buffer.
+ /// New properties are written to the JSON buffer using "camelCase" property names.
+ ///
+ PascalCaseGettersCamelCaseSetters = 2
+ }
+}
diff --git a/sdk/core/Azure.Core.Experimental/src/DynamicJsonOptions.cs b/sdk/core/Azure.Core.Experimental/src/DynamicJsonOptions.cs
new file mode 100644
index 0000000000000..bfad8b64c0792
--- /dev/null
+++ b/sdk/core/Azure.Core.Experimental/src/DynamicJsonOptions.cs
@@ -0,0 +1,29 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+namespace Azure.Core.Dynamic
+{
+ ///
+ /// Provides the ability for the user to define custom behavior when accessing JSON through a dynamic layer.
+ ///
+ public struct DynamicJsonOptions
+ {
+ ///
+ /// Gets the default for Azure services.
+ ///
+ public static readonly DynamicJsonOptions AzureDefault = new()
+ {
+ PropertyNameCasing = DynamicJsonNameMapping.PascalCaseGettersCamelCaseSetters
+ };
+
+ ///
+ /// Creates a new instance of DynamicJsonOptions.
+ ///
+ public DynamicJsonOptions() { }
+
+ ///
+ /// Specifies how properties on will be accessed in the underlying JSON buffer.
+ ///
+ public DynamicJsonNameMapping PropertyNameCasing { get; set; }
+ }
+}
diff --git a/sdk/core/Azure.Core.Experimental/src/MutableJsonChange.cs b/sdk/core/Azure.Core.Experimental/src/MutableJsonChange.cs
index 88bfd050dee98..8d5b1a63238e8 100644
--- a/sdk/core/Azure.Core.Experimental/src/MutableJsonChange.cs
+++ b/sdk/core/Azure.Core.Experimental/src/MutableJsonChange.cs
@@ -2,7 +2,6 @@
// Licensed under the MIT License.
using System;
-using System.Text;
using System.Text.Json;
namespace Azure.Core.Json
diff --git a/sdk/core/Azure.Core.Experimental/tests/DynamicJsonTests.cs b/sdk/core/Azure.Core.Experimental/tests/DynamicJsonTests.cs
index f295dd3f57353..f4564bde2bf85 100644
--- a/sdk/core/Azure.Core.Experimental/tests/DynamicJsonTests.cs
+++ b/sdk/core/Azure.Core.Experimental/tests/DynamicJsonTests.cs
@@ -405,6 +405,289 @@ public void DisposingAChildDisposesTheParent()
Assert.Throws(() => { var foo = json.Foo; });
}
+ [Test]
+ public void CanGetCamelCasePropertyEitherCase()
+ {
+ string json = """{ "foo" : 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(DynamicJsonOptions.AzureDefault);
+
+ Assert.AreEqual(1, (int)dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanGetCamelCasePropertyNoMapping()
+ {
+ string json = """{ "foo" : 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic();
+
+ Assert.AreEqual(1, (int)dynamicJson.foo);
+ Assert.AreEqual(null, dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanGetCamelCasePropertyPascalGetters()
+ {
+ string json = """{ "foo" : 1 }""";
+
+ DynamicJsonOptions options = new()
+ {
+ PropertyNameCasing = DynamicJsonNameMapping.PascalCaseGetters
+ };
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(options);
+
+ Assert.AreEqual(1, (int)dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanGetCamelCasePropertyPascalGettersCamelSetters()
+ {
+ string json = """{ "foo" : 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(DynamicJsonOptions.AzureDefault);
+
+ Assert.AreEqual(1, (int)dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanGetPascalCasePropertyNoMapping()
+ {
+ string json = """{ "Foo" : 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic();
+
+ Assert.AreEqual(null, dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanGetPascalCasePropertyPascalGetters()
+ {
+ string json = """{ "Foo" : 1 }""";
+
+ DynamicJsonOptions options = new()
+ {
+ PropertyNameCasing = DynamicJsonNameMapping.PascalCaseGetters
+ };
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(options);
+
+ Assert.AreEqual(null, dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanGetPascalCasePropertyPascalGettersCamelSetters()
+ {
+ string json = """{ "Foo" : 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(DynamicJsonOptions.AzureDefault);
+
+ Assert.AreEqual(null, dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ }
+
+ [Test]
+ public void CanSetCamelCaseNoMapping()
+ {
+ string json = """{ "foo": 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic();
+
+ // Existing property access
+ dynamicJson.foo = 2;
+
+ // New property access
+ dynamicJson.bar = 3;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(null, dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(null, dynamicJson.Bar);
+
+ dynamicJson.Foo = 4;
+ dynamicJson.Bar = 5;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(4, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(5, (int)dynamicJson.Bar);
+ }
+
+ [Test]
+ public void CanSetCamelCasePascalGetters()
+ {
+ string json = """{ "foo": 1 }""";
+
+ DynamicJsonOptions options = new()
+ {
+ PropertyNameCasing = DynamicJsonNameMapping.PascalCaseGetters
+ };
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(options);
+
+ // Existing property access
+ dynamicJson.foo = 2;
+
+ // New property is created as camelCase
+ dynamicJson.bar = 3;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(2, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(3, (int)dynamicJson.Bar);
+
+ // PascalCase getters find camelCase properties and sets them.
+ dynamicJson.Foo = 4;
+ dynamicJson.Bar = 5;
+
+ // New property is created as PascalCase
+ dynamicJson.Baz = 6;
+
+ Assert.AreEqual(4, (int)dynamicJson.foo);
+ Assert.AreEqual(4, (int)dynamicJson.Foo);
+ Assert.AreEqual(5, (int)dynamicJson.bar);
+ Assert.AreEqual(5, (int)dynamicJson.Bar);
+ Assert.AreEqual(null, dynamicJson.baz);
+ Assert.AreEqual(6, (int)dynamicJson.Baz);
+ }
+
+ [Test]
+ public void CanSetCamelCasePascalGettersCamelSetters()
+ {
+ string json = """{ "foo": 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(DynamicJsonOptions.AzureDefault);
+
+ // Existing property access
+ dynamicJson.foo = 2;
+
+ // New property is created as camelCase
+ dynamicJson.bar = 3;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(2, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(3, (int)dynamicJson.Bar);
+
+ // PascalCase getters find camelCase properties and sets them.
+ dynamicJson.Foo = 4;
+ dynamicJson.Bar = 5;
+
+ // New property is created as camelCase
+ dynamicJson.Baz = 6;
+
+ Assert.AreEqual(4, (int)dynamicJson.foo);
+ Assert.AreEqual(4, (int)dynamicJson.Foo);
+ Assert.AreEqual(5, (int)dynamicJson.bar);
+ Assert.AreEqual(5, (int)dynamicJson.Bar);
+ Assert.AreEqual(6, (int)dynamicJson.baz);
+ Assert.AreEqual(6, (int)dynamicJson.Baz);
+ }
+
+ [Test]
+ public void CanSetPascalCaseNoMapping()
+ {
+ string json = """{ "Foo": 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic();
+
+ // This adds a new property, since it doesn't find `Foo`.
+ dynamicJson.foo = 2;
+
+ // New property access
+ dynamicJson.bar = 3;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(null, dynamicJson.Bar);
+
+ // This updates the PascalCase property and not the camelCase one.
+ dynamicJson.Foo = 4;
+
+ // This creates a new PascalCase property.
+ dynamicJson.Bar = 5;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(4, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(5, (int)dynamicJson.Bar);
+ }
+
+ [Test]
+ public void CanSetPascalCasePascalGetters()
+ {
+ string json = """{ "Foo": 1 }""";
+
+ DynamicJsonOptions options = new()
+ {
+ PropertyNameCasing = DynamicJsonNameMapping.PascalCaseGetters
+ };
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(options);
+
+ // This property doesn't exist, so it creates a new camelCase property.
+ dynamicJson.foo = 2;
+
+ // New property is created as camelCase
+ dynamicJson.bar = 3;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(1, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(3, (int)dynamicJson.Bar);
+
+ // This updates the PascalCase property and not the camelCase one.
+ dynamicJson.Foo = 4;
+
+ // The PascalCase getter finds `bar`, so it updates the camelCase property.
+ dynamicJson.Bar = 5;
+
+ // New property is created as PascalCase
+ dynamicJson.Baz = 6;
+
+ Assert.AreEqual(2, (int)dynamicJson.foo);
+ Assert.AreEqual(4, (int)dynamicJson.Foo);
+ Assert.AreEqual(5, (int)dynamicJson.bar);
+ Assert.AreEqual(5, (int)dynamicJson.Bar);
+ Assert.AreEqual(null, dynamicJson.baz);
+ Assert.AreEqual(6, (int)dynamicJson.Baz);
+ }
+
+ [Test]
+ public void CanSetPascalCasePascalGettersCamelSetters()
+ {
+ string json = """{ "Foo": 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(DynamicJsonOptions.AzureDefault);
+
+ // Existing property access does not add a camelCase property.
+ dynamicJson.Foo = 2;
+
+ // New property is created as camelCase
+ dynamicJson.Bar = 3;
+
+ Assert.AreEqual(null, dynamicJson.foo);
+ Assert.AreEqual(2, (int)dynamicJson.Foo);
+ Assert.AreEqual(3, (int)dynamicJson.bar);
+ Assert.AreEqual(3, (int)dynamicJson.Bar);
+ }
+
+ [Test]
+ public void CanPassPropertyNameCasingEnumDirectly()
+ {
+ string json = """{ "foo" : 1 }""";
+
+ dynamic dynamicJson = new BinaryData(json).ToDynamic(DynamicJsonNameMapping.None);
+
+ Assert.AreEqual(1, (int)dynamicJson.foo);
+ Assert.AreEqual(null, dynamicJson.Foo);
+ }
+
#region Helpers
internal static dynamic GetDynamicJson(string json)
{