Как принимать JSON независимо от имен узлов верхнего уровня - PullRequest
0 голосов
/ 07 ноября 2018

У меня есть функция без сервера Azure, которая служит для получения полезной нагрузки JSON и работы с содержащимися в ней записями. Функция прекрасно работает для выполнения того, что предназначено, за исключением того, что это не должно иметь значения для имени узла-оболочки. Например:

{
   "Wrapper": [{
        "Field1": "Apple",
        "Field2": "Peach",
        "Field3": "########5",
        "Field4": "Kiwi",
    }]
}

Должно быть обработано так же, как:

{
    "OtherWrapperName": [{
        "Column1": "Apple",
        "Something": "Peach",
        "SomethingElse": "Banana",
        "Field4": "Kiwi"
    }]
}

Сейчас, похоже, ожидается, что узел верхнего уровня будет называться "Wrapper". Вот моя попытка сделать это (какой-то код был отредактирован, поскольку он не нужен для этого примера):

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    string InputData = await req.Content.ReadAsStringAsync();
    var inputData = JsonConvert.DeserializeObject<ItemsPayload>(InputData);

    var propertiesLookup = new Dictionary<string, ItemUpdate>();
    var propertiesRequest = new PropertySearchRequest { Registry = new List<RequestPropertySearch>() };


    int recordCounter = 0;
    foreach (var item in inputData.Wrapper)
    {
        foreach (var kvp in item.Where(property => property.Value.StartsWith("@!!!@")))
        {
            propertiesLookup[recordCounter.ToString() + "|" + kvp.Value] = new ItemUpdate
            {
                Properties = item,
                UpdateKey = kvp.Key
            };
            propertiesRequest.Registry.Add(new RequestPropertySearch
            {
                Token = kvp.Value
            });
            recordCounter++;
        }

    }

    var intermediateRequest = JsonConvert.SerializeObject(propertiesRequest, Formatting.Indented);
    HttpResponseMessage response = MakeRequest(serviceUrl, intermediateRequest, securityHeaderName, securityHeaderValue);

    var responseBodyAsText = response.Content.ReadAsStringAsync();
    var intermediateData = JsonConvert.DeserializeObject<PropertySearchResponse>(responseBodyAsText.Result);
    recordCounter = 0;
    foreach (var item in intermediateData.Registry)
    {
        if (item.Value != null)
        {
            var itemToUpdate = propertiesLookup[recordCounter.ToString() + "|" + item.Token];
            itemToUpdate.Properties[itemToUpdate.UpdateKey] = item.Value;
            if (directive.ToLower() == "s")
            {
                itemToUpdate.Properties[$"@{itemToUpdate.UpdateKey}"] = item.Token;
            }
            // recordCounter++;
        }
        recordCounter++;
    }

    var result = JsonConvert.SerializeObject(inputData, Formatting.Indented);


    //return req.CreateResponse(HttpStatusCode.OK, "");
    return new HttpResponseMessage()
    {
        Content = new StringContent(result, System.Text.Encoding.UTF8, "application/json")
    };
}

Модель:

public class ItemsPayload
{
    //public string Directive { get; set; }

    public List<Dictionary<string, string>> Wrapper { get; set; }
}

public class PropertySearchRequest
{
    public List<RequestPropertySearch> Registry { get; set; }
}

public class RequestPropertySearch
{
    public string Token { get; set; }
}

public class PropertySearchResponse
{
    public List<ResponsePropertySearch> Registry { get; set; }
}

public class ResponsePropertySearch
{
    public string Token { get; set; }

    public string Value { get; set; }

    public string ProcessId { get; set; }

    public string Code { get; set; }

    public string Remote { get; set; }

    public string Message { get; set; }
}

public class ItemUpdate
{
    public Dictionary<string, string> Properties { get; set; }

    public string UpdateKey { get; set; }
}

Я думаю, что свойство класса ItemsPayload "Wrapper" вызывает это так, как будто вы меняете это на что-то другое и переименовываете узел в JSON, он работает нормально, но я хочу, чтобы он был независим от имени узла верхнего уровня. Есть мысли?

1 Ответ

0 голосов
/ 08 ноября 2018

Вы можете создать простой JsonConverter для вашего ItemsPayload для обработки изменяющегося имени оболочки.

public class ItemsPayloadConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(ItemsPayload);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject obj = JObject.Load(reader);
        ItemsPayload payload = new ItemsPayload();
        // Get the first property of the outer JSON object regardless of its name
        // and populate the payload from it
        JProperty wrapper = obj.Properties().FirstOrDefault();
        if (wrapper != null)
        {
            payload.Wrapper = wrapper.Value.ToObject<List<Dictionary<string, string>>>(serializer);
        }
        return payload;
    }

    public override bool CanWrite
    {
        get { return false; }
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Затем просто аннотируйте свой класс ItemsPayload с помощью атрибута [JsonConverter], как это, и он должен работать без других изменений в вашем коде:

[JsonConverter(typeof(ItemsPayloadConverter))]
public class ItemsPayload
{
    public List<Dictionary<string, string>> Wrapper { get; set; }
}

Скрипка: https://dotnetfiddle.net/9q4tgW

...