Plugin Conversor
Converta documentos para 24 formatos de destino
O plugin Conversor transforma o Doconut em um serviço de conversão de documentos. Ele fornece o mecanismo por trás da fachada pública DocumentConverter e — opcionalmente — um widget pronto servido por DocImage.axd, permitindo que você converta documentos a partir de C#, do widget ou de uma interface que você mesmo desenvolva.
Instalar o pacote
Install-Package Doconut.NETFramework.ConverterMantenha o pacote Conversor na mesma versão que Doconut.NETFramework.
Registrar o plugin
Todo plugin é registrado da mesma forma: AddPlugin<TPlugin>() em DoconutHost.Initialize.
Doconut.DoconutHost.Initialize(options =>
{
options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});Se nenhuma licença ativa conceder a capacidade
Converter— nenhuma licença, um arquivo legadoTRIALou uma licença sem essa capacidade —DoconutHost.Initializelança uma exceção a partir deApplication_Start. No System.Web isso significa que cada requisição responde com um500vazio, e o motivo está apenas no log de eventos do Windows (fonte ASP.NET). Licenças temporárias Demo/NFR são aceitas. Veja Configuração de Licença.
Converter a partir de C#
Cada conversão retorna um MemoryStream buscável posicionado em 0. DocumentConverter é sem estado: obtenha-o de DoconutHost.Services onde precisar e reutilize livremente.
// 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);Dois detalhes que são fáceis de errar: sourceExtension na sobrecarga que aceita stream deve incluir o ponto inicial (".xlsx", não "xlsx"), caso contrário não será resolvido. E, apesar do nome, WordToHtmlAsync retorna Task<Stream>, não Task<string> — o documento HTML (imagens incorporadas como Base64) chega como um stream, como todo o resto dos resultados.
Em um controlador MVC 5
Torne a ação assíncrona e await a conversão:
[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");
}Em Web Forms: nunca bloqueie uma conversão
Uma página Web Forms é executada em um contexto de requisição de thread única. ConvertAsync retoma nesse contexto quando termina, portanto uma página que espera por ele de forma síncrona — .Result, .Wait(), .GetAwaiter().GetResult() — ocupa a própria thread que a conversão precisa para concluir. A requisição nunca retorna. O navegador continua carregando, o IIS não registra nada e o restante do site continua funcionando, parecendo uma conversão lenta em vez de um deadlock.
Marque a página com Async="true" e execute a conversão como uma tarefa assíncrona da 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();
}
}));
}Sem Async="true" na diretiva @Page, RegisterAsyncTask é silenciosamente ignorado. Após um await, use o Context da página; HttpContext.Current pode ser null nesse caso.
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, WebpNem todo fonte converte para todo alvo: cada família de formato da fonte (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, web document) tem seu próprio conjunto de alvos permitidos. Não codifique este enum como a lista de alvos da sua UI: ?convert=open retorna os allowedTargets para o arquivo enviado, e isso é o que deve conduzir um seletor.
Widget incorporável
Os endpoints do widget ?convert=open|run|download são servidos por DocImage.axd e estão desativados por padrão. Habilite-os ao lado do registro do 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>Duas coisas a verificar quando o widget se comporta de forma inesperada:
basePath: '/DocImage.axd'. O padrão do widget,/doconut, é o endpoint ASP.NET Core. Neste pacote, os endpoints são o manipuladorDocImage.axddoWeb.config.- O script e os endpoints são independentes. O módulo de recursos serve
doconutConverter.jsesteja ou não o widget habilitado. SemAddConverterWidget(), o widget carrega, pinta sua zona de arraste e parece totalmente correto — e sua primeira ação responde404.
Limites de upload
ASP.NET lê todo o corpo da requisição antes que DocImage.axd seja executado. Um upload acima de MaxUploadMb mas abaixo dos limites do host gera o JSON 413 do widget ("File is too large."). Um upload acima dos limites do host é rejeitado primeiro pelo IIS, com uma página de erro que o widget não consegue ler. Mantenha ambos os limites do host em Web.config acima do teto do 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 o widget
Opções passadas para Doconut.convert(selector, options):
| Opção | Tipo | Padrão | Observações |
|---|---|---|---|
basePath | string | /doconut | A URL do endpoint. Defina '/DocImage.axd' neste pacote |
resPath | string | /doconut-res | Aceito por consistência com outros widgets Doconut; o widget conversor não constrói nenhuma URL a partir dele |
maxUploadMb | number | 25 | Apenas verificação prévia no cliente; o servidor impõe seu próprio limite |
licenseUrl | string | null | null | Transforma o aviso de marca d'água na tela de resultado em um link |
labels | object | {} | Substitui qualquer subconjunto das strings em inglês do widget |
Callbacks:
| Callback | Dispara quando | Carga útil |
|---|---|---|
onReady() | O widget renderizou sua tela de arrastar | — |
onSourceLoaded({ token, pages, sourceExt, allowedTargets }) | ?convert=open tem sucesso | Token da fonte, contagem de páginas, extensão da fonte (sem ponto inicial), alvos permitidos |
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target }) | ?convert=run tem sucesso | A resposta da execução mais o target solicitado |
onDownload({ downloadName, downloadToken }) | O usuário clica em Download | Dispara junto ao download próprio do navegador |
onError({ phase, message }) | Uma requisição open ou run falha | phase é 'open' ou 'run'; message é o erro do servidor sanitizado |
Doconut.convert() devolve a instância do widget: reset() volta à tela de arraste, loadFile(file) inicia o fluxo com um File, e destroy() o remove.
Construa seu próprio frontend
O widget é um cliente para este contrato HTTP em DocImage.axd:
| Rota | Propósito | Resposta de sucesso |
|---|---|---|
POST /DocImage.axd?convert=open (multipart, field file) | Carregar e abrir um documento fonte | 200 — { token, pages, sourceExt, allowedTargets } |
POST /DocImage.axd?token=<token>&convert=run&target=<ext> | Converter a fonte carregada para target | 200 — { downloadToken, resultToken, resultPages, downloadName, watermarked } |
GET /DocImage.axd?convert=download&token=<downloadToken> | Transmitir o arquivo convertido | 200 — o arquivo, Content-Disposition: attachment |
As fontes carregadas são mantidas por 30 minutos; depois disso, run responde 404 e o arquivo deve ser aberto novamente. downloadToken tem sua própria janela de 30 minutos quando a conversão é concluída. resultToken é um token de visualizador comum que segue a duração da sessão do visualizador.
sourceExt na resposta de open não tem ponto inicial ("docx") — o oposto do parâmetro sourceExtension de ConvertAsync.
| Rota | Status | Quando | Corpo |
|---|---|---|---|
| qualquer | 404 | O widget não está habilitado (AddConverterWidget() nunca foi chamado) | apenas status |
| qualquer | 405 | Verbo errado (open/run requerem POST, download requer GET) | apenas status |
open | 413 | O upload excede MaxUploadMb (mas não os limites do IIS) | { "error": "File is too large." } |
open | 400 | Sem corpo multipart, sem arquivo, ou um tipo que não pode ser convertido | { "error": "..." } |
open | 403 | O tipo de arquivo requer uma capacidade que a licença não concede | { "error": "..." } |
run | 400 | Um token malformado, um target desconhecido, ou um alvo que não está em allowedTargets | { "error": "..." } |
run | 404 | O upload expirou ou nunca foi aberto | { "error": "Upload expired — please re-open the file." } |
open, run | 500 | Processamento falhou | { "error": "<sanitized message>" } |
download | 400 / 404 | Um token de download malformado, desconhecido ou expirado | apenas status |
Propriedade de recursos
O chamador possui o MemoryStream que uma conversão retorna e deve descartá‑lo após copiar ou retorná‑lo (o File(stream, …) do MVC descarta‑o para você). Não construa ou descarte DocumentConverter manualmente — seu construtor é interno.
Marcação d'água
| Estado da licença | Inicialização | Saída da conversão |
|---|---|---|
Licença paga de visualizador concedendo Converter | Inicia | Limpo — watermarked: false |
| Licença Temporária/Demo ativa | Inicia | Converte, com a marca d'água de avaliação — watermarked: true |
Sem licença, um arquivo legado TRIAL, ou uma licença sem Converter | Application_Start lança exceção; toda requisição responde um 500 vazio | — |
| Licença Temporária/Demo expirada | Inicia | Converte, com a marca d'água de avaliação — watermarked: true |
Uma integração pode ser construída e testada de ponta a ponta com uma licença de avaliação antes da compra — apenas os bytes de saída mudam.
Solução de problemas
| Sintoma | Verificação |
|---|---|
Todas as requisições respondem um 500 vazio após adicionar o plugin | A licença concede Converter — log de eventos do Windows, fonte ASP.NET |
Resolver DocumentConverter lança exceção | AddPlugin<ConverterPlugin>() está em DoconutHost.Initialize |
| Uma conversão Web Forms nunca retorna | A página bloqueia em ConvertAsync — use Async="true" e RegisterAsyncTask |
| A conversão de stream indica que o formato não é suportado | sourceExtension inclui o ponto inicial |
O widget carrega mas suas requisições retornam 404 | AddConverterWidget() não foi chamado, ou basePath não é '/DocImage.axd' |
| Um upload grande mostra uma página de erro do IIS ao invés da mensagem do widget | maxRequestLength / maxAllowedContentLength estão abaixo de MaxUploadMb |
| Um alvo está ausente | Use o allowedTargets de convert=open |
| O download expirou | Repita convert=open / convert=run; os tokens são temporários intencionalmente |
Esta página foi útil?