Skip to content

Commit 832979d

Browse files
[Resources] Use JsonExtensions to serialize and deserialize template and parameter objects (#15552)
* preserve datetime string value * Update serialization and deserialization code to use JsonExtensions * Added unit test * retrieved output from outputs hashtable * Updated parameter file parsing and added new test * Update changelog * remove unneeded file * Fixed unit test * Remove comment * update changelog to avoid merge issue * nit text update Co-authored-by: Yeming Liu <[email protected]>
1 parent 19406c8 commit 832979d

File tree

12 files changed

+1955
-9
lines changed

12 files changed

+1955
-9
lines changed

src/Resources/ResourceManager/Json/PSJsonSerializer.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ public static string Serialize(object value, SerializeContext context)
5252
{
5353
object processed = ProcessValue(value, 0, context);
5454

55-
return JsonConvert.SerializeObject(processed);
55+
// NOTE(jcotillo): JsonExtensions.ToJson() extension uses a custom serialization settings
56+
// that preserves DateTime values as string (DateParseHandling = DateParseHandling.None),
57+
// plus other custom settings.
58+
return processed.ToJson();
5659
}
5760
catch (OperationCanceledException)
5861
{

src/Resources/ResourceManager/SdkClient/ResourceManagerSdkClient.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -453,11 +453,16 @@ private Deployment CreateBasicDeployment(PSDeploymentCmdletParameters parameters
453453
{
454454
if (!string.IsNullOrEmpty(parameters.TemplateFile))
455455
{
456-
deployment.Properties.Template = JObject.Parse(FileUtilities.DataStore.ReadFileAsText(parameters.TemplateFile));
456+
// NOTE(jcotillo): JsonExtensions.FromJson<> extension uses a custom serialization settings
457+
// that preserves DateTime values as string (DateParseHandling = DateParseHandling.None),
458+
// plus other custom settings (see: JsonExtensions.JsonObjectTypeSerializer)
459+
deployment.Properties.Template =
460+
FileUtilities.DataStore.ReadFileAsStream(parameters.TemplateFile).FromJson<JObject>();
457461
}
458462
else
459463
{
460-
deployment.Properties.Template = JObject.Parse(PSJsonSerializer.Serialize(parameters.TemplateObject));
464+
deployment.Properties.Template =
465+
PSJsonSerializer.Serialize(parameters.TemplateObject).FromJson<JObject>();
461466
}
462467
}
463468

@@ -475,8 +480,9 @@ private Deployment CreateBasicDeployment(PSDeploymentCmdletParameters parameters
475480
string parametersContent = parametersDictionary != null
476481
? PSJsonSerializer.Serialize(parametersDictionary)
477482
: null;
483+
// NOTE(jcotillo): Adding FromJson<> to parameters as well
478484
deployment.Properties.Parameters = !string.IsNullOrEmpty(parametersContent)
479-
? JObject.Parse(parametersContent)
485+
? parametersContent.FromJson<JObject>()
480486
: null;
481487
}
482488

src/Resources/ResourceManager/Utilities/TemplateUtility.cs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
using System.Security;
2727
using Microsoft.WindowsAzure.Commands.Common;
2828
using Microsoft.Azure.Commands.Common.Authentication.Abstractions;
29+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2930

3031
namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.Utilities
3132
{
@@ -88,12 +89,18 @@ public static Dictionary<string, TemplateFileParameterV1> ParseTemplateParameter
8889
{
8990
try
9091
{
91-
parameters = JsonConvert.DeserializeObject<Dictionary<string, TemplateFileParameterV1>>(FileUtilities.DataStore.ReadFileAsText(templateParameterFilePath));
92+
// NOTE(jcotillo): We must use JsonExtensions to ensure the proper use of serialization settings.
93+
// otherwise we could get invalid date time serializations.
94+
parameters =
95+
FileUtilities.DataStore.ReadFileAsStream(templateParameterFilePath)
96+
.FromJson<Dictionary<string, TemplateFileParameterV1>>();
9297
}
9398
catch (JsonSerializationException)
9499
{
95-
parameters = new Dictionary<string, TemplateFileParameterV1>(
96-
JsonConvert.DeserializeObject<TemplateFileParameterV2>(FileUtilities.DataStore.ReadFileAsText(templateParameterFilePath)).Parameters);
100+
var parametersv2 =
101+
FileUtilities.DataStore.ReadFileAsStream(templateParameterFilePath)
102+
.FromJson<TemplateFileParameterV2>();
103+
parameters = new Dictionary<string, TemplateFileParameterV1>(parametersv2.Parameters);
97104
}
98105
}
99106

src/Resources/Resources.Test/Json/PSJsonSerializerTests.cs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ namespace Microsoft.Azure.Commands.Resources.Test.Json
1818
using System.Collections;
1919
using System.Collections.Generic;
2020
using System.Management.Automation;
21+
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Extensions;
2122
using Microsoft.Azure.Commands.ResourceManager.Cmdlets.Json;
2223
using Microsoft.WindowsAzure.Commands.ScenarioTest;
2324
using Newtonsoft.Json.Linq;
@@ -90,11 +91,15 @@ public void Serialize_Hashtable_Success()
9091

9192
string result = PSJsonSerializer.Serialize(hashtable);
9293

93-
JToken parsedResult = JToken.Parse(result);
94+
JToken parsedResult = result.FromJson<JToken>();
95+
96+
// NOTE(jcotillo): JsonExtensions is now camelCasing all property keys
97+
// therefore even though Bar was set as PascalCase, after serializing it
98+
// the key became camelCase.
9499
JToken expected = JToken.FromObject(new
95100
{
96101
foo = "fooValue",
97-
Bar = true,
102+
bar = true,
98103
nested = new
99104
{
100105
foo = "4d44fe86-f04a-4ba5-9900-abdec8cb11c1",

src/Resources/Resources.Test/Resources.Test.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
</ItemGroup>
2222

2323
<ItemGroup>
24+
<ProjectReference Include="..\ResourceManager\ResourceManager.csproj" />
2425
<ProjectReference Include="..\Resources\Resources.csproj" />
2526
</ItemGroup>
2627

src/Resources/Resources.Test/ScenarioTests/DeploymentTests.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,5 +202,19 @@ public void TestWhatIfWithQueryString()
202202
{
203203
TestRunner.RunTestScript("Test-WhatIfWithQueryString");
204204
}
205+
206+
[Fact]
207+
[Trait(Category.AcceptanceType, Category.CheckIn)]
208+
public void TestNewDeploymentFromTemplateFileContainingDatetimeOutput()
209+
{
210+
TestRunner.RunTestScript("Test-NewDeploymentFromTemplateFileContainingDatetimeOutput");
211+
}
212+
213+
[Fact]
214+
[Trait(Category.AcceptanceType, Category.CheckIn)]
215+
public void TestNewDeploymentFromTemplateAndParameterFileContainingDatetimeOutput()
216+
{
217+
TestRunner.RunTestScript("Test-NewDeploymentFromTemplateAndParameterFileContainingDatetimeOutput");
218+
}
205219
}
206220
}

src/Resources/Resources.Test/ScenarioTests/DeploymentTests.ps1

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -923,4 +923,90 @@ function Test-WhatIfWithQueryString
923923
Clean-ResourceGroup $rgname
924924
}
925925
}
926+
}
927+
928+
<#
929+
.SYNOPSIS
930+
Tests deployment via template file containing a single datetime string output.
931+
#>
932+
function Test-NewDeploymentFromTemplateFileContainingDatetimeOutput
933+
{
934+
# Setup
935+
$rgname = Get-ResourceGroupName
936+
$rname = Get-ResourceName
937+
$rglocation = "West US 2"
938+
939+
try
940+
{
941+
# Test
942+
New-AzResourceGroup -Name $rgname -Location $rglocation
943+
944+
$datetime = "2021-07-08T22:56:00"
945+
$datetimeFormatted = $datetime | Get-Date
946+
$parameters = @{ "date"= $datetime }
947+
948+
$deployment = New-AzResourceGroupDeployment -Name $rname -ResourceGroupName $rgname -TemplateFile simpleTemplateWithDatetimeOutput.json -TemplateParameterObject $parameters
949+
950+
# Assert
951+
Assert-AreEqual Succeeded $deployment.ProvisioningState
952+
953+
$subId = (Get-AzContext).Subscription.SubscriptionId
954+
$deploymentId = "/subscriptions/$subId/resourcegroups/$rgname/providers/Microsoft.Resources/deployments/$rname"
955+
$getById = Get-AzResourceGroupDeployment -Id $deploymentId
956+
Assert-AreEqual $getById.DeploymentName $deployment.DeploymentName
957+
958+
$datetimeOutput = $getById.Outputs.date.Value | Get-Date
959+
960+
Assert-AreEqual $datetimeFormatted $datetimeOutput
961+
}
962+
963+
finally
964+
{
965+
# Cleanup
966+
Clean-ResourceGroup $rgname
967+
}
968+
}
969+
970+
<#
971+
.SYNOPSIS
972+
Tests deployment via template and parameter file containing a single datetime string output.
973+
#>
974+
function Test-NewDeploymentFromTemplateAndParameterFileContainingDatetimeOutput
975+
{
976+
# Setup
977+
$rgname = Get-ResourceGroupName
978+
$rname = Get-ResourceName
979+
$rglocation = "West US 2"
980+
981+
try
982+
{
983+
# Test
984+
New-AzResourceGroup -Name $rgname -Location $rglocation
985+
986+
# NOTE(jcotillo): This is the same value as the one from: simpleTemplateWithDatetimeOutputParameters.json
987+
# if the parameter file gets updated, please ensure to update this value as well otherwise test will fail.
988+
$datetime = "2021-07-08T22:56:00"
989+
$datetimeFormatted = $datetime | Get-Date
990+
$parameters = @{ "date"= $datetime }
991+
992+
$deployment = New-AzResourceGroupDeployment -Name $rname -ResourceGroupName $rgname -TemplateFile simpleTemplateWithDatetimeOutput.json -TemplateParameterFile simpleTemplateWithDatetimeOutputParameters.json
993+
994+
# Assert
995+
Assert-AreEqual Succeeded $deployment.ProvisioningState
996+
997+
$subId = (Get-AzContext).Subscription.SubscriptionId
998+
$deploymentId = "/subscriptions/$subId/resourcegroups/$rgname/providers/Microsoft.Resources/deployments/$rname"
999+
$getById = Get-AzResourceGroupDeployment -Id $deploymentId
1000+
Assert-AreEqual $getById.DeploymentName $deployment.DeploymentName
1001+
1002+
$datetimeOutput = $getById.Outputs.date.Value | Get-Date
1003+
1004+
Assert-AreEqual $datetimeFormatted $datetimeOutput
1005+
}
1006+
1007+
finally
1008+
{
1009+
# Cleanup
1010+
Clean-ResourceGroup $rgname
1011+
}
9261012
}

0 commit comments

Comments
 (0)