azure-sdk-for-net icon indicating copy to clipboard operation
azure-sdk-for-net copied to clipboard

ArmDeploymentPropertiesExtended.Outputs does not return valid JSON

Open tdwright opened this issue 3 years ago • 3 comments
trafficstars

I'm trying to collect the outputs from an ARM template using the Outputs property of ArmDeploymentPropertiesExtended.

For example:

var depop = rg.GetArmDeployments().CreateOrUpdate(Azure.WaitUntil.Completed, "MyDeployment", deploymentContent);
var outputs = depop.Value.Data.Properties.Outputs;
var credentials = outputs.ToObjectFromJson<DeploymentCredentials>();

Where the outputs section of my ARM template contains something like this:

"outputs": {
    "username": {
      "value": "[list(resourceId('Microsoft.Web/sites/config', variables('function_app_name'), 'publishingcredentials'), '2016-08-01').properties.publishingUserName]",
      "type": "string"
    },
    "password": {
      "value": "[list(resourceId('Microsoft.Web/sites/config', variables('function_app_name'), 'publishingcredentials'), '2016-08-01').properties.publishingPassword]",
      "type": "string"
    }
  }

If I inspect the BinaryData object returned, it appears to contain a username and password that match what I can see in the Azure portal. A promising start. Unfortunately, on closer inspection, the BinaryData contents is not quite valid JSON:

{
	{
        "username": {
            "type": "String",
            "value": "$someValueHere"
        },
        "password": {
            "type": "String",
            "value": "AsIfImGoingToShareThaat_DeadBeef_0123456789"
        }
    }
}

This is almost valid JSON, except for the extra pair of curly braces. This can be checked at (for instance) jsonlint.com, which complains with the following message:

Error: Parse error on line 1:
{	{		"username": {		
--^
Expecting 'STRING', '}', got '{'

Unfortunately, this is enough to break the JSON deserialiser, so that when we call outputs.ToObjectFromJson<DeploymentCredentials>() we get an empty instance of our class, without the values from the response.

tdwright avatar Aug 08 '22 12:08 tdwright

Label prediction was below confidence level 0.6 for Model:ServiceLabels: 'Azure.Identity:0.19045697,Tables:0.06827297,ARM:0.065124005'

azure-sdk avatar Aug 08 '22 12:08 azure-sdk

To add - I'm aware I can work around this by trimming the leading and trailing braces before manually deserialising.

I'm adding this issue because I think the experience could be improved.

tdwright avatar Aug 08 '22 12:08 tdwright

Thank you for your feedback. Tagging and routing to the team member best able to assist.

jsquire avatar Aug 08 '22 12:08 jsquire

Hi @tdwright, I tested this method and it worked as expected. One possible reason that you can't deserialize the outputs might be that ToObjectFromJson method has a default JsonSerializerOptions which set the PropertyNameCaseInsensitive to false. So could you double check if the properties' name in DeploymentCredentials could match the response in case sensitive or you can try this way to see if the deserialization can work:

JsonSerializerOptions options = new JsonSerializerOptions
{
    PropertyNameCaseInsensitive = true
};
Sample sample= deployment.Data.Properties.Outputs.ToObjectFromJson<Sample>(options );

Yao725 avatar Aug 12 '22 06:08 Yao725

Hi @Yao725. Thanks for taking a look. Case sensitivity is a good guess, but I think I can rule it out. I'm using JsonProperty attributes that match the casing of the raw JSON names. Since I can get it to work (see below) without further tweaks to the JsonSerializerOptions, I think we can rule this out.

I'm pretty sure the problem is that the returned JSON string contains a JSON object nested within another JSON object, without being in an array or having a key. This is not valid per the JSON specification (friendly | RFC) and causes errors in every validator I've tried. I actually first noticed this when trying to (lazily) generate the classes with quicktype.

As I said in my 2nd comment above, removing the outer pair of braces makes the JSON valid and allows it to be deserialised. For anyone else who stumbles across this problem, here's the code I used to fix it:

private static DeploymentCredentials ExtractCredentialsFromDeployment(ArmOperation<ArmDeploymentResource> depop)
{
	var outputs = depop.Value.Data.Properties.Outputs.ToString().Trim();

	var regex = new Regex(@"\{(.+)\}");
	var regexMatches = regex.Matches(outputs);
	var output_contents = regexMatches[0].Value;

	var credentials = JsonConvert.DeserializeObject<DeploymentCredentials>(output_contents);
	return credentials;
}

tdwright avatar Aug 12 '22 08:08 tdwright

Hi @tdwright Thank you for using Azure SDK for .NET. We can't repro you issue on our side, you could try the latest version see if the issue is gone. We tried with the the sample template with following code, both convert works as expected:

    var deployment = resourceGroup.GetArmDeployments().CreateOrUpdate(Azure.WaitUntil.Completed, "deploy4549", deploymentContent);
    var outputs = deployment.Value.Data.Properties.Outputs;
    var test1 = outputs.ToObjectFromJson<TestClass>();
    var middleClass = outputs.ToObjectFromJson<JsonDocument>();
    var test2 = middleClass.RootElement.Deserialize<TestClass>();

    public class TestClass
    {
        public Object? storageEndpoint { get; set; }
    }

HarveyLink avatar Mar 13 '24 08:03 HarveyLink

Hi @tdwright. Thank you for opening this issue and giving us the opportunity to assist. To help our team better understand your issue and the details of your scenario please provide a response to the question asked above or the information requested above. This will help us more accurately address your issue.

github-actions[bot] avatar Mar 13 '24 08:03 github-actions[bot]

@HarveyLink This issue is 18 months old. I don't work on Azure any more, so won't be able to try to repro the issue, nor validate that it's fixed. Sorry.

tdwright avatar Mar 18 '24 22:03 tdwright

@HarveyLink This issue is 18 months old. I don't work on Azure any more, so won't be able to try to repro the issue, nor validate that it's fixed. Sorry.

Thank you for the reply, closed this issue for now. If any have the same problem, feel free to open another one.

HarveyLink avatar Mar 20 '24 07:03 HarveyLink