Compartir vía


Usar datos de archivo con registros de Adjuntos y Notas

Las tablas de datos adjuntos (ActivityMimeAttachment) y notas (anotación) contienen columnas de cadenas especiales que almacenan datos de archivos. Estas tablas existían antes que las columnas de archivos o imágenes, por lo que funcionan de manera diferente a esas tablas.

  • Los datos del archivo binario se almacenan como valores de cadena codificados en Base64 en columnas de cadena. Los archivos adjuntos se almacenan en la columnaActivityMimeAttachment.Body y las notas se almacenan en la columna Annotation.DocumentBody.
  • Los datos del nombre del archivo se almacenan en la columna FileName.
  • Los datos de tipo MIME se almacenan en la columna MimeType.

Dado que FileName, MimeType, ActivityMimeAttachment.Body y Annotation.DocumentBody son parte de los datos del archivo adjunto o nota, debe actualizar estos tres columnas junto con cualquier otro valor.

Puede obtener y establecer directamente los valores de las columnas activitymimeattachment.body y annotation.documentbody como cadenas codificadas en Base64. Establecer estos valores debería estar bien siempre que los archivos no sean demasiado grandes, por ejemplo, menos de 4 MB. De forma predeterminada, la longitud máxima es 5 MB. Puede configurar estas columnas para aceptar archivos de hasta 128 MB. Cuando haya aumentado el tamaño máximo de archivo y esté trabajando con archivos más grandes, debe usar los mensajes proporcionados para dividir los archivos en partes más pequeñas al cargar o descargar archivos. Para obtener información sobre cómo recuperar o cambiar los límites de tamaño de archivo, consulte Límites de tamaño de archivo.

Archivos de datos adjuntos

Un adjunto es un archivo que está asociado con una actividad de correo electrónico, ya sea directamente o a través de una Plantilla de correo electrónico (Plantilla). Se pueden asociar varios archivos adjuntos a la actividad o plantilla. Puede reutilizar archivos adjuntos configurando el valor activitymimeattachment.attachmentid para hacer referencia a otro archivo adjunto existente en lugar de configurar las propiedades body, filename y mimetype.

Otras tablas de Dataverse denominadas archivo adjunto

Adjunto (ActivityMimeAttachment) no debe confundirse con archivo de actividad adjunto, que admite archivos asociados con la tabla Post.

Dentro del esquema de Dataverse, también hay una tabla pública con el nombre Attachment, que se expone en la API web como attachment EntityType. Esta tabla se puede consultar y refleja los datos de la tabla ActivityMimeAttachment. Pero no admite operaciones de crear, recuperar, actualizar o eliminar. Esta tabla no aparece en el diseñador de Power Apps.

Cargar archivos adjuntos

Utilice los mensajes InitializeAttachmentBlocksUpload, UploadBlock y CommitAttachmentBlocksUpload para cargar archivos grandes para adjuntar.

Importante

Solo puede usar estos mensajes para crear un nuevo archivo adjunto. Si intenta usarlos para actualizar un archivo adjunto existente, obtendrá un error de que el registro ya existe.

El siguiente método estático UploadAttachment muestra cómo crear un adjunto con un archivo utilizando las clases InitializeAttachmentBlocksUploadRequest, UploadBlockRequest y CommitAttachmentBlocksUploadRequest para devolver un CommitAttachmentBlocksUploadResponse con propiedades ActivityMimeAttachmentId y FileSizeInBytes.

static CommitAttachmentBlocksUploadResponse UploadAttachment(
   IOrganizationService service,
   Entity attachment,
   FileInfo fileInfo,
   string fileMimeType = null)
{
   if (attachment.LogicalName != "activitymimeattachment")
   {
         throw new ArgumentException(
            "The attachment parameter must be an activitymimeattachment entity.",
            nameof(attachment));
   }

   // body value in activitymimeattachment not needed. Remove if found.
   if (attachment.Contains("body"))
   {
         attachment.Attributes.Remove("body");
   }

   // Try to get the mimetype if not provided.
   if (string.IsNullOrEmpty(fileMimeType))
   {
         var provider = new FileExtensionContentTypeProvider();

         if (!provider.TryGetContentType(fileInfo.Name, out fileMimeType))
         {
            fileMimeType = "application/octet-stream";
         }
   }
   // Don't overwrite mimetype value if it exists
   if (!attachment.Contains("mimetype"))
   {
         attachment["mimetype"] = fileMimeType;
   }

   // Initialize the upload
   InitializeAttachmentBlocksUploadRequest initializeRequest = new()
   {
         Target = attachment
   };

   var initializeResponse =
         (InitializeAttachmentBlocksUploadResponse)service.Execute(initializeRequest);

   string fileContinuationToken = initializeResponse.FileContinuationToken;

   // Capture blockids while uploading
   List<string> blockIds = new();

   using Stream uploadFileStream = fileInfo.OpenRead();

   int blockSize = 4 * 1024 * 1024; // 4 MB

   byte[] buffer = new byte[blockSize];
   int bytesRead = 0;

   long fileSize = fileInfo.Length;

   // The number of iterations that will be required:
   // int blocksCount = (int)Math.Ceiling(fileSize / (float)blockSize);
   int blockNumber = 0;

   // While there is unread data from the file
   while ((bytesRead = uploadFileStream.Read(buffer, 0, buffer.Length)) > 0)
   {
         // The file or final block may be smaller than 4MB
         if (bytesRead < buffer.Length)
         {
            Array.Resize(ref buffer, bytesRead);
         }

         blockNumber++;

         string blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));

         blockIds.Add(blockId);

         // Prepare the request
         UploadBlockRequest uploadBlockRequest = new()
         {
            BlockData = buffer,
            BlockId = blockId,
            FileContinuationToken = fileContinuationToken,
         };

         // Send the request
         service.Execute(uploadBlockRequest);
   }

   // Commit the upload
   CommitAttachmentBlocksUploadRequest commitRequest = new()
   {
         BlockList = blockIds.ToArray(),
         FileContinuationToken = fileContinuationToken,
         Target = attachment
   };
   
      return  (CommitAttachmentBlocksUploadResponse)service.Execute(commitRequest);

}

Más información:

Nota

Este método de ejemplo incluye algo de lógica para tratar de obtener el Tipo de MIME del archivo usando el Método FileExtensionContentTypeProvider.TryGetContentType(String, String) si no se proporciona. Si el tipo de datos no se encuentra, se establece en application/octet-stream.

Descargar los archivos de datos adjuntos

Puede descargar un archivo adjunto en una sola operación mediante la API web o en fragmentos mediante el SDK o la API web.

Descargue archivos adjuntos en una sola operación utilizando la API web

Puede descargar un archivo adjunto en una sola operación utilizando la API web.

A diferencia de la recuperación de columnas de archivos, este método no proporciona información sobre el tamaño del archivo, el nombre del archivo o el tipo MIME.

Solicitud:

GET [Organization Uri]/api/data/v9.2/activitymimeattachments(<activitymimeattachmentid>)/body/$value HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0
Content-Type: text/plain

<Base64 string content removed for brevity>

Más información:

Descargar los archivos de datos adjuntos en fragmentos

Para recuperar el archivo en fragmentos, use los siguientes mensajes con el SDK o la API web:

Publicación Descripción
InitializeAttachmentBlocksDownload Especifica el registro de Nota del que desea descargar un archivo. Devuelve el tamaño del archivo en bytes y un token de continuación de archivo que puede usar para descargar el archivo en bloques usando el mensaje DownloadBlock.
DownloadBlock Solicita el tamaño del bloque, el valor de compensación y el token de continuación del archivo.

Después de descargar todos los bloques, únelos para crear el archivo descargado completo.

El siguiente método estático DownloadAttachment muestra cómo descargar un archivo adjunto mediante el SDK con las clases InitializeAttachmentBlocksDownloadRequest y DownloadBlockRequest. Esta función devuelve los datos byte[] y el nombre del archivo.

static (byte[] bytes, string fileName) DownloadAttachment(
   IOrganizationService service,
   EntityReference target)
{
   if (target.LogicalName != "activitymimeattachment")
   {
         throw new ArgumentException(
            "The target parameter must refer to an activitymimeattachment record.",
            nameof(target));
   }

   InitializeAttachmentBlocksDownloadRequest initializeRequest = new()
   {
         Target = target
   };

   var response =
         (InitializeAttachmentBlocksDownloadResponse)service.Execute(initializeRequest);

   string fileContinuationToken = response.FileContinuationToken;
   int fileSizeInBytes = response.FileSizeInBytes;
   string fileName = response.FileName;

   List<byte> fileBytes = new(fileSizeInBytes);

   long offset = 0;
   long blockSizeDownload = 4 * 1024 * 1024; // 4 MB

   // File size may be smaller than defined block size
   if (fileSizeInBytes < blockSizeDownload)
   {
         blockSizeDownload = fileSizeInBytes;
   }

   while (fileSizeInBytes > 0)
   {
         // Prepare the request
         DownloadBlockRequest downLoadBlockRequest = new()
         {
            BlockLength = blockSizeDownload,
            FileContinuationToken = fileContinuationToken,
            Offset = offset
         };

         // Send the request
         var downloadBlockResponse =
                  (DownloadBlockResponse)service.Execute(downLoadBlockRequest);

         // Add the block returned to the list
         fileBytes.AddRange(downloadBlockResponse.Data);

         // Subtract the amount downloaded,
         // which may make fileSizeInBytes < 0 and indicate
         // no further blocks to download
         fileSizeInBytes -= (int)blockSizeDownload;
         // Increment the offset to start at the beginning of the next block.
         offset += blockSizeDownload;
   }

   return (fileBytes.ToArray(), fileName);
}

Más información:

Archivos de anotación

Una nota es un registro asociado con una fila de la tabla que contiene texto y puede tener un solo archivo adjunto. Solo las tablas con EntityMetadata.HasNotes establecido en verdadero pueden tener notas asociadas.

Cargar archivos de anotación

Utilice los mensajes InitializeAnnotationBlocksUpload, UploadBlock y CommitAnnotationBlocksUpload para cargar archivos para notas.

La anotación que pasa como el parámetro Target para estos mensajes debe tener un valor annotationid. Así es como puede actualizar los registros de anotación existentes.

Normalmente, es mejor dejar a Dataverse generar los valores de identificador único al crear nuevos registros, pero eso no es posible con estos mensajes. Para crear una nueva anotación con estos mensajes, debe generar un nuevo valor Guid para establecer como valor annotationid en lugar de dejar que Dataverse genere el valor.

El siguiente método estático UploadNote muestra cómo crear o actualizar una nota con un archivo usando las clases InitializeAnnotationBlocksUploadRequest, UploadBlockRequest y CommitAnnotationBlocksUploadRequest. Devuelve un registro CommitAnnotationBlocksUploadResponse con las propiedades AnnotationId y FileSizeInBytes.

static CommitAnnotationBlocksUploadResponse UploadNote(
   IOrganizationService service,
   Entity annotation,
   FileInfo fileInfo,
   string? fileMimeType = null)
{

   if (annotation.LogicalName != "annotation")
   {
         throw new ArgumentException(
            message: "The annotation parameter must be an annotation entity",
            paramName: nameof(annotation));
   }
   if (!annotation.Attributes.Contains("annotationid") || annotation.Id != Guid.Empty)
   {
         throw new ArgumentException(
            message: "The annotation parameter must include a valid annotationid value.",
            paramName: nameof(annotation));
   }

   // documentbody value in annotation not needed. Remove if found.
   if (annotation.Contains("documentbody"))
   {
         annotation.Attributes.Remove("documentbody");
   }

   // Try to get the mimetype if not provided.
   if (string.IsNullOrEmpty(fileMimeType))
   {
         var provider = new FileExtensionContentTypeProvider();

         if (!provider.TryGetContentType(fileInfo.Name, out fileMimeType))
         {
            fileMimeType = "application/octet-stream";
         }
   }
   // Don't override what might be included in the annotation.
   if (!annotation.Contains("mimetype")) {
         annotation["mimetype"] = fileMimeType;
   }
   
   // Initialize the upload
   InitializeAnnotationBlocksUploadRequest initializeRequest = new()
   {
         Target = annotation
   };

   var initializeResponse =
         (InitializeAnnotationBlocksUploadResponse)service.Execute(initializeRequest);

   string fileContinuationToken = initializeResponse.FileContinuationToken;

   // Capture blockids while uploading
   List<string> blockIds = new();

   using Stream uploadFileStream = fileInfo.OpenRead();

   int blockSize = 4 * 1024 * 1024; // 4 MB

   byte[] buffer = new byte[blockSize];
   int bytesRead = 0;

   long fileSize = fileInfo.Length;

   // The number of iterations that will be required:
   // int blocksCount = (int)Math.Ceiling(fileSize / (float)blockSize);
   int blockNumber = 0;

   // While there is unread data from the file
   while ((bytesRead = uploadFileStream.Read(buffer, 0, buffer.Length)) > 0)
   {
         // The file or final block may be smaller than 4MB
         if (bytesRead < buffer.Length)
         {
            Array.Resize(ref buffer, bytesRead);
         }

         blockNumber++;
         // Generates base64 string blockId values based on a Guid value so they are always the same length.
         string blockId = Convert.ToBase64String(Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()));

         blockIds.Add(blockId);

         // Prepare the request
         UploadBlockRequest uploadBlockRequest = new()
         {
            BlockData = buffer,
            BlockId = blockId,
            FileContinuationToken = fileContinuationToken,
         };

         // Send the request
         service.Execute(uploadBlockRequest);
   }

   // Commit the upload
   CommitAnnotationBlocksUploadRequest commitRequest = new()
   {
         BlockList = blockIds.ToArray(),
         FileContinuationToken = fileContinuationToken,
         Target = annotation
   };

      return  (CommitAnnotationBlocksUploadResponse)service.Execute(commitRequest);
}

Más información:

Nota

Este método de ejemplo incluye algo de lógica para tratar de obtener el Tipo de MIME del archivo usando el Método FileExtensionContentTypeProvider.TryGetContentType(String, String) si no se proporciona. Si el tipo de datos no se encuentra, se establece en application/octet-stream.

Descargar archivos de anotación

Puede descargar un archivo de Nota en una sola operación mediante la API web o en fragmentos mediante el SDK o la API web.

Descargue archivos de anotación en una sola operación utilizando la API web

Puede descargar un archivo de Nota en una sola operación utilizando la API web:

A diferencia de la recuperación de columnas de archivos, este método no proporciona información sobre el tamaño del archivo, el nombre del archivo o el tipo MIME.

Solicitud:

GET [Organization Uri]/api/data/v9.2/annotations(<annotationid>)/documentbody/$value HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0
Content-Type: text/plain

<Base64 string content removed for brevity>

Más información:

Descargar los archivos de anotación en fragmentos

Para recuperar el archivo en fragmentos, use los siguientes mensajes con el SDK o la API web:

Publicación Descripción
InitializeAnnotationBlocksDownload Especifica el registro de Nota del que desea descargar un archivo. Devuelve el tamaño del archivo en bytes y un token de continuación de archivo que puede usar para descargar el archivo en bloques usando el mensaje DownloadBlock.
DownloadBlock Solicita el tamaño del bloque, el valor de compensación y el token de continuación del archivo.

Después de descargar todos los bloques, únelos para crear el archivo descargado completo.

El siguiente método estático DownloadNote muestra cómo descargar una nota usando el SDK con las clases InitializeAnnotationBlocksDownloadRequest y DownloadBlockRequest. Esta función devuelve los datos byte[] y el nombre del archivo.

static (byte[] bytes, string fileName) DownloadNote(
    IOrganizationService service,
    EntityReference target)
{
if (target.LogicalName != "annotation")
{
      throw new ArgumentException("The target parameter must refer to an note record.", nameof(target));
}

InitializeAnnotationBlocksDownloadRequest initializeRequest = new()
{
      Target = target
};

var response =
      (InitializeAnnotationBlocksDownloadResponse)service.Execute(initializeRequest);

string fileContinuationToken = response.FileContinuationToken;
int fileSizeInBytes = response.FileSizeInBytes;
string fileName = response.FileName;

List<byte> fileBytes = new(fileSizeInBytes);

long offset = 0;
long blockSizeDownload = 4 * 1024 * 1024; // 4 MB

// File size may be smaller than defined block size
if (fileSizeInBytes < blockSizeDownload)
{
      blockSizeDownload = fileSizeInBytes;
}

while (fileSizeInBytes > 0)
{
      // Prepare the request
      DownloadBlockRequest downLoadBlockRequest = new()
      {
            BlockLength = blockSizeDownload,
            FileContinuationToken = fileContinuationToken,
            Offset = offset
      };

      // Send the request
      var downloadBlockResponse =
                  (DownloadBlockResponse)service.Execute(downLoadBlockRequest);

      // Add the block returned to the list
      fileBytes.AddRange(downloadBlockResponse.Data);

      // Subtract the amount downloaded,
      // which may make fileSizeInBytes < 0 and indicate
      // no further blocks to download
      fileSizeInBytes -= (int)blockSizeDownload;
      // Increment the offset to start at the beginning of the next block.
      offset += blockSizeDownload;
}

return (fileBytes.ToArray(), fileName);
}

Más información:

Límites de tamaño de archivo

La columna Organization.MaxUploadFileSize especifica el tamaño máximo permitido de un archivo en bytes para un archivo adjunto y una nota, y otros tipos de datos, como los archivos de recursos web que se utilizan para modelar. aplicaciones impulsadas. El límite máximo de tamaño de archivo de carga se aplica al tamaño del archivo en codificación Base64. Una codificación Base64 produce una cadena que es más grande que los datos del archivo byte[] original.

El tamaño predeterminado es 5 MB (5242880 bytes) y el valor máximo es 128 MB (131072000 bytes) y se puede establecer en la configuración de correo electrónico del entorno. Más información: Administrar la configuración de correo electrónico

Si intenta cargar un archivo que es demasiado grande, obtendrá el siguiente error:

Nombre: unManagedidsattachmentinvalidfilesize
Código: 0x80044a02
Número: -2147202558
Mensaje: Attachment file size is too big.

Recuperar el tamaño máximo de archivo de carga

Puede recuperar el tamaño máximo del archivo de carga de varias maneras.

Utilice un método estático como el siguiente GetMaxUploadFileSize para obtener el valor.

public static int GetMaxUploadFileSize(IOrganizationService service) {

   QueryExpression query = new("organization") { 
         ColumnSet = new ColumnSet("maxuploadfilesize")
   };

   EntityCollection organizations = service.RetrieveMultiple(query);

   // There is only one row in organization table
   return (int)organizations.Entities.FirstOrDefault()["maxuploadfilesize"];
}

Más información:

Cambiar el tamaño máximo de archivo de carga

Puede establecer el valor organization.maxuploadfilesize de varias maneras.

Utilice un método estático como el siguiente SetMaxUploadFileSize para establecer el tamaño máximo del archivo de carga.

public static void SetMaxUploadFileSize(
    IOrganizationService service, 
    int maxUploadFileSizeInBytes)
{
   if (maxUploadFileSizeInBytes > 131072000 || maxUploadFileSizeInBytes < 1) {
         throw new ArgumentOutOfRangeException(nameof(maxUploadFileSizeInBytes), 
         "The maxUploadFileSizeInBytes parameter must be less than 131072000 bytes and greater than 0 bytes.");
   }

   QueryExpression query = new("organization")
   {
         ColumnSet = new ColumnSet("organizationid")
   };

   EntityCollection organizations = service.RetrieveMultiple(query);

   // There is only one row in organization table
   Entity organization = organizations.Entities.FirstOrDefault();
   organization["maxuploadfilesize"] = maxUploadFileSizeInBytes;

   service.Update(organization);
}

Más información:

Consulte también

Información general sobre imágenes y archivos
Ejemplo: operaciones de archivo con archivos adjuntos y notas mediante el Dataverse SDK para .NET
Ejemplo: operaciones con archivos adjuntos y anotaciones utilizando la API web de Dataverse

Nota

¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)

La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).