Offene Typen mit Custom-APIs verwenden

Wenn Sie eine Microsoft Dataverse-Nachricht mit einer Custom-API erstellen, müssen Sie den Namen und den Typ der einzelnen Abfrageparameter und Antworteigenschaften angeben. Die Datentypen können offen oder geschlossen sein. Bei geschlossenen Typen ist jeder Eigenschaftsname und jeder Wert des Typs bekannt. Alle Typen, die in Dataverse definiert sind, sind geschlossen. Das System kennt geschlossene Typen und kann sie für Sie validieren. Wenn Sie den falschen Namen verwenden oder den Wert auf den falschen Typ setzen, erhalten Sie eine Fehlermeldung. Geschlossene Typen sind jedoch nicht dynamisch. Sie lassen keine komplexen und verschachtelten Eigenschaften zu. Normalerweise ist eine bestimmte Struktur eine gute Sache, aber manchmal erfordert Ihre Geschäftslogik einen flexibleren Ansatz.

Anders als geschlossene Typen können offene Typen dynamische Eigenschaften haben. Die Verwendung offener Typen mit Custom-APIs ist sinnvoll, wenn:

  • Sie müssen Strukturierte dynamische Daten verwenden. Diese Daten können nicht anhand einer Klasse beschrieben werden, daher besteht keine Notwendigkeit, sie zu serialisieren oder zu deserialisieren.
  • Sie möchten, dass eine Custom-API einen Anfrageparameter akzeptiert oder eine Antworteigenschaft zurückgibt, die einen komplexen Typ hat, der nicht mit den verfügbaren Optionen ausgedrückt werden kann. In diesem Fall müssen Sie einen angepassten geschlossenen Typ verwenden.

Es ist wichtig, dass Sie das Szenario verstehen, das für Ihre Custom-API gilt, um offene Typen korrekt zu verwenden. Lassen Sie uns zunächst verstehen, wie man offene Typen verwendet.

So verwenden Sie offene Typen

Um offene Typen zu verwenden, benötigen Sie eine Nachricht, die für diese Typen konfiguriert ist. Mit einer Custom-API geben Sie an, dass ein Anfrageparameter oder eine Antworteigenschaft offen ist, indem Sie die Type auf Entität (3) oder EntityCollection (4) ohne eine LogicalEntityName angeben.

Wenn Sie die LogicalEntityName nicht angeben, teilen Sie Dataverse mit, dass Entity eine Sammlung von Schlüssel/Wert-Paaren ist, die nicht gegen eine Tabellendefinition validiert werden kann, also wird es nicht versucht. Eine EntityCollection ohne einen LogicalEntityName ist nur ein Array von Entity.

Hinweis

Eine Custom-API, die als Funktionen definiert ist, kann keine offenen Typen als Anfrageparameter verwenden, aber sie kann sie als Antworteigenschaften verwenden.

Dataverse-Entitäten verwenden

Obwohl es sich nicht um einen offenen Typ handelt, ist es erwähnenswert, dass Sie eine Custom-API mit Parametern oder Antworteigenschaften haben können, die mehr als einen geschlossenen Typ von Entitäten darstellen. Sie können zum Beispiel eine Custom-API mit einem Customer-Parameter erstellen, der entweder Account oder Contact Entitäten erwartet. Dataverse erlaubt jeden Entitätstyp. Bei Ihrem Plug-In-Code muss der Entity.LogicalName-Wert überprüft werden, um zu bestimmen, ob es sich um einen Typ handelt, den Sie erwarten.

Entität als Wörterbuch verwenden

Der allgemeinere Fall ist die Verwendung von Entität als Wörterbuch. Verwenden Sie die Entity.Attributes-Sammlung, um einen Satz von Schlüsseln und Werten anzugeben. Die Werte können ein beliebiger .NET-Typ und verschachtelt sein. Verwenden Sie keine anderen Entitäts-Klasseneigenschaften.

Angenommen, Ihre Anwendung verwendet Daten, die aus Microsoft Graph stammen oder an Microsoft Graph gesendet werden und den Typ educationSchool repräsentieren. Sie könnten einen offenen Typ wie in den folgenden Beispielen verwenden.

Um einen offenen Typ mit dem SDK zu verwenden, verwenden Sie die Klasse Entity, ohne den Namen der Entität anzugeben, und setzen dann die Sammlung Entity.Attributes mit den Schlüsseln und ihren Werten.

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" },
                }
            }
        }
    }
};

Dataverse-Typen verwenden

Zusätzlich zu den grundlegenden .NET-Typen können Sie auch für Dataverse bekannte Typen verwenden. Das SDK für .NET enthält Definitionen vieler Klassen, die Dataverse kennt, und in der Web-API sind diese Typen in der Web-API Complex Typ Referenz und Enum Typ Referenz aufgeführt.

Bei Verwendung des SDK können Sie die Werte einfach festlegen.

Wenn Sie die Web-API verwenden, müssen Sie den Typ über den Web-API-Namensraum angeben: Microsoft.Dynamics.CRM. Das folgende Beispiel verwendet diese Dataverse-Web-API-Typen:

{
  "@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)"
}

Strukturierte dynamische Daten

Strukturierte dynamische Daten können in verschiedenen Zeichenfolgen definiert werden, z.B. JSON, XML, YAML und HTML. Diese Art von Daten kann einfach mithilfe eines Zeichenfolgenparameters oder einer Antworteigenschaft festgelegt werden. Warum sollten also offene Typen verwendet werden?

  • Verwenden Sie eine Zeichenfolge, wenn die strukturierten Daten über Ihre Custom-API an einen anderen Dienst weitergegeben werden oder von einer anderen Anwendung, die Ihre Custom-API aufruft, als Zeichenfolge konsumiert werden.
  • Verwenden Sie einen offenen Typ, wenn das Plug-in, das Ihre Custom-API unterstützt, oder alle Plug-ins, die Ihre Custom-API erweitern, die strukturierten Daten lesen oder ändern müssen.

Das Parsen eines Zeichenfolgenwerts in ein Objekt wie XDocument oder JObject, damit Sie es in Ihrem Plug-In bearbeiten können, ist ein relativ teurer Vorgang. Wenn Ihr Plug-in oder ein anderes Plug-in, das die Logik Ihrer Custom-API erweitern könnte, die Daten ändert, muss es das Objekt wieder in eine Zeichenfolge umwandeln. Sie können diese teuren Vorgänge vermeiden, indem Sie offene Typen verwenden.

Mit offenen Typen können die Aufrufer Ihrer Custom-API die vertraute Wörterbuchstruktur verwenden, die die Klasse Entity bietet. Ihr Plugin kann damit auf die gleiche Weise interagieren wie mit anderen Dataverse-Datensätzen.

Wenn Sie die Zeichenfolge in eine Klasse serialisieren oder deserialisieren, sind Ihre Daten nicht dynamisch. Lesen Sie dazu den nächsten Abschnitt.

Benutzerdefinierte geschlossene Typen

Offene Typen ermöglichen dynamische und unstrukturierte Daten. Sie sollten jedoch überlegen, ob Ihre API über wirklich dynamische Parameter verfügt oder ob Sie tatsächlich einen angepassten Typ haben möchten.

Derzeit können Sie keinen benutzerdefinierten Typ definieren, von dem Dataverse Kenntnis hat. Aber mit offenen Typen können Sie eine Klasse vom geschlossenen Typ definieren, die Dataverse als offenen Typ verarbeiten kann. Entwickler, die Ihre Custom-API verwenden, können Ihre Klassen nutzen, um eine bessere, produktivere Erfahrung mit weniger Verkaufschancen zu haben.

Nehmen wir an, dass Ihre Custom-API einen Parameter benötigt, der einen Kurs anhand eines Arrays von Breiten- und Längengradkoordinaten verfolgt. Sie benötigen eine Location-Klasse.

Sie können eine Location-Klasse erstellen, die Eigenschaften von der Entitäts-Klasse übernimmt und die von Ihnen benötigten Eigenschaften enthält. Zum Beispiel:

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);
            }
        }
    }
}

Da dieser Typ von der Klasse Entity erbt, kann er die Methoden Entity GetAttributeValue und SetAttributeValue für den Zugriff auf die Werte in der Attributes Sammlung verwenden. Sie können diese Klasse in Ihrem Plugin-Code verwenden und sie in einer Bibliothek oder in einem Beispielcode in Ihrer Dokumentation mit den Konsumenten teilen. Das Ergebnis ist ein Code, der einfacher zu verwenden und zu lesen ist.

Vorher:

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

// OR 

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

Nachher:

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

// OR 

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

Bekannte Probleme

Fehler beim Verwenden von Array-Daten mit der Web-API

Wenn Sie die Web-API verwenden, um Daten zu senden, die ein Array enthalten, tritt der folgende Fehler auf, wenn Ihre Custom-API über ein Plug-In verfügt:

{
  "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'.",
  }
}

Dieser Fehler tritt nicht auf, wenn die Client-Anwendung das SDK für .NET verwendet oder wenn kein Plug-in für die Custom-API eingestellt ist.

Verwenden Sie die Schaltfläche Feedback für Diese Seite unten, um Fragen zu offenen Typen einzureichen.

Siehe auch

Custom-APIs erstellen und verwenden
Odata.org-Tutorial für Fortgeschrittene: Offener Typ