ASP .NET Core Importar y Exportar un Archivo Word
Esta guía explora cómo importar documentos de Word existentes, mostrar su contenido y crear documentos desde cero utilizando la biblioteca IronWord. Al final de este tutorial, habrás creado una aplicación web ASP.NET Core que puede:
- Cargar y leer documentos de Word
- Mostrar el contenido de estos documentos en un cuadro de texto
- Exportar el archivo Docx
Este proyecto es perfecto para desarrolladores que necesitan integrar el procesamiento de documentos de Word en sus aplicaciones web, ya sea para sistemas de gestión de documentos, generadores de informes o cualquier otro escenario que involucre archivos de Microsoft Word.
Requisitos previos
Para seguir este tutorial, debes tener:
- Conocimientos básicos de C# y ASP.NET Core
- Visual Studio 2019 o posterior instalado (alternativamente, puedes usar Visual Studio Code con la extensión C#)
- .NET Core SDK 3.1 o posterior
No te preocupes si no eres un experto en estas tecnologías, ¡te guiaremos en cada paso del proceso!
¿Qué es IronWord?
IronWord es una biblioteca .NET que permite a los desarrolladores leer, manipular y crear documentos de Microsoft Word programáticamente. Proporciona una API de alto nivel que simplifica el trabajo con archivos de Word, lo que la convierte en una excelente opción para nuestro proyecto.
Algunas características clave de IronWord incluyen:
- Leer y escribir varios formatos de Word (DOCX, DOC, etc.)
- Manipular el contenido y la estructura del documento
- Formatear texto y párrafos
- Trabajar con tablas, imágenes y otros elementos del documento
- Proceso de combinación de correspondencia para documentos
- Convertir un documento de Word a un documento PDF con facilidad, lo que te permite tomar tus documentos finales de Word y convertirlos en archivos PDF fáciles de compartir
Ahora que tenemos una visión general de lo que estamos construyendo y las herramientas que utilizaremos, ¡vamos a sumergirnos en la configuración de nuestro proyecto!
2. Configuración del proyecto
En esta sección, crearemos un nuevo proyecto ASP.NET Core e instalaremos los paquetes necesarios para trabajar con IronWord.
2.1 Creación de un nuevo proyecto ASP.NET Core
- Abre Visual Studio 2019 o posterior.
- Haz clic en "Crear un nuevo proyecto".
- Busca "Aplicación Web ASP.NET Core" y selecciónala.
- Haz clic en "Siguiente".
- Nombra tu proyecto "WordDocumentProcessor" (o cualquier nombre que prefieras).
- Selecciona el .NET Framework y una ubicación para tu proyecto y haz clic en "Crear".
2.2 Instalación del paquete NuGet de IronWord
Ahora que tenemos nuestro proyecto configurado, agreguemos la biblioteca IronWord:
- Haz clic derecho en tu proyecto en el Explorador de Soluciones.
- Selecciona "Administrar paquetes NuGet".
- En la pestaña "Explorar", busca "IronWord".
- Busca el paquete oficial de IronWord.
- Haz clic en "Instalar" para agregarlo a tu proyecto.
2.3 Actualización del controlador y la vista existentes
Vamos a actualizar nuestra estructura existente para incorporar la funcionalidad de procesamiento de documentos:
- Usaremos el HomeController.cs existente en la carpeta de Controladores para nuestra lógica de procesamiento de documentos.
- Actualizaremos la vista Index.cshtml existente en la carpeta Views/Home para incluir la funcionalidad de carga y visualización de documentos.
Ahora que tenemos nuestro proyecto configurado y el paquete IronWord instalado, estamos listos para comenzar a implementar la funcionalidad de importación y exportación de documentos. Agregaremos nuevos métodos a nuestro HomeController y modificaremos la vista Index para manejar estas características. En la siguiente sección, nos centraremos en la importación de documentos de Word y la visualización de su contenido, utilizando nuestra estructura de controlador y vista existente.
3. Importación de documentos de Word
En esta sección, exploraremos cómo implementar una característica para importar y procesar documentos de Word en una aplicación ASP.NET MVC. Cubriremos tanto el diseño de la interfaz de usuario como la lógica de controlador de back-end.
3.1 Diseño de la interfaz de usuario
La interfaz de usuario para importar documentos de Word está diseñada para ser intuitiva y visualmente atractiva. Desglosaremos los componentes clave de la IU:
3.1.1 Área de carga
El área de carga es el punto focal de la interfaz, invitando a los usuarios a seleccionar y cargar sus documentos de Word. Así es como está estructurada:
<div class="upload-area">
<svg class="file-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
<p>Choose a Word document</p>
<label for="fileInput" class="choose-file">Choose File</label>
<p class="file-info">.DOC or .DOCX (MAX. 10MB)</p>
<button id="uploadBtn" class="upload-button">Upload and Process</button>
</div><div class="upload-area">
<svg class="file-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"></path>
<polyline points="14 2 14 8 20 8"></polyline>
<line x1="16" y1="13" x2="8" y2="13"></line>
<line x1="16" y1="17" x2="8" y2="17"></line>
<polyline points="10 9 9 9 8 9"></polyline>
</svg>
<p>Choose a Word document</p>
<label for="fileInput" class="choose-file">Choose File</label>
<p class="file-info">.DOC or .DOCX (MAX. 10MB)</p>
<button id="uploadBtn" class="upload-button">Upload and Process</button>
</div>Este código crea un área de carga visualmente atractiva con un ícono de archivo, una entrada de archivo oculta y una etiqueta estilizada que actúa como botón de selección de archivo. También incluye información sobre los tipos de archivo aceptados y un botón para iniciar la carga y el procesamiento.
3.1.2 Área de visualización de contenido
Después de procesar el documento, su contenido se muestra en un área dedicada:
<div class="content-wrapper">
<h2>Document Content:</h2>
<div id="documentContent" class="content-area">
No content to display.
</div>
</div><div class="content-wrapper">
<h2>Document Content:</h2>
<div id="documentContent" class="content-area">
No content to display.
</div>
</div>Esta sección proporciona un área desplazable para mostrar el contenido del documento procesado.
3.2 Implementación del controlador
El HomeController maneja la lógica del lado del servidor para importar y procesar documentos de Word. Examinemos los métodos clave:
3.2.1 Método UploadAndProcess
Este método es responsable de manejar la carga y el procesamiento del archivo:
[HttpPost]
public IActionResult UploadAndProcess(IFormFile file)
{
if (file == null || file.Length == 0)
{
return Json(new { success = false, message = "No file uploaded." });
}
var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (fileExtension != ".doc" && fileExtension != ".docx")
{
return Json(new { success = false, message = "Invalid file type. Please upload a .doc or .docx file." });
}
try
{
var tempFilePath = Path.GetTempFileName();
using (var stream = new FileStream(tempFilePath, FileMode.Create))
{
file.CopyTo(stream);
}
StringBuilder contentBuilder = new StringBuilder();
WordDocument doc = new WordDocument(tempFilePath);
foreach (Paragraph paragraph in doc.Paragraphs)
{
foreach (Text textRun in paragraph.Texts)
{
contentBuilder.AppendLine(textRun.Text);
}
contentBuilder.AppendLine(); // Add an extra line between paragraphs
}
System.IO.File.Delete(tempFilePath); // Clean up the temporary file
return Json(new { success = true, content = FormatContentAsHtml(contentBuilder.ToString()) });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing document");
return Json(new { success = false, message = "An error occurred while processing the document." });
}
}[HttpPost]
public IActionResult UploadAndProcess(IFormFile file)
{
if (file == null || file.Length == 0)
{
return Json(new { success = false, message = "No file uploaded." });
}
var fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant();
if (fileExtension != ".doc" && fileExtension != ".docx")
{
return Json(new { success = false, message = "Invalid file type. Please upload a .doc or .docx file." });
}
try
{
var tempFilePath = Path.GetTempFileName();
using (var stream = new FileStream(tempFilePath, FileMode.Create))
{
file.CopyTo(stream);
}
StringBuilder contentBuilder = new StringBuilder();
WordDocument doc = new WordDocument(tempFilePath);
foreach (Paragraph paragraph in doc.Paragraphs)
{
foreach (Text textRun in paragraph.Texts)
{
contentBuilder.AppendLine(textRun.Text);
}
contentBuilder.AppendLine(); // Add an extra line between paragraphs
}
System.IO.File.Delete(tempFilePath); // Clean up the temporary file
return Json(new { success = true, content = FormatContentAsHtml(contentBuilder.ToString()) });
}
catch (Exception ex)
{
_logger.LogError(ex, "Error processing document");
return Json(new { success = false, message = "An error occurred while processing the document." });
}
}<HttpPost>
Public Function UploadAndProcess(ByVal file As IFormFile) As IActionResult
If file Is Nothing OrElse file.Length = 0 Then
Return Json(New With {
Key .success = False,
Key .message = "No file uploaded."
})
End If
Dim fileExtension = Path.GetExtension(file.FileName).ToLowerInvariant()
If fileExtension <> ".doc" AndAlso fileExtension <> ".docx" Then
Return Json(New With {
Key .success = False,
Key .message = "Invalid file type. Please upload a .doc or .docx file."
})
End If
Try
Dim tempFilePath = Path.GetTempFileName()
Using stream = New FileStream(tempFilePath, FileMode.Create)
file.CopyTo(stream)
End Using
Dim contentBuilder As New StringBuilder()
Dim doc As New WordDocument(tempFilePath)
For Each paragraph As Paragraph In doc.Paragraphs
For Each textRun As Text In paragraph.Texts
contentBuilder.AppendLine(textRun.Text)
Next textRun
contentBuilder.AppendLine() ' Add an extra line between paragraphs
Next paragraph
System.IO.File.Delete(tempFilePath) ' Clean up the temporary file
Return Json(New With {
Key .success = True,
Key .content = FormatContentAsHtml(contentBuilder.ToString())
})
Catch ex As Exception
_logger.LogError(ex, "Error processing document")
Return Json(New With {
Key .success = False,
Key .message = "An error occurred while processing the document."
})
End Try
End FunctionEste método realiza las siguientes tareas:
- Valida el archivo cargado, asegurándose de que esté en el formato de archivo correcto (DOC o DOCX).
- Procesa el documento utilizando la biblioteca IronWord.
- Devuelve el contenido formateado como JSON.
3.2.2 Método FormatContentAsHtml
Este método privado formatea el contenido extraído en HTML:
private string FormatContentAsHtml(string content)
{
var lines = content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
var htmlBuilder = new StringBuilder();
htmlBuilder.Append("<div class='document-content'>");
foreach (var line in lines)
{
if (string.IsNullOrWhiteSpace(line))
{
htmlBuilder.Append("<p> </p>");
}
else
{
htmlBuilder.Append($"<p>{HttpUtility.HtmlEncode(line)}</p>");
}
}
htmlBuilder.Append("</div>");
return htmlBuilder.ToString();
}private string FormatContentAsHtml(string content)
{
var lines = content.Split(new[] { Environment.NewLine }, StringSplitOptions.None);
var htmlBuilder = new StringBuilder();
htmlBuilder.Append("<div class='document-content'>");
foreach (var line in lines)
{
if (string.IsNullOrWhiteSpace(line))
{
htmlBuilder.Append("<p> </p>");
}
else
{
htmlBuilder.Append($"<p>{HttpUtility.HtmlEncode(line)}</p>");
}
}
htmlBuilder.Append("</div>");
return htmlBuilder.ToString();
}Private Function FormatContentAsHtml(ByVal content As String) As String
Dim lines = content.Split( { Environment.NewLine }, StringSplitOptions.None)
Dim htmlBuilder = New StringBuilder()
htmlBuilder.Append("<div class='document-content'>")
For Each line In lines
If String.IsNullOrWhiteSpace(line) Then
htmlBuilder.Append("<p> </p>")
Else
htmlBuilder.Append($"<p>{HttpUtility.HtmlEncode(line)}</p>")
End If
Next line
htmlBuilder.Append("</div>")
Return htmlBuilder.ToString()
End FunctionEste método asegura que el contenido del documento esté correctamente formateado como HTML, con cada línea envuelta en etiquetas de párrafo y líneas vacías preservadas.
3.3 JavaScript del lado del cliente
Para manejar la carga del archivo y mostrar el contenido procesado, usamos JavaScript:
uploadBtn.addEventListener('click', () => {
const file = fileInput.files[0];
if (!file) {
alert('Please select a file first.');
return;
}
const formData = new FormData();
formData.append('file', file);
uploadBtn.disabled = true;
uploadBtn.textContent = 'Processing...';
documentContent.innerHTML = 'Processing document...';
fetch('/Home/UploadAndProcess', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
documentContent.innerHTML = data.content;
} else {
documentContent.innerHTML = `<p>Error: ${data.message}</p>`;
}
})
.catch(error => {
console.error('Error:', error);
documentContent.innerHTML = '<p>An error occurred while processing the document.</p>';
})
.finally(() => {
uploadBtn.disabled = false;
uploadBtn.textContent = 'Upload and Process';
});
});uploadBtn.addEventListener('click', () => {
const file = fileInput.files[0];
if (!file) {
alert('Please select a file first.');
return;
}
const formData = new FormData();
formData.append('file', file);
uploadBtn.disabled = true;
uploadBtn.textContent = 'Processing...';
documentContent.innerHTML = 'Processing document...';
fetch('/Home/UploadAndProcess', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
documentContent.innerHTML = data.content;
} else {
documentContent.innerHTML = `<p>Error: ${data.message}</p>`;
}
})
.catch(error => {
console.error('Error:', error);
documentContent.innerHTML = '<p>An error occurred while processing the document.</p>';
})
.finally(() => {
uploadBtn.disabled = false;
uploadBtn.textContent = 'Upload and Process';
});
});Este código JavaScript maneja el proceso de carga del archivo, envía el archivo al servidor para su procesamiento y actualiza la interfaz de usuario con el contenido procesado o mensajes de error.
3.4 Estilo de la interfaz de usuario
La aplicación utiliza CSS personalizado para crear una interfaz atractiva y fácil de usar.
<style>
body {
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
background-color: #f7f7f7;
color: #333;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 2rem;
padding-top: 0.5rem;
}
h1 {
font-weight: 300;
color: #2c3e50;
text-align: center;
margin-bottom: 1rem;
}
.lead {
text-align: center;
color: #7f8c8d;
margin-bottom: 2rem;
}
.upload-area {
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 2rem;
text-align: center;
margin-bottom: 2rem;
transition: all 0.3s ease;
}
.upload-area:hover {
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
}
.file-icon {
width: 64px;
height: 64px;
margin-bottom: 1rem;
color: #3498db;
}
.choose-file {
background-color: #ecf0f1;
color: #2c3e50;
border: none;
padding: 0.5rem 1rem;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.choose-file:hover {
background-color: #d5dbdb;
}
.file-info {
font-size: 0.9em;
color: #95a5a6;
margin-top: 0.5rem;
}
.upload-button {
background-color: #3498db;
color: white;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s ease;
margin-top: 1rem;
}
.upload-button:hover {
background-color: #2980b9;
}
.content-wrapper {
background-color: #ffffff;
border-radius: 8px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
padding: 1rem;
margin-top: 2rem;
}
.content-area {
max-height: 300px;
overflow-y: auto;
padding: 1rem;
background-color: #f9f9f9;
border-radius: 4px;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
font-size: 14px;
line-height: 1.6;
}
.content-area::-webkit-scrollbar {
width: 8px;
}
.content-area::-webkit-scrollbar-track {
background: #f1f1f1;
border-radius: 4px;
}
.content-area::-webkit-scrollbar-thumb {
background: #bdc3c7;
border-radius: 4px;
}
.content-area::-webkit-scrollbar-thumb:hover {
background: #95a5a6;
}
.document-content p {
margin: 0 0 10px 0;
}
</style>Este CSS crea un aspecto limpio y moderno con una paleta de colores claros. El área de carga presenta un fondo blanco con efectos de sombra sutiles, mientras que el área de contenido tiene un diseño desplazable con un fondo gris claro. El uso de propiedades de border-radius y box-shadow añade profundidad e interés visual a los elementos de la interfaz.
4. Exportación de documentos de Word
A medida que continuamos mejorando nuestro Procesador de Documentos de Word, agreguemos la capacidad de exportar documentos. Esta función permitirá a los usuarios generar un nuevo documento de Word desde nuestra aplicación.
4.1 Actualización de la interfaz de usuario
Primero, agregaremos una opción de "Exportar" a nuestra barra de navegación. Abre el archivo _Layout.cshtml en la carpeta Views/Shared y localiza el elemento . Agreguemos un nuevo elemento de lista para nuestra función de exportación:
<li class="nav-item">
<a class="nav-link" id="exportLink" href="#" onclick="exportDocument(); return false;"><i class="fas fa-file-export"></i> Export</a>
</li><li class="nav-item">
<a class="nav-link" id="exportLink" href="#" onclick="exportDocument(); return false;"><i class="fas fa-file-export"></i> Export</a>
</li>Estamos usando Font Awesome para el ícono, así que asegúrate de tener el enlace CSS en nuestra sección
. Este código agrega un enlace "Exportar" a la barra de navegación. Utiliza Font Awesome para el ícono y llama a la función exportDocument() al hacer clic. El href="#" y return false previenen el comportamiento predeterminado del enlace.4.2 Implementación de la lógica de exportación del lado del cliente
Ahora, agreguemos la función JavaScript que manejará el proceso de exportación. Al final de nuestro archivo _Layout.cshtml, justo antes de la etiqueta de cierre













