5
votes

Échec de la sérialisation de IConfigurationSection à partir de Json

J'ai le fichier de configuration basé sur Json suivant:

{   
  "ProcessRecognitionConfiguration": {
    "OrderSelectionConfiguration": {
      "SelectionDaysInterval": 30,
      "SelectionDaysMaximum": 365
    }
  }
}

En tant que cadre de sérialisation, j'utilise Newtonsoft . Pour sérialiser cette configuration en objets, j'ai implémenté les classes suivantes:

this.ConfigurationSection.GetSection("Processing").Get<ProcessRecognitionConfiguration>()

Dans une classe, j'essaie de sérialiser une section de configuration spécifique dans ces structures de classe en utilisant IConfigurationSection.Get ( ) .

var serializedConfiguration = this.ConfigurationSection.Get<RecognitionConfiguration>();

Mais quand je débogue le code, j'obtiens toujours une variable "vide" serializedConfiguration qui n'est pas nulle, mais toutes les propriétés sont nulles.

 entrez la description de l'image ici

Si j'utilise

[JsonObject(MemberSerialization.OptIn)]
public class RecognitionConfiguration {
    [JsonProperty(PropertyName = "PostProcessing", Required = Required.Always)]
    public PostRecognitionConfiguration PostRecognitionConfiguration { get; set; }

    [JsonProperty(PropertyName = "Processing", Required = Required.Always)]
    public ProcessRecognitionConfiguration ProcessRecognitionConfiguration { get; set; }
}

[JsonObject(MemberSerialization.OptIn)]
public class PostRecognitionConfiguration {
    [JsonProperty(Required = Required.Always)]
    public ValidationHandlerConfiguration ValidationHandlerConfiguration { get; set; }

    [JsonProperty] public List<string> MatchingCharacterRemovals { get; set; }
}

[JsonObject(MemberSerialization.OptIn)]
public class ProcessRecognitionConfiguration {
    [JsonProperty(PropertyName = "OrderSelection", Required = Required.Always)]
    public OrderSelectionConfiguration OrderSelectionConfiguration { get; set; }
}

ou modifie le nom des propriétés dans le fichier json pour correspondre exactement aux noms de propriété dans les classes comme ceci:

{
  "PostProcessing": {
    "ValidationHandlerConfiguration": {
      "MinimumTrustLevel": 80,
      "MinimumMatchingTrustLevel": 75
    },
    "MatchingCharacterRemovals": [
      "-",
      "''",
      ":"
    ]
  },
  "Processing": {
    "OrderSelection": {
      "SelectionDaysInterval": 30,
      "SelectionDaysMaximum": 365
    }
  }
}

cela fonctionne bien. Avez-vous une idée, pourquoi définir PropertyName sur JsonProperty ne semble pas avoir d'effet?


5 commentaires

Lorsque vous déboguez et que vous appelez var serializedConfiguration = this.ConfigurationSection.Get (); les valeurs existent-elles dans l'objet à ce moment-là avant d'essayer d'enregistrer les enfants?


@KieranDevlin J'ai édité mon message pour vous le montrer.


Modifiez votre exemple minimal reproductible et supprimez-en Autofac. La partie intéressante est ConfigurationSection.Get () ainsi que le json qui devrait être désérialisé. Le fait que les propriétés soient nulles n'a rien à voir avec Autofac, laisser cela dans votre question ne fait qu'ajouter du bruit.


@Igor Merci pour vos commentaires. J'ai remanié mon message.


@ rbr94 qui est par conception. La liaison à POCO via la configuration ne ressemble pas aux paramètres de liaison de modèle aux paramètres d'action. Il fait correspondre les noms de propriété sur le POCO aux clés dans le JSON fourni. Lisez ici docs.microsoft.com/en-us/aspnet/core/fundamentals/configurat‌ ion /…


3 Réponses :


3
votes

C'est par conception. La liaison à POCO via la configuration se fait par convention. Pas comme la liaison de modèle aux paramètres d'action du contrôleur.

Il fait correspondre les noms de propriété du POCO aux clés du JSON fourni.

Référence Configuration dans ASP.NET Core

Donc, soit vous modifiez les paramètres pour qu'ils correspondent à la classe comme vous l'avez montré dans la question d'origine, soit vous modifiez la classe pour correspondre aux paramètres clés dans le fichier de configuration basé sur Json.

[JsonObject(MemberSerialization.OptIn)]
public class RecognitionConfiguration {
    [JsonProperty(PropertyName = "PostProcessing", Required = Required.Always)]
    public PostRecognitionConfiguration PostProcessing{ get; set; }

    [JsonProperty(PropertyName = "Processing", Required = Required.Always)]
    public ProcessRecognitionConfiguration Processing{ get; set; }
}

[JsonObject(MemberSerialization.OptIn)]
public class PostRecognitionConfiguration {
    [JsonProperty(Required = Required.Always)]
    public ValidationHandlerConfiguration ValidationHandlerConfiguration { get; set; }

    [JsonProperty] 
    public List<string> MatchingCharacterRemovals { get; set; }
}

[JsonObject(MemberSerialization.OptIn)]
public class ProcessRecognitionConfiguration {
    [JsonProperty(PropertyName = "OrderSelection", Required = Required.Always)]
    public OrderSelectionConfiguration OrderSelection { get; set; }
}

public partial class ValidationHandlerConfiguration {
    [JsonProperty("MinimumTrustLevel")]
    public long MinimumTrustLevel { get; set; }

    [JsonProperty("MinimumMatchingTrustLevel")]
    public long MinimumMatchingTrustLevel { get; set; }
}


public partial class OrderSelectionConfiguration {
    [JsonProperty("SelectionDaysInterval")]
    public long SelectionDaysInterval { get; set; }

    [JsonProperty("SelectionDaysMaximum")]
    public long SelectionDaysMaximum { get; set; }
}


3 commentaires

Merci pour votre réponse. C'est vraiment utile! J'espérais une solution où il est possible d'attribuer des noms de propriété personnalisés comme dans newtonsoft


Bien que ma réponse puisse résoudre le problème d'OP, je ne pense (encore) à aucune situation nécessitant la complexité impliquée. Je recommande fortement d'utiliser celui-ci si possible.


Une question à ce sujet ... Les propriétés [JsonProperty] et [JsonObject] perdent maintenant leur sens?



-1
votes

La modification de PropertyName sur JsonProperty a un effet. Voici la même chose que j'ai essayé et cela a fonctionné pour moi:

mes données JSON:

RootObject obj = JsonConvert.DeserializeObject<RootObject>(json);

et le modèle:

public class RootObject
    {
        [JsonProperty(PropertyName ="name")]
        public string Apple { get; set; }
        public int age { get; set; }
        public List<string> cars { get; set; }
    }


1 commentaires

Je ne pense pas que cela pose le problème de ma question. Ce n'est pas un problème avec la désérialisation avec Newtonsoft, mais avec l'extension Get<> de IConfigurationSection



1
votes

EDIT: J'ai trouvé que celle-ci est beaucoup plus agréable que mes solutions précédentes: liez tout dans un ExpandoObject , écrivez-les en JSON et utilisez JSON.NET pour les relier. Utilisation du code de cet article :

public class MySettings
{

    [JsonProperty("PostProcessing")]
    public SomeNameElseSettings SomenameElse { get; set; }

    public class SomeNameElseSettings
    {

        [JsonProperty("ValidationHandlerConfiguration")]
        public ValidationHandlerConfigurationSettings WhateverNameYouWant { get; set; }

        public class ValidationHandlerConfigurationSettings
        {

            [JsonProperty("MinimumTrustLevel")]
            public int MinimumTrustLevelFoo { get; set; }

            [JsonProperty("MinimumMatchingTrustLevel")]
            public int MinimumMatchingTrustLevelBar { get; set; }
        }
    }
}
  • Insérez votre code source là-bas, ou copiez simplement ce fichier (dans ma tentative de tracer le code, je renomme toutes les méthodes en quelque chose comme Bind2 , BindInstance2 etc), et réécrivez le code en conséquence.

  • Celui-ci est très spécifique à l'implémentation actuelle, il n'est donc pas à l'épreuve du temps: le code actuel appelle config.GetSection (property.Name) , vous pouvez donc écrire votre propre IConfiguration et indiquez votre propre nom pour la méthode GetSection et appuyez dessus dans le processus d'amorçage au lieu d'utiliser celui par défaut.


0 commentaires