如何保持从模型到控制器的流打开?

时间:2012-06-07 18:55:19

标签: c# asp.net-mvc pdf

我正在编辑pdf,然后在新标签页中打印。我收到一条错误消息,说我“无法访问封闭的流”。这就是我到目前为止......

CONTROLLER

public ActionResult QST(string ID) 
{   
    ...
    PdfReader reader = new PdfReader(Server.MapPath("~/Content/PDF/QST.pdf"));
    QstRepository repo = new QstRepository();
    Stream newPdf = repo.GS(ID, reader);            
    return new FileStreamResult(newPdf, "application/pdf");
}

MODEL

public Stream GS(string ID, PdfReader reader)
{
    Stream newPdf = new MemoryStream();
    using (MemoryStream ms = new MemoryStream())
    {
        PdfStamper formFiller = new PdfStamper(reader, ms);
        AcroFields formFields = formFiller.AcroFields;
        formFields.SetField("ID", ID);

        formFiller.FormFlattening = true;
        formFiller.Writer.CloseStream = false;
        newPdf = ms;
        formFiller.Close();
    }
    return newPdf;
}

如何在关闭之前访问pdf ...或者如何在之后访问pdf?

2 个答案:

答案 0 :(得分:3)

返回前代码的最后两行是

newPdf = ms;
formFiller.Close(); 

由于您的代码全部位于using (MemoryStream ms = new MemoryStream())块内,因此MemoryStream ms将在您返回之前关闭。

由于您要将newPdf分配给变量ms,因此nwePdf eventualy会返回MemoryStream指向的相同(已关闭)ms

您可以public Stream GS(string ID, PdfReader reader)只创建没有使用块的流,但如果您的代码中出现异常,则会冒着保持打开状态的风险。我想你可以尝试以下方法:

// All calls to GS() must ensure that the returned stream gets closed.
public Stream GS(string ID, PdfReader reader) 
{ 
    MemoryStream newPdf = new MemoryStream();
    PdfStamper formFiller = null;
    try 
    { 
        formFiller = new PdfStamper(reader, newPdf); 
        AcroFields formFields = formFiller.AcroFields; 
        formFields.SetField("ID", ID); 

        formFiller.FormFlattening = true;
        //formFiller.Writer.CloseStream = false;
    }
    catch
    {
        // Only close newPdf on an exception
        newPdf.Close();
        throw; // Rethrow original exception
    }
    finally
    {
        // Always ensure that formFiller gets closed
        formFiller.Close();
    }
    return newPdf; 
} 

更新:我删除了额外的MemoryStream,因为一个只是在函数的开头声明,然后设置为指向另一个,而不是用于任何东西介于两者之间。

更新:我找到了example using the PdfStamper。根据示例,调用formFiller.Close()实际上是写入流。在他们的示例中,它们不将Writer.CloseStream属性设置为false。这可能就是你得到一个空白页面的原因。不幸的是,我无法在PdfStamper上找到任何实际文档来验证这一点。

答案 1 :(得分:1)

在您的代码中,msnewPdf引用相同的MemoryStream个实例;由于msusing块结束时关闭,newPdf也会关闭(因为它是相同的流)。因此,您需要在不关闭它的情况下返回Stream

public Stream GS(string ID, PdfReader reader)
{
    PdfStamper formFiller = new PdfStamper(reader, ms);
    AcroFields formFields = formFiller.AcroFields;
    formFields.SetField("ID", ID);

    formFiller.FormFlattening = true;
    formFiller.Writer.CloseStream = false;
    formFiller.Close();
    return ms;
}

我对ASP.NET MVC不太熟悉,但我认为FileStreamResult负责关闭流。