Estrenamos blog: te contamos lo que hacemos de forma más rápida, cercana y transparente.
DinaupBlog
← Volver al blog

Conecta tu app .NET a Dinaup: guía del SDK

Conecta tu aplicación .NET a Dinaup: conexión asíncrona, informes tipados, escritura con WriteOperation y subida de archivos. Con código que compila.

Equipo Dinaup1 de octubre de 20246 min de lectura

Tus datos ya están en Dinaup. No necesitas otro backend encima.

El SDK .NET conecta tu aplicación a la misma infraestructura que ya usas. Consultas informes, escribes registros y subes archivos. Tú pones la lógica y la interfaz. El backend, el almacenamiento y la seguridad ya están resueltos.

Esta guía te deja operativo con código real y firmas reales.

Qué te ahorras

  • No mantienes ningún servidor. Dinaup gestiona el backend. Tú escribes la app.
  • Los secretos viven fuera del código con VaultData. Las credenciales están en el Vault, no en el código ni en appsettings.
  • Trabajas con datos tipados. Tu modelo (secciones, informes, documentos) viaja en un paquete MyDinaup con los nombres reales de tu organización. Tienes autocompletado y errores en tiempo de compilación, no en producción. Cómo funciona ese modelo por dentro: El SDK .NET de Dinaup: dos paquetes, y uno es tuyo.

Antes de empezar: la clave API

La conexión se autentica con una clave API vinculada a un usuario. La clave hereda los permisos de ese usuario: lee y escribe solo lo que el usuario puede ver y editar, y cada acción queda en la auditoría a su nombre.

Genera la clave en el Panel de administración → Claves APICrear clave API. Asóciala a un usuario con los permisos mínimos que necesite tu integración. La clave se muestra una sola vez: guárdala. Tienes el detalle en Claves API.

Instala los paquetes

Necesitas dos: el cliente base y el modelo tipado de tu organización.

dotnet add package Dinaup
dotnet add package Demoup.MyDinaup

Demoup.MyDinaup es el modelo de pre-producción del equipo Dinaup: vale para probar, no para producción. Qué MyDinaup usar en cada caso y cómo se regenera el tuyo: El SDK .NET de Dinaup: dos paquetes, y uno es tuyo.

Conecta

La conexión es asíncrona y pide tres credenciales: el endpoint de tu instancia, una clave pública y una secreta. ConnectAsync devuelve el cliente conectado, o null si algo falla. Comprueba siempre IsConnected.

using Dinaup;

var client = await DinaupClientC.ConnectAsync(
    endPoint: "https://api.dinaup.com/v2/tu-codigo",
    publicKey: "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    secretKey: "tu-secret-key-aqui"
);

if (client == null || client.IsConnected == false)
    throw new Exception("No se pudo conectar a Dinaup");

No pongas las claves en el código. Léelas del Vault. En variables de entorno solo viven la URL del Vault y su contraseña.

using Dinaup;

var vault = new VaultData(
    Environment.GetEnvironmentVariable("VAULT_URL"),
    Environment.GetEnvironmentVariable("VAULT_PASSWORD")
);
vault.Initialize();

var client = await DinaupClientC.ConnectAsync(
    endPoint: vault.Read("dinaup.endpoint"),
    publicKey: vault.Read("dinaup.publickey"),
    secretKey: vault.Read("dinaup.secretkey")
);

if (client == null || client.IsConnected == false)
    throw new Exception("No se pudo conectar a Dinaup");

En una API o app web, conecta una sola vez al arrancar y registra el cliente como Singleton: builder.Services.AddSingleton(client);. No reconectes en cada request.

Lee datos con Informes

Los Informes son consultas predefinidas y tipadas. Son la forma recomendada de leer. Viven en {Empresa}.MyDinaup.Reports.{Categoria} y siguen la convención API + NombreDeSeccion + C. Creas la clase, ejecutas la consulta paginada y recorres Rows.

using DemoUp.MyDinaup.Reports.VentasD;

var ventas = new APIVentasC();
await ventas.ExecuteQueryAsync(client, page: 1, resultsPerPage: 50);

Console.WriteLine($"Total: {ventas.TotalResults} registros");

foreach (var fila in ventas.Rows)
    Console.WriteLine($"- {fila.NumerodefacturaCompleto}: {fila.Total}");

Para muchos resultados, pagina con ExecuteQuery_NextPageAsync. Devuelve false cuando no quedan más páginas.

var ventas = new APIVentasC();
await ventas.ExecuteQueryAsync(client, page: 1, resultsPerPage: 300);

if (ventas.Rows.IsNotEmpty())
{
    do
    {
        foreach (var fila in ventas.Rows)
        {
            // procesa la fila
        }
    } while (await ventas.ExecuteQuery_NextPageAsync());
}

Filtrar es igual de directo. Llama a AddFilter(campo, operador, valor) antes de ejecutar:

var ventas = new APIVentasC();
ventas.AddFilter(VentasES.ValorEntero, "=", 3);
await ventas.ExecuteQueryAsync(client, page: 1, resultsPerPage: 10);

También tienes filtros por rango (AddFilterBetween), solapamiento de fechas (AddFilterDateRangeOverlapFilter) y filtros sobre datos relacionados. Todos en la doc del cliente.

Para casos puntuales o prototipos también tienes MyDinaup.SectionsD (lectura por Id o por criterios). Recupera todos los datos relacionados de cada fila y cuesta más. En producción, usa Informes.

Escribe con WriteOperation

Toda alta o edición pasa por un WriteOperation: un diccionario campo → valor y un Id que decide la intención.

  • Id vacío ("") → alta. El servidor asigna el Id.
  • Id válido → edición.
  • Id que no existe → excepción.

Ejecutas con RunWriteOperationAsync, validas con EnsureSuccess() (lanza excepción si falló) y solo entonces lees el resultado.

var data = new Dictionary<string, string>
{
    { SeccionDePruebasAPIES.TextoPrincipal, $"Prueba {Guid.NewGuid()}" }
};

var wOp = new WriteOperation("", data); // "" => alta

await client.RunWriteOperationAsync(SeccionDePruebasAPIES._SectionIDGUID, wOp, false);

wOp.EnsureSuccess(); // excepción si la operación falló
Guid nuevoId = wOp.WriteOperationResult.RowID;
var data = new Dictionary<string, string>
{
    { SeccionDePruebasAPIES.TextoPrincipal, $"Editado {DateTime.UtcNow.Ticks}" }
};

var wOp = new WriteOperation(rowId, data); // Id válido => edición

await client.RunWriteOperationAsync(SeccionDePruebasAPIES._SectionIDGUID, wOp, false);

wOp.EnsureSuccess();
Guid editadoId = wOp.WriteOperationResult.RowID;

El Id de sección es un Guid: usa _SectionIDGUID, no _SectionID (que es string). Lee WriteOperationResult.RowID solo después de EnsureSuccess(). Antes puede ser nulo.

El tercer parámetro de RunWriteOperationAsync activa la escritura virtualizada: con true corre la lógica de negocio de la sección (scripts, recálculos, validaciones), con false solo persiste los valores. Regla rápida: true para registrar una venta, false para cambiar un estado o una nota. La comparativa de los dos modos, en el post del SDK.

Por lotes

Una sola llamada admite varias operaciones, hasta 25 (MaxItemsPerWriteOperation). Para más, trocea con .Chunk(25).

var operaciones = new List<WriteOperation>();

for (int i = 0; i < 10; i++)
{
    var fila = new Dictionary<string, string>
    {
        { SeccionDePruebasAPIES.TextoPrincipal, $"Lote {i}: {Guid.NewGuid()}" }
    };
    operaciones.Add(new WriteOperation("", fila));
}

var batch = await client.RunWriteOperationAsync(SeccionDePruebasAPIES._SectionIDGUID, operaciones, false);
batch.EnsureSuccess();

var ids = operaciones
    .Where(o => o.WriteOperationResult != null)
    .Select(o => o.WriteOperationResult.RowID)
    .ToList();

Sube archivos y genera URLs firmadas

Subes desde un array de bytes (o desde una URL con File_UploadURLAsync) y recuperas el FileId. Para servir el archivo, pides una URL firmada de lectura con File_SignURLGetAsync.

var bytes = System.Text.Encoding.UTF8.GetBytes("hola " + Guid.NewGuid());

var upload = await client.File_UploadBytesAsync(bytes, "prueba.txt");
Guid fileId = upload.FileId;

var signed = await client.File_SignURLGetAsync(fileId);
var url = signed.url_original; // URL lista para consumir

Si subes el mismo archivo a menudo, calcula el SHA1 en cliente con Dinaup.extensions.ToSHA1(bytes) y consúltalo antes de subir. Ahorras almacenamiento y ancho de banda.

Lo que no hemos cubierto

El cliente hace más cosas:

  • Anotaciones por registro con Annotation_PutAsync: comentarios tipo chat, galería pública en CDN y archivos privados asociados.
  • Documentos dinámicos para orquestar varias consultas en una llamada o generar documentos de impresión, como facturas y albaranes.
  • Filtros avanzados: rangos, solapamiento de fechas y relaciones entre secciones.

Lo tienes todo en la guía completa del cliente.

Siguiente paso

Tienes la referencia completa —firmas, ejemplos y casos reales— en la documentación oficial:

Sigue leyendo