Partage via


Utiliser des types ouverts avec des API personnalisées

Lorsque vous créez un message Microsoft Dataverse à l’aide d’une API personnalisée, vous devez spécifier le nom et le type de données de chacun des paramètres de demande et des propriétés de réponse. Les types de données peuvent être ouverts ou fermés. Avec les types fermés, chaque nom de propriété et chaque valeur de type sont connus. Tous les types définis dans Dataverse sont fermés. Le système connaît les types fermés et peut les valider pour vous. Si vous utilisez le mauvais nom ou définissez la valeur sur le mauvais type, vous obtenez une erreur. Mais les types fermés ne sont pas dynamiques. Ils ne permettent pas les propriétés complexes et imbriquées. Normalement, une structure spécifique est une bonne chose, mais parfois votre logique métier nécessite une approche plus flexible.

Contrairement aux types fermés, les types ouverts peuvent avoir des propriétés dynamiques. L’utilisation de types ouverts avec des API personnalisées a du sens lorsque :

  • Vous devez utiliser des données dynamiques structurées. Ces données ne peuvent pas être décrites par une classe, il n’est donc pas nécessaire de les sérialiser ou de les désérialiser.
  • Vous souhaitez qu’une API personnalisée accepte un paramètre de requête ou renvoie une propriété de réponse dont le type complexe ne peut pas être exprimé à l’aide des options disponibles. Dans ce cas, vous devez utiliser un type fermé personnalisé.

Il est important de comprendre le scénario qui s’applique à votre API personnalisée pour utiliser correctement les types ouverts. Voyons d’abord comment utiliser les types ouverts.

Comment utiliser les types ouverts

Pour utiliser des types ouverts, vous avez besoin d’un message configuré pour eux. Avec une API personnalisée, vous spécifiez qu’un paramètre de requête ou une propriété de réponse est ouvert en définissant Type sur Entity (3) ou EntityCollection (4) sans spécifier un LogicalEntityName.

Lorsque vous ne spécifiez pas le LogicalEntityName, vous indiquez à Dataverse que Entity est une collection de paires clé/valeur qui ne peut être validée par aucune définition de table, donc il n’essaie pas. Une EntityCollection sans LogicalEntityName est juste un tableau d’Entité.

Notes

Une API personnalisée définie comme fonctions ne peut pas utiliser de types ouverts comme paramètres de requête, mais peut les utiliser comme propriétés de réponse.

Utiliser des entités Dataverse

Bien qu’il ne s’agisse pas réellement d’un type ouvert, il convient de mentionner que vous pouvez avoir une API personnalisée avec des paramètres ou des propriétés de réponse qui représentent plusieurs types d’entités fermées. Par exemple, vous pouvez créer une API personnalisée avec un paramètre Customer qui attend des instances d’entité Account ou Contact. Dataverse permet n’importe quel type d’entité. Votre code de plug-in doit vérifier la valeur Entity.LogicalName pour déterminer s’il s’agit d’un type attendu.

Utiliser Entité en tant que dictionnaire

Le cas le plus courant consiste à utiliser Entity comme dictionnaire. Utilisez la collection Entity.Attributes pour spécifier un ensemble de clés et de valeurs. Les valeurs peuvent être de n’importe quel type .NET et peuvent être imbriquées. N’utilisez pas d’autre propriété de classe Entité.

Supposons que votre application utilise des données provenant de ou envoyées à Microsoft Graph et représente le type de ressource educationSchool. Vous pouvez utiliser un type ouvert comme dans les exemples suivants.

Pour utiliser un type ouvert avec le SDK, utilisez la classe Entity sans spécifier le nom de l’entité, puis définissez la collection Entity.Attributes avec les clés et leurs valeurs.

var educationSchool = new Entity() {
    Attributes =
    {
        { "id", Guid.NewGuid() },
        { "displayName","Redmond STEM Academy" },
        { "phone", "555-1234" },
        { "address",  new Entity() //physicalAddress resource type
            {
            Attributes =
                {
                    { "city","Redmond" },
                    { "countryOrRegion","United States" },
                    { "postalCode","98008" },
                    { "state","Washington" },
                    { "street","123 Maple St" },
                }
            }
        }
    }
};

Utiliser les types Dataverse

En plus des types .NET de base, vous pouvez également utiliser des types connus pour Dataverse. Le SDK pour .NET contient les définitions de nombreuses classes connues de Dataverse et dans l’API web, ces types sont répertoriés dans l’API web référence du type complexe et Référence du type d’énumération.

Lorsque vous utilisez le SDK, vous pouvez simplement définir les valeurs.

Lorsque vous utilisez l’API web, vous devez spécifier le type à l’aide de l’espace de noms de l’API web : Microsoft.Dynamics.CRM. L’exemple suivant utilise ces types d’API web Dataverse :

{
  "@odata.type": "Microsoft.Dynamics.CRM.expando",
  "label@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
   "label": {      
      "Label": "Yes",
      "LanguageCode": 1033
   },
  "labelarray": [
    {
      "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
      "Label": "test",
      "LanguageCode": 1033
    },
    {
      "@odata.type": "Microsoft.Dynamics.CRM.LocalizedLabel",
      "Label": "prøve",
      "LanguageCode": 1030
    }
  ],
  "labelarray@odata.type": "Collection(Microsoft.Dynamics.CRM.LocalizedLabel)",
  "enumarray": ["DateOnly"],
  "enumarray@odata.type": "Collection(Microsoft.Dynamics.CRM.DateTimeFormat)"
}

Données dynamiques structurées

Les données dynamiques structurées peuvent être définies à l’aide de divers formats pouvant être définis sous forme de chaîne, tels que JSON, XML, YAML et HTML. Ce type de données peut être facilement défini à l’aide d’un paramètre de chaîne ou d’une propriété de réponse. Alors pourquoi utiliser des types ouverts ?

  • Utilisez une chaîne lorsque les données structurées sont transmises via votre API personnalisée à un autre service ou sont consommées sous forme de chaîne par une autre application qui appelle votre API personnalisée.
  • Utilisez un type ouvert lorsque le plug-in qui prend en charge votre API personnalisée, ou tout plug-in qui étend votre API personnalisée, doit lire ou modifier les données structurées.

Analyser une valeur de chaîne dans un objet tel que XDocument ou JObject afin que vous puissiez la manipuler dans votre plug-in- est une opération relativement coûteuse. Lorsque votre plug-in, ou tout autre plug-in susceptible d’étendre la logique de votre API personnalisée, modifie les données, il doit reconvertir l’objet en chaîne. Vous pouvez éviter ces opérations coûteuses en utilisant des types ouverts.

Avec les types ouverts, les appelants de votre API personnalisée peuvent utiliser la structure de dictionnaire familière fournie par la classe Entity. Votre plug-in peut interagir avec lui de la même manière que vous travaillez avec d’autres enregistrements Dataverse.

Si vous sérialisez ou désérialisez les données de chaîne dans une classe, vos données ne sont pas dynamiques. Vous devriez revoir la section suivante.

Types fermés personnalisés

Les types ouverts permettent des données dynamiques et non structurées. Mais vous devez déterminer si votre API a des paramètres vraiment dynamiques ou si vous souhaitez réellement avoir un type personnalisé.

Actuellement, vous ne pouvez pas définir un type personnalisé que Dataverse connaît. Mais en utilisant des types ouverts, vous pouvez définir une classe de type fermé que Dataverse peut traiter comme un type ouvert. Les développeurs utilisant votre API personnalisée peuvent utiliser vos classes pour avoir une meilleure expérience plus productive avec moins de possibilités d’erreurs.

Par exemple, supposons que votre API personnalisée nécessite un paramètre qui suit un parcours à l’aide d’un tableau de coordonnées de latitude et de longitude. Vous avez besoin d’une classe Location.

Vous pouvez créer une classe Location qui hérite de la classe Entité et contient les propriétés dont vous avez besoin. Par exemple :

using Microsoft.Xrm.Sdk;

namespace MyCompany
{
    /// <summary>
    /// Specifies a location for use with my_CustomAPI
    /// </summary>
    public class Location : Entity
    {
        // Gets or sets the latitude of the Location.
        [AttributeLogicalName("Latitude")]
        public double Latitude
        {
            get
            {
                return GetAttributeValue<double>("Latitude");
            }
            set
            {
                SetAttributeValue("Latitude", value);
            }
        }

        // Gets or sets the longitude of the Location.
        [AttributeLogicalName("Longitude")]
        public double Longitude
        {
            get
            {
                return GetAttributeValue<double>("Longitude");
            }
            set
            {
                SetAttributeValue("Longitude", value);
            }
        }
    }
}

Puisque ce type hérite de la classe Entity, il peut utiliser les méthodes Entity GetAttributeValue et SetAttributeValue pour accéder aux valeurs de la collection Attributes. Vous pouvez utiliser cette classe dans votre code de plug-in et la partager avec des consommateurs dans une bibliothèque ou dans un exemple de code dans votre documentation. Le résultat est un code plus facile à utiliser et à lire.

Avant :

var location = new Entity() { 
   Attributes =
   {
      { "Latitude", 47.66132951804776 },
      { "Longitude", -122.11446844957624},            
   }            
};

// OR 

var location = new Entity();
location["Latitude"] = 47.66132951804776;
location["Longitude"] = -122.11446844957624;

Après :

var location = new Location { 
   Latitude = 47.66132951804776,
   Longitude = -122.11446844957624
};

// OR 

var location = new Location()
location.Latitude = 47.66132951804776;
location.Longitude = -122.11446844957624;

Problèmes connus

Erreur d’utilisation des données du tableau avec l’API web

Lorsque vous utilisez l’API web pour envoyer des données contenant un tableau, l’erreur suivante se produit lorsque votre API personnalisée dispose d’un plug-in :

{
  "error": {
    "code": "0x80040224",
    "message": "Element 'http://schemas.datacontract.org/2004/07/System.Collections.Generic:value' contains 
     data from a type that maps to the name 'System.Collections.Generic:List`1'. The deserializer has no 
     knowledge of any type that maps to this name. Consider changing the implementation of the ResolveName 
     method on your DataContractResolver to return a non-null value for name 'List`1' and namespace 
     'System.Collections.Generic'.",
  }
}

Cette erreur ne se produit pas lorsque l’application cliente utilise le SDK pour .NET ou lorsqu’aucun plug-in n’est défini pour l’API personnalisée.

Utilisez le bouton Commentaires pour Cette page ci-dessous pour soumettre vos questions sur les types ouverts.

Voir aussi

Créer et utiliser des API personnalisées
Tutoriel avancé Odata.org : Type ouvert