Para almacenar diferentes tipos de archivos (imágenes, documentos, PDFs) en una base de datos relacional, es necesario definir una tabla que pueda contener los metadatos y el contenido en formato binario. Se recomeinda una estructura con las siguientes columnas:
- NombreArchivo: Almacena el nombre original del documento.
- TipoMIME: Guarda el tipo de contenido (por ejemplo, application/pdf, image/png).
- DatosBinarios: Campo de tipo
varbinary(max)para guardar el archivo como un arreglo de bytes.
En la capa de presentación de una aplicación ASP.NET Web Forms, se requiere un control de carga de archivos, un botón de envío y una etiqueta para mostrar el resultado de la operación:
<asp:FileUpload ID="CargadorArchivos" runat="server" />
<asp:Button ID="BtnGuardar" runat="server" Text="Guardar Documento" OnClick="BtnGuardar_Click" />
<br />
<asp:Label ID="MsgEstado" runat="server"></asp:Label>
En el código subyacente, se procesa el archivo recibido, se determina su tipo MIME y se prepara para la inserción. Una forma eficiente y escalable de mapear extensiones a tipos MIME, en lugar de una estructura switch, es mediante un diccionario estático:
private static readonly Dictionary<string, string> MapeoMime = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
{
{ ".pdf", "application/pdf" },
{ ".docx", "application/vnd.openxmlformats-officedocument.wordprocessingml.document" },
{ ".xlsx", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet" },
{ ".jpg", "image/jpeg" },
{ ".png", "image/png" }
};
protected void BtnGuardar_Click(object sender, EventArgs e)
{
if (CargadorArchivos.HasFile)
{
string nombreDoc = Path.GetFileName(CargadorArchivos.FileName);
string extension = Path.GetExtension(nombreDoc);
if (MapeoMime.TryGetValue(extension, out string tipoContenido))
{
byte[] bufferArchivo;
using (Stream flujoEntrada = CargadorArchivos.PostedFile.InputStream)
{
bufferArchivo = new byte[flujoEntrada.Length];
flujoEntrada.Read(bufferArchivo, 0, bufferArchivo.Length);
}
string consultaSql = "INSERT INTO Documentos (NombreArchivo, TipoMIME, DatosBinarios) VALUES (@Nombre, @Tipo, @Datos)";
using (SqlCommand comando = new SqlCommand(consultaSql))
{
comando.Parameters.AddWithValue("@Nombre", nombreDoc);
comando.Parameters.AddWithValue("@Tipo", tipoContenido);
comando.Parameters.AddWithValue("@Datos", bufferArchivo);
if (PersistirDatos(comando))
{
MsgEstado.ForeColor = System.Drawing.Color.Green;
MsgEstado.Text = "El archivo se almacenó correctamente en la base de datos.";
}
}
}
else
{
MsgEstado.ForeColor = System.Drawing.Color.Red;
MsgEstado.Text = "Formato no soportado. Intente con PDF, Word, Excel o imágenes.";
}
}
}
La persistencia en la base de datos se maneja mediante ADO.NET, utilizando bloques using para garantizar la correcta libearción de recursos de la conexión y el comando, evitando así fugas de memoria:
private bool PersistirDatos(SqlCommand cmd)
{
string cadenaConexion = ConfigurationManager.ConnectionStrings["MiCadenaBD"].ConnectionString;
using (SqlConnection conexion = new SqlConnection(cadenaConexion))
{
cmd.Connection = conexion;
cmd.CommandType = CommandType.Text;
try
{
conexion.Open();
cmd.ExecuteNonQuery();
return true;
}
catch (Exception ex)
{
// Registrar la excepción (ex.Message) según la estrategia de logging
return false;
}
}
}