将Razor HTML转换为可下载的PDF [英] Convert Razor HTML into downloadable PDF

查看:108
本文介绍了将Razor HTML转换为可下载的PDF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个动态的元素过滤表,每个表都有一组用于操作的按钮.其中之一显示了用Razor生成的部分HTML以及元素的数据.

I have a dynamic filtered table of elements, and each one have a group of buttons to operate with them. One of them shows a partial HTML generated with Razor with the element's data.

表条目:

foreach (var item in listado.Where(x => x.Raw != null)) {
<tr>
    <td>@item.Id</td>
    <td>@item.Usuario</td>
    <td>@item.NIF_CIF</td>
    <td>
        @if (!(String.IsNullOrEmpty(item.Telefono)) && !(String.IsNullOrWhiteSpace(item.Telefono))) {
            @item.Telefono
        } else {
            @Html.Raw("No disponible")}
    </td>
    <td>@Math.Round(item.Raw.PrecioTotal).ToString("0.##")&nbsp;&euro;</td>
    <td>@item.FechaCreacion.ToShortDateString()</td>
    <td class="btn-group-sm" role="group">
        <button class="eliminar btn btn-secondary btn-danger" data-itemid="@item.Id">Eliminar</button>
        <button class="convertirPDF btn btn-secondary btn-info" data-itemid="@item.Id">PDF</button>
        <button class="detalles btn brn-secondary btn-info" data-itemid="@item.Id">Detalles</button></td>
</tr>
<tr id="vistaDetalles@(item.Id)" hidden>
    <td colspan="7">
        @Html.Partial("_PresupuestoFinal", item)
    </td>
</tr> }

我要使用的元素在行中生成

The element I want to work with is generated in the line

@Html.Partial("_PresupuestoFinal", item)

然后,使用jQuery,我为这些按钮提供了功能. PDF按钮代码为:

So then, with jQuery, I provide function to those buttons. The PDF button code is:

$(".convertirPDF").on("click", function (id) {
    var itemId = $(this).data('itemid');
    var presupuesto = $('#content').html($(this).find('#vistaDetalles' + itemId).html());
    Pdf(presupuesto);
});

function Pdf(presupuesto) {
    presupuestoHTML = presupuesto;

    $.ajax({
        method: "GET",
        url: 'DescargarPDF',
        data: { presupuestoHTML: presupuesto },
        cache: false,
        async: true,
    });
};

但是,每当我按下按钮时,我都会进入控制台:

But every tim I press the button, I get on console:

TypeError: can't convert undefined to object

当我调用函数Pdf时参考该行.我要做的是选择该特定的html(对应于该元素的html)并将其转换为PDF文件.由于我无法获得足够的信息来知道错误在哪里,所以我在做什么错了?

Referring to the line when I invoke the function Pdf. What I want to do is to pick that particular html (the one corresponding to the element) and convert it to a PDF file. Since I can't get enough info to know where the error is, what am I doing wrong?

顺便说一句,url: 'DescargarPDF行指向我控制器中的方法.

BTW that url: 'DescargarPDF line is pointing to the method in my controller.

编辑

这是我要求的控制器方法:

Here's my controller method as requested:

public void DescargarPDF (string presupuestoHTML) {

        Response.Clear();
        Response.ContentType = "application/pdf";
        Response.AddHeader("content-disposition", "attachment;filename=" + "PDF.pdf");
        Response.Cache.SetCacheability(HttpCacheability.NoCache);

        MemoryStream ms = new MemoryStream();
        TextReader txtReader = new StringReader(presupuestoHTML);

        // Creamos un objeto de clase itextsharp document
        Document doc = new Document(PageSize.A4, 25, 25, 30, 30);

        // Creamos un pdfwriter de itextsharp que lee el documento y dirige un stream XML a un archivo
        PdfWriter oPdfWriter = PdfWriter.GetInstance(doc, ms);

        // Creamos un trabajador para parsear el documento
        HTMLWorker htmlWorker = new HTMLWorker(doc);

        // Abrimos el documento y se lo pasamos al trabajador
        doc.Open();
        htmlWorker.StartDocument();

        // Parseamos el presupuesto en html al documento
        htmlWorker.Parse(txtReader);

        // Cerramos el documento y el trabajador
        htmlWorker.EndDocument();
        htmlWorker.Close();
        doc.Close();

        var bPDF = ms.ToArray();

        Response.BinaryWrite(bPDF);
        Response.End();
    }

脚本没有被击中.

第二次编辑

所以我得到了有关该错误的更多信息:

So I got more info on the error:

presupuestoHTML[toArray]

是引起错误的原因.不知道在哪里,或如何.

Is what's causing the error. Don't know where, or how.

第三次编辑

好,所以我现在知道问题出在检索我想要的html的脚本上.我更改了这一行:

Ok so I know now the issue is on the script retrieving the html I want. I changed that line:

$(".convertirPDF").on("click", function (id) {
    itemId = $(this).data('itemid');
    presupuesto = document.documentElement.getElementsByTagName('vistaDetalles' + itemId);
    Pdf(presupuesto);
});

现在控制台中的错误是:

And now the error in console is:

TypeError: 'item' called on an object that does not implement interface HTMLCollection.

我会继续研究,希望这可以使问题更清楚.

I'll keep looking into it, hope this gets the issue clearer.

第二次更新

我一直在努力,除了文件下载之外,我都能正常工作.我会解释:

I've been working on this, I got everything working except for the file download. I'll explain:

这是脚本,它使用适当的数据命中了控制器方法.

Here's the script, it hits the controller method with the proper data.

$(".convertirPDF").on("click", function (id) {
    var itemId = $(this).data('itemid');
    // var presupuesto = $('#vistaDetalles' + itemId).html();
    Pdf(itemId);
});

function Pdf(itemid) {
    var id = itemid;

    $.ajax({
        method: "POST",
        url: 'DescargarPDF',
        data: { itemId: id },
        cache: false,
        async: true,
    });
};

这样行得通.这是我的控制器方法,我怀疑是引起问题的地方:

So that works. Here's my controller method, where I suspect the trouble is caused:

 public FileResult DescargarPDF (int itemId) {
        var presupuesto = ReglasNegocio.Fachada.Consultas.ObtenerPresupuesto(itemId);             
        var archivo = new Rotativa.PartialViewAsPdf("_PresupuestoFinal", presupuesto) { FileName = "Presupuesto_" + itemId + ".pdf" };

        return File(archivo.FileName, "application/pdf");
    }

那是我到目前为止的最后一次尝试.我也尝试过Rotativa的ActionAsPdf,并且在浏览器控制台上获得了数据流(我必须猜是pdf文件)而不是可下载文件.我还尝试了其他选项,例如将文件转换为字节数组并进行流传输,但是由于我不想保存文件,因此该选项被丢弃(函数需要文件路径,我无法提供该路径,因为文件未保存,仍在内存中).仍在努力.

That's my last try so far. I've tried Rotativa's ActionAsPdf as well and I got on the browser console a stream of data (which I have to guess it's the pdf file) not the downloadable file. I've also tried other options like converting the file to a byte array and stream it but since I don't want to save the file, that option is discarded (functions require a file path, which I'm not able to provide because the file is not saved, still on memory). Still working on it.

推荐答案

我问了另一个

I asked another question to try to solve the not downloading file issue, and I got it.

在进行任何操作之前,我都是通过ajax进行请求的,因为我认为这样做是一种很好的方法,但事实证明,有一种更简单的方法:不使用ajax.

Before anything, I was doing the request through ajax because I thought to be a good way to do so, but as it turns out, there's a much simpler way: not using ajax.

因此,我删除了按钮的脚本和按钮本身,因此现在看起来像这样:

So, I removed the script for the button and the button itself, so now looks like this:

<a href="DescargarPDF/?itemId=@item.Id" target="_blank" class="btn btn-secondary btn-info">PDF</a>

它的外观与以前相同,但实际上是到我的控制器方法的链接,现在看起来像这样:

It has the same appearance than before, but it's actually a link to my controller's method, which right now looks like this:

public FileResult DescargarPDF (int itemId) {
        var presupuesto = ReglasNegocio.Fachada.Consultas.ObtenerPresupuesto(itemId);             
        var archivo = new Rotativa.PartialViewAsPdf("_PresupuestoFinal", presupuesto) { FileName = "Presupuesto_" + itemId + ".pdf", PageSize = Rotativa.Options.Size.A4 };
        var binario = archivo.BuildFile(this.ControllerContext);        

        return File(binario, "application/pdf", archivo.FileName);           
    }

我知道在大多数情况下这不是一个有效的解决方案,因为我只是将ajax抛在了后面,但是还有很多其他问题,答案对他们有用,他们仍然使用ajax来管理请求.

I know in most cases this wouldn't be a valid solution since I just left ajax behind, but there are many other questions where the answer worked for them and they still use ajax to manage the request.

不过,我希望这会有所帮助.谢谢大家.编码愉快.

Still, I hope this helps. Thanks to everyone. Happy coding.

更新

我刚刚发现为什么将我的PDF文件放入控制台,请检查

I just found out why my PDF file was dropped into console, check the other question, I left a little explanation for that particular issue. Thanks everyone.

这篇关于将Razor HTML转换为可下载的PDF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆