1

I run post to get API Management subscription data but can't parse the returned json and can't find what further filtering on the returned string is required.

Postman shows json just fine. Other APIM REST requests parse json just fine.

Can someone please shed some light?

string url = $"https://management.azure.com/subscriptions/XXX/resourceGroups/YYY/providers/Microsoft.ApiManagement/service/ZZZ/subscriptions?api-version=2019-12-01&$filter=(contains(name, '{myname}'))";

        string json = null;
        using (HttpClient client = new HttpClient())
        {
            client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", bearerToken);
            using (HttpResponseMessage response2 = client.GetAsync(url).Result)
            {
                using (HttpContent content = response2.Content)
                {
                    json = content.ReadAsStringAsync().Result;

                    //JObject s = JObject.Parse(json);//didn't work
                    //Console.WriteLine((string)s["name"]);//didn't work
                    //var user = JsonConvert.DeserializeObject<UserAPIMSubscriptionMetaData>(json);//didn't work
                    //var user3 = JsonConvert.DeserializeObject(json);//didn't work

                    var json2 = json.Replace("\r\n", "");
                    json2 = json2.Replace(" ", "");// first replace didn't work so tried adding this one too but didn't work either
                    //var a = JObject.Parse(json2);//tried this too but didn't work
                    var user = JsonConvert.DeserializeObject<UserAPIMSubscriptionMetaData>(json2);
                }
            }
        }


internal class properties
{
    [JsonProperty("ownerId")]
    public string ownerId { get; set; }
    [JsonProperty("scope")]
    public string scope { get; set; }
    [JsonProperty("displayName")]
    public string displayName { get; set; }
    [JsonProperty("state")]
    public string state { get; set; }
    [JsonProperty("createdDate")]
    public string createdDate { get; set; }
    [JsonProperty("startDate")]
    public string startDate { get; set; }
    [JsonProperty("expirationDate")]
    public string expirationDate { get; set; }
    [JsonProperty("endDate")]
    public string endDate { get; set; }
    [JsonProperty("notificationDate")]
    public string notificationDate { get; set; }
    [JsonProperty("stateComment")]
    public string stateComment { get; set; }
    [JsonProperty("allowTracing")]
    public string allowTracing { get; set; }
}
internal class UserAPIMSubscriptionMetaData
{
    [JsonProperty("id")]
    public string id { get; set; }
    [JsonProperty("type")]
    public string thisType { get; set; }
    [JsonProperty("name")]
    public string name { get; set; }
    [JsonProperty("properties")]
    public properties properties { get; set; }
}

Initial Result value from ReadAsStringAsync():

"{\r\n  \"value\": [\r\n    {\r\n      \"id\": \"/subscriptions/XXXXX/resourceGroups/ZZZZ/providers/Microsoft.ApiManagement/service/YYYYY/subscriptions/sergiosolorzanoSubscription\",\r\n      \"type\": \"Microsoft.ApiManagement/service/subscriptions\",\r\n      \"name\": \"sergiosolorzanoSubscription\",\r\n      \"properties\": {\r\n        \"ownerId\": \"/subscriptions/XXXX/resourceGroups/YYYY/providers/Microsoft.ApiManagement/service/ZZZ/users/sergiosolorzanogmailcom\",\r\n        \"scope\": \"/subscriptions/XXXX/resourceGroups/JJJJJ/providers/Microsoft.ApiManagement/service/ZZZZ/apis\",\r\n        \"displayName\": \"sergiosolorzanoSubscription\",\r\n        \"state\": \"active\",\r\n        \"createdDate\": \"2020-04-23T08:04:31.737Z\",\r\n        \"startDate\": null,\r\n        \"expirationDate\": null,\r\n        \"endDate\": null,\r\n        \"notificationDate\": null,\r\n        \"stateComment\": null,\r\n        \"allowTracing\": true\r\n      }\r\n    }\r\n  ],\r\n  \"count\": 1\r\n}"
Sergio Solorzano
  • 476
  • 9
  • 29

1 Answers1

1

I don't know the exact error you are getting but I suspect the issue is that you're not deserializing it correctly.

If you look at your JSON, the objects you're trying to parse are in value which is a Json Array. What you're trying to do at the moment is parse that array into the object that the array contains.

What you need to do is either make a 3rd object as a "Container" for the other objects

public class Container
{
    [JsonProperty("value")]
    public IEnumerable<UserAPIMSubscriptionMetaData> Metadata {get; set;}

    [JsonProperty("count")]
    public int Count {get; set;}
}

or you can parse the Json into a JObject and token to value so your JSON becomes just an array of your Metadata object which you can then deserialize into a collection of your object.

var jobj = JObject.Parse(json);
var newjson = jobj["value"].ToString();
var myobj = JsonConvert.DeserializeObject<IEnumerable<UserAPIMSubscriptionMetaData>>(newjson);

Notes:

I used IEnumerable<> just as an example, you can use whatever type of collection you want. Array, List, etc.

Additionally, you should use proper Async/Await pattern instead of .Result as .Result can cause blocking. See the answer by Jon Skeet on this question for info on .Result vs await.

li223
  • 369
  • 3
  • 11
  • thank you @li223 , so it's a collection ! but looping over myobj you create above with foreach (var a in myobj) Console.Write(a.name); a.name returns error a.name error CS0103: The name 'a' does not exist in the current context? And then creating the container var obj2 = JsonConvert.DeserializeObject(newjson); throws: Cannot deserialize the current JSON array (e.g. [1,2,3]) into type 'ARTFunctions.MyContainer' because the type requires a JSON object (e.g. {"name":"value"}) to deserialize correctly. To fix this error either change the JSON to a JSON object (e.g. {"name":"value"}) – Sergio Solorzano Apr 25 '20 at 15:54
  • so i changed your Container property to "name" instead of "Count" but same error remains. Note: I also amended as suggested to json = await content.ReadAsStringAsync(); , thank you! – Sergio Solorzano Apr 25 '20 at 15:54
  • 1
    As for the property names. That's to help serialize the JSON correctly. If you look at the JSON you'll see the root has `value` and `count` properties. `value` being the collection of your metadata object and `count` the number of objects in `value` – li223 Apr 25 '20 at 16:06
  • 1
    I messed a comment up so I'm reposting it: The error with `a` is likely because you're trying to call `a` outside of the scope of the foreach loop. I'd have to see the code to be sure. As for your JSON error it's because you are probably trying to parse `value` as `MyContainer` instead of `IEnumerable`. Parse into MyContainer if you're parsing the raw response. Parse into a collection of your metadata object if you're just trying to parse `value` instead of the entire JSON – li223 Apr 25 '20 at 16:10
  • Yes it looks like "a" is out of scope, but I don't understand why because we deserialize the collection (myobj count =1) so foreach would loop over the collection?: using your 3 lines of code above: var myobj = JsonConvert.DeserializeObject>(newjson); foreach (var a in myobj) { Console.Write(a.name);} – Sergio Solorzano Apr 25 '20 at 16:11
  • Got'cha. var conta = JsonConvert.DeserializeObject(json); Then looped over conta.value so foreach (var item in conta.value) Console.Write(z.name); and all properties show :) thanks a bunch – Sergio Solorzano Apr 25 '20 at 16:23
  • 1
    Ah yeah. Sorry I wasn't more clear about that. You need to iterate over `Container.Value` like you have done. – li223 Apr 25 '20 at 16:24