Plugin Convertidor
Convertir documentos a 24 formatos de destino
El plugin Converter convierte a Doconut en un servicio de conversión de documentos. Contribuye con el motor detrás de la fachada pública DocumentConverter y — opcionalmente — un widget listo para usar servido por DocImage.axd, de modo que pueda convertir documentos desde C#, desde el widget, o desde una interfaz frontal que usted mismo escriba.
Instalar el paquete
Install-Package Doconut.NETFramework.ConverterMantenga el paquete Converter en la misma versión que Doconut.NETFramework.
Registrar el plugin
Cada plugin se registra de la misma manera: AddPlugin<TPlugin>() en DoconutHost.Initialize.
Doconut.DoconutHost.Initialize(options =>
{
options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});Si ninguna licencia activa otorga la capacidad
Converter— sin licencia, un archivo legadoTRIAL, o una licencia que no la incluya —DoconutHost.Initializelanza una excepción desdeApplication_Start. En System.Web eso significa que cada solicitud responde con un500vacío, y la razón solo aparece en el registro de eventos de Windows (fuente ASP.NET). Se aceptan licencias temporales Demo/NFR. Consulte Configuración de Licencia.
Convertir desde C#
Cada conversión devuelve un MemoryStream buscable posicionado en 0. DocumentConverter es sin estado: resuélvalo desde DoconutHost.Services donde lo necesite y reutilícelo libremente.
// Resolve DocumentConverter from DoconutHost.Services; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);// sourceExtension includes the leading dot. password is null unless the document is protected.
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);Stream html = await converter.WordToHtmlAsync("report.docx", ct);Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);Dos detalles que es fácil equivocarse: sourceExtension en la sobrecarga de stream debe incluir el punto inicial (".xlsx", no "xlsx"), de lo contrario no se resuelve. Y a pesar de su nombre, WordToHtmlAsync devuelve Task<Stream>, no Task<string> — el documento HTML (imágenes incrustadas como Base64) llega como un stream, como cualquier otro resultado.
En un controlador MVC 5
Haga que la acción sea asíncrona y await la conversión:
[HttpPost]
public async Task<ActionResult> ToPdf(HttpPostedFileBase file)
{
var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
Stream pdf = await converter.ConvertAsync(
file.InputStream, Path.GetExtension(file.FileName), ConversionTarget.Pdf,
password: null, ct: Response.ClientDisconnectedToken);
return File(pdf, "application/pdf", Path.GetFileNameWithoutExtension(file.FileName) + ".pdf");
}En Web Forms: nunca bloquee una conversión
Una página de Web Forms se ejecuta en un contexto de solicitud de un solo hilo. ConvertAsync se reanuda en ese contexto cuando finaliza, por lo que una página que lo espera de forma síncrona — .Result, .Wait(), .GetAwaiter().GetResult() — retiene el propio hilo que la conversión necesita para terminar. La solicitud nunca regresa. El navegador sigue girando, IIS no registra nada, y el resto del sitio sigue funcionando, por lo que parece una conversión lenta en lugar de un deadlock.
Marque la página Async="true" y ejecute la conversión como una tarea asíncrona de la página:
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>// Web Forms: the @Page directive needs Async="true", and the conversion runs as a page async task.
// Blocking on it instead (.Result, .Wait(), .GetAwaiter().GetResult()) deadlocks the request:
// it never returns, and nothing is logged.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) return;
RegisterAsyncTask(new PageAsyncTask(async ct =>
{
var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
using (var pdf = await converter.ConvertAsync(
Server.MapPath("~/App_Data/contract.docx"), ConversionTarget.Pdf, ct: ct))
using (var ms = new MemoryStream())
{
if (pdf.CanSeek) pdf.Position = 0;
await pdf.CopyToAsync(ms);
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment; filename=contract.pdf");
Response.BinaryWrite(ms.ToArray());
// Context, not HttpContext.Current: after an await the latter can be null.
Context.ApplicationInstance.CompleteRequest();
}
}));
}Sin Async="true" en la directiva @Page, RegisterAsyncTask se ignora silenciosamente. Después de un await, use el Context de la página; HttpContext.Current puede ser null allí.
Formatos de destino
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, WebpNo todas las fuentes se convierten a todos los destinos: la familia de formatos de cada fuente (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, web document) tiene su propio conjunto de destinos permitidos. No codifiques este enum como la lista de destinos de tu UI: ?convert=open devuelve los allowedTargets para el archivo subido, y eso es lo que debe impulsar un selector.
Widget incrustable
Los endpoints ?convert=open|run|download del widget son servidos por DocImage.axd y están desactivados por defecto. Habilítalos junto al registro del plugin:
Doconut.DoconutHost.Initialize(options =>
{
options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
options.AddConverterWidget(widget =>
{
widget.MaxUploadMb = 25;
});
});
// System.Web reads the whole upload before Doconut sees it: keep maxRequestLength (KB) and
// maxAllowedContentLength (bytes) in Web.config above the widget's MaxUploadMb.<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
Doconut.convert('#doconut-convert', { basePath: '/DocImage.axd', maxUploadMb: 25 });
</script>Dos cosas a comprobar cuando el widget se comporta de forma errónea:
basePath: '/DocImage.axd'. El valor predeterminado del widget,/doconut, es el endpoint de ASP.NET Core. En este paquete, los endpoints son el controladorDocImage.axddeWeb.config.- El script y los endpoints son independientes. El módulo de recursos sirve
doconutConverter.jstanto si el widget está habilitado como si no. SinAddConverterWidget(), el widget se carga, pinta su zona de arrastre y parece completamente correcto — y su primera acción responde404.
Límites de carga
ASP.NET lee todo el cuerpo de la solicitud antes de que se ejecute DocImage.axd. Una carga superior a MaxUploadMb pero por debajo de los límites del host devuelve el propio JSON 413 del widget ("File is too large."). Una carga superior a los límites del host es rechazada primero por IIS, con una página de error que el widget no puede leer. Mantén ambos límites del host en Web.config por encima del límite del widget:
<system.web>
<httpRuntime maxRequestLength="30720" /> <!-- KILOBYTES: 30 MB -->
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="31457280" /> <!-- BYTES: 30 MB -->
</requestFiltering>
</security>
</system.webServer>Personalizar el widget
Opciones pasadas a Doconut.convert(selector, options):
| Opción | Tipo | Predeterminado | Notas |
|---|---|---|---|
basePath | string | /doconut | La URL del endpoint. Establece '/DocImage.axd' en este paquete |
resPath | string | /doconut-res | Aceptado por consistencia con otros widgets Doconut; el widget de conversión no construye ninguna URL a partir de él |
maxUploadMb | number | 25 | Solo verificación previa del lado del cliente; el servidor impone su propio límite |
licenseUrl | string | null | null | Convierte el aviso de marca de agua en la pantalla de resultados en un enlace |
labels | object | {} | Sobrescribe cualquier subconjunto de las cadenas en inglés del widget |
Funciones de devolución de llamada:
| Función | Se dispara cuando | Carga útil |
|---|---|---|
onReady() | El widget ha renderizado su pantalla de arrastre | — |
onSourceLoaded({ token, pages, sourceExt, allowedTargets }) | ?convert=open tiene éxito | Token de la fuente, recuento de páginas, extensión de la fuente (sin punto inicial), destinos permitidos |
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target }) | ?convert=run tiene éxito | La respuesta de ejecución más el target solicitado |
onDownload({ downloadName, downloadToken }) | El usuario hace clic en Descargar | Se dispara junto con la propia descarga del navegador |
onError({ phase, message }) | Una solicitud open o run falla | phase es 'open' o 'run'; message es el error del servidor sanitizado |
Doconut.convert() devuelve la instancia del widget: reset() vuelve a la pantalla de arrastre, loadFile(file) inicia el flujo con un File, y destroy() lo elimina.
Construye tu propio frontend
El widget es un cliente de este contrato HTTP en DocImage.axd:
| Ruta | Propósito | Respuesta exitosa |
|---|---|---|
POST /DocImage.axd?convert=open (multipart, field file) | Subir y abrir un documento fuente | 200 — { token, pages, sourceExt, allowedTargets } |
POST /DocImage.axd?token=<token>&convert=run&target=<ext> | Convertir el origen subido a target | 200 — { downloadToken, resultToken, resultPages, downloadName, watermarked } |
GET /DocImage.axd?convert=download&token=<downloadToken> | Transmitir el archivo convertido | 200 — el archivo, Content-Disposition: attachment |
Los orígenes subidos se conservan durante 30 minutos; después de ese tiempo, run responde 404 y el archivo debe abrirse de nuevo. downloadToken dispone de su propia ventana de 30 minutos cuando la conversión finaliza. resultToken es un token de visor ordinario que sigue la vida útil de la sesión del visor.
sourceExt en la respuesta de open no lleva punto inicial ("docx"), a diferencia del parámetro sourceExtension de ConvertAsync.
| Ruta | Estado | Cuándo | Cuerpo |
|---|---|---|---|
| cualquiera | 404 | El widget no está habilitado (AddConverterWidget() nunca se llamó) | solo estado |
| cualquiera | 405 | Verbo incorrecto (open/run requieren POST, download requiere GET) | solo estado |
open | 413 | La carga supera MaxUploadMb (pero no los límites de IIS) | { "error": "File is too large." } |
open | 400 | No hay cuerpo multipart, no hay archivo, o un tipo que no se puede convertir | { "error": "..." } |
open | 403 | El tipo de archivo necesita una capacidad que la licencia no otorga | { "error": "..." } |
run | 400 | Un token mal formado, un target desconocido, o un objetivo que no está en allowedTargets | { "error": "..." } |
run | 404 | La carga expiró o nunca se abrió | { "error": "Upload expired — please re-open the file." } |
open, run | 500 | Falló el procesamiento | { "error": "<sanitized message>" } |
download | 400 / 404 | Un token de descarga mal formado, desconocido o expirado | solo estado |
Propiedad de recursos
El llamador posee el MemoryStream que devuelve una conversión y debe disponer de él después de copiarlo o devolverlo (el File(stream, …) de MVC lo dispone por ti). No construyas ni dispongas DocumentConverter tú mismo — su constructor es interno.
Marca de agua
| Estado de la licencia | Inicio | Salida de la conversión |
|---|---|---|
Licencia de visor pagada que otorga Converter | Inicia | Limpia — watermarked: false |
| Licencia Temporal/Demo activa | Inicia | Convierte, con la marca de agua de evaluación — watermarked: true |
Sin licencia, un archivo heredado TRIAL, o una licencia sin Converter | Application_Start lanza excepción; cada solicitud responde un 500 vacío | — |
| Licencia Temporal/Demo expirada | Inicia | Convierte, con la marca de agua de evaluación — watermarked: true |
Una integración puede construirse y probarse de extremo a extremo con una licencia de evaluación antes de la compra — solo cambian los bytes de salida.
Solución de problemas
| Síntoma | Verificación |
|---|---|
Cada solicitud responde un 500 vacío después de añadir el plugin | La licencia otorga Converter — registro de eventos de Windows, origen ASP.NET |
Resolver DocumentConverter lanza excepción | AddPlugin<ConverterPlugin>() está en DoconutHost.Initialize |
| Una conversión Web Forms nunca devuelve | La página se bloquea en ConvertAsync — usa Async="true" y RegisterAsyncTask |
| La conversión de flujo indica que el formato no es compatible | sourceExtension incluye el punto inicial |
El widget se carga pero sus solicitudes devuelven 404 | No se llamó a AddConverterWidget(), o basePath no es '/DocImage.axd' |
| Una carga grande muestra una página de error de IIS en lugar del mensaje del widget | maxRequestLength / maxAllowedContentLength están por debajo de MaxUploadMb |
| Falta un objetivo | Usa los allowedTargets de convert=open |
| La descarga expiró | Repite convert=open / convert=run; los tokens son temporales a propósito |
¿Fue útil esta página?