Usar tipos abiertos con API personalizadas

Cuando creas un mensaje de Microsoft Dataverse utilizando una API personalizada, debe especificar el nombre y el tipo de datos de cada uno de los parámetros de solicitud y propiedades de respuesta. Los tipos de datos pueden ser abiertos o cerrados. Con tipos cerrados, se conoce cada nombre de propiedad y valor de tipo. Todos los tipos que se definen en Dataverse estan cerrados. El sistema conoce los tipos cerrados y puede validarlos por usted. Si usa el nombre incorrecto o establece el valor en el tipo incorrecto, obtendrá un error. Pero los tipos cerrados no son dinámicos. No permiten propiedades complejas y anidadas. Normalmente, una estructura específica es algo bueno, pero a veces la lógica de su negocio requiere un enfoque más flexible.

A diferencia de los tipos cerrados, tipos abiertos puede tener propiedades dinámicas. El uso de tipos abiertos con API personalizadas tiene sentido cuando:

  • Necesitas usar datos dinámicos estructurados. Estos datos no pueden ser descritos por una clase, por lo que no es necesario serializarlos o deserializarlos.
  • Desea que una API personalizada acepte un parámetro de solicitud o devuelva una propiedad de respuesta que tenga un tipo complejo que no se pueda expresar mediante las opciones disponibles. En ese caso, debe utilizar un tipo cerrado personalizado.

Es importante comprender el escenario que se aplica a su API personalizada para usar correctamente los tipos abiertos. Entendamos cómo usar tipos abiertos primero.

Cómo usar tipos abiertos

Para usar tipos abiertos, necesita un mensaje que esté configurado para ellos. Con una API personalizada, especifica que un parámetro de solicitud o una propiedad de respuesta está abierta configurando Type en Entidad (3) o EntityCollection (4) sin especificar a LogicalEntityName.

Cuando no especifica LogicalEntityName, le está diciendo a Dataverse que Entidad es una colección de pares clave/valor eso no se puede validar con ninguna definición de tabla, por lo que no lo intenta. Una EntityCollection sin LogicalEntityName es solo una matriz de Entity.

Nota

Una API personalizada definida como funciones no puede usar tipos abiertos como parámetros de solicitud, pero puede usarlos como propiedades de respuesta.

Usar entidades de Dataverse

Si bien en realidad no es un tipo abierto, vale la pena mencionar que puede tener una API personalizada con parámetros o propiedades de respuesta que representen más de un tipo de entidad cerrada. Por ejemplo, puede crear una API personalizada con un parámetro Customer que espere instancias de entidad Account o Contact. Dataverse permite cualquier tipo de entidad. Su código de complemento debe verificar el valor Entity.LogicalName para determinar si es un tipo que espera.

Usar Entity como diccionario

El caso más común es usar Entidad como diccionario. Utilizar la colección Entity.Attributes para especificar un conjunto de claves y valores. Los valores pueden ser de cualquier tipo .NET y se pueden anidar. No use ninguna otra propiedad de clase de Entidad.

Supongamos que su aplicación usa datos que provienen o se envían a Microsoft Graph y representan el tipo de recurso educationSchool. Puede usar un tipo abierto como en los siguientes ejemplos.

Para usar un tipo abierto con el SDK, use la clase Entity sin especificar el nombre de la entidad, luego configure la colección Entity.Attributes con las claves y sus valores.

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

Usar tipos de Dataverse

Además de los tipos básicos de .NET, también puede utilizar tipos conocidos por Dataverse. El SDK para .NET contiene definiciones de muchas clases que Dataverse conoce, y en la API web, estos tipos se enumeran en la API web Referencia de tipos complejos y Referencia de tipo de enumeración.

Al usar el SDK, simplemente puede establecer los valores.

Al usar la API web, debe especificar el tipo usando el espacio de nombres de la API web: Microsoft.Dynamics.CRM. El siguiente ejemplo utiliza estos tipos de API web de 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)"
}

Datos dinámicos estructurados

Los datos dinámicos estructurados se pueden definir utilizando varios formatos que se pueden configurar como una cadena, como JSON, XML, YAML y HTML. Este tipo de datos se puede configurar fácilmente mediante un parámetro de cadena o una propiedad de respuesta. Entonces, ¿por qué usar tipos abiertos?

  • Utilice una cadena cuando los datos estructurados pasan a través de su API personalizada a otro servicio o cuando otra aplicación los consume como una cadena que llama a su API personalizada.
  • Utilice un tipo abierto cuando el complemento que admita su API personalizada, o cualquier complemento que amplíe su API personalizada, deba leer o cambiar los datos estructurados.

Analizar un valor de cadena en un objeto como XDocument o JObject para que pueda manipularlo en su complemento es una operación relativamente costosa. Cuando su complemento, o cualquier otro complemento que pueda ampliar la lógica en su API personalizada, cambia los datos, debe volver a convertir el objeto en una cadena. Puede evitar estas costosas operaciones utilizando tipos abiertos.

Con tipos abiertos, las personas que llaman a su API personalizada pueden usar la estructura de diccionario familiar que proporciona la clase Entity. Tu complemento puede interactuar con él de la misma manera que trabajas con otros registros de Dataverse.

Si está serializando o deserializando los datos de la cadena en una clase, sus datos no son dinámicos. Debe revisar la siguiente sección.

Tipos cerrados personalizados

Los tipos abiertos permiten datos dinámicos y no estructurados. Pero debe considerar si su API tiene parámetros verdaderamente dinámicos o si realmente desea tener un tipo personalizado.

Actualmente, no puede definir un tipo personalizado que Dataverse conozca. Pero al usar tipos abiertos, puede definir una clase de tipo cerrado que Dataverse puede procesar como un tipo abierto. Los desarrolladores que usan su API personalizada pueden usar sus clases para tener una experiencia mejor y más productiva con menos oportunidades de errores.

Por ejemplo, supongamos que su API personalizada requiere un parámetro que rastrea un curso utilizando una matriz de coordenadas de latitud y longitud. Necesita una clase de Location.

Puede crear una clase Location que herede de la clase Entity y que contenga las propiedades que necesita. Por ejemplo:

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

Debido a que este tipo hereda de la clase Entity, puede usar los métodos Entity GetAttributeValue y SetAttributeValue para acceder a los valores en la colección Attributes. Puede usar esta clase en su código de complemento y compartirla con los consumidores en una biblioteca o en un código de muestra en su documentación. El resultado es un código que es más fácil de usar y leer.

Antes:

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

// OR 

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

Después:

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

// OR 

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

Problemas conocidos

Error al usar datos de matriz con API web

Cuando utiliza la API web para enviar datos que contienen una matriz, se produce el siguiente error cuando su API personalizada tiene un complemento:

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

Este error no ocurre cuando la aplicación cliente usa el SDK para .NET o cuando no se establece ningún complemento para la API personalizada.

Use el botón Comentarios para Esta página a continuación para enviar las preguntas que tenga sobre los tipos abiertos.

Consulte también

Crear y usar API personalizadas
Tutorial avanzado de Odata.org: tipo abierto