web-dev-qa-db-fra.com

Faire fonctionner PdfStamper avec MemoryStreams (c #, itextsharp)

Il m'est venu de retravailler l'ancien code qui signe PDF fichiers dans un nouveau, qui signe MemoryStreams (tableaux d'octets) qui viennent et sont envoyés par les services Web. Simple, non? Eh bien, c'était hier Aujourd'hui, je n'arrive pas à le faire fonctionner.

Ceci est l'ancien code, qui utilise FileStreams et cela fonctionne:

    public static string OldPdfSigner(PdfReader pdfReader, string destination, string password, string reason, string location, string pathToPfx)
    {
        using (FileStream pfxFile = new FileStream(pathToPfx, FileMode.Open, FileAccess.Read))
        {
            ...

            using (PdfStamper st = PdfStamper.CreateSignature(pdfReader, new FileStream(destination, FileMode.Create, FileAccess.Write), '\0'))
            {
                PdfSignatureAppearance sap = st.SignatureAppearance;
                sap.SetCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
                sap.Reason = reason;
                sap.Location = location;
                return destination;
            }
        }
    }

Voici ce que j'ai refait moi-même, ce qui lève System.ObjectDisposedException: Impossible d'accéder à un flux fermé.

    public static byte[] PdfSigner(PdfReader pdfReader, string password, string reason, string location, string pathToPfx)
    {
        using (FileStream pfxFile = new FileStream(pathToPfx, FileMode.Open, FileAccess.Read))
        {
            ...

            MemoryStream outputStream = new MemoryStream();
            using (PdfStamper st = PdfStamper.CreateSignature(pdfReader, outputStream, '\0'))
            {
                st.Writer.CloseStream = false;
                PdfSignatureAppearance sap = st.SignatureAppearance;
                sap.SetCrypto(key, chain, null, PdfSignatureAppearance.WINCER_SIGNED);
                sap.Reason = reason;
                sap.Location = location;
                st.Close();
                outputStream.Position = 0;
                return outputStream.ToArray();
            }
        }
    }

et si je commente

st.Close();

il crée un document vide. Qu'est-ce que je fais mal?

21
ADSMarko

Non spécifique à votre code de signature, mais lorsque vous travaillez avec MemoryStream et PdfStamper, suivez ce schéma général:

using (MemoryStream ms = new MemoryStream()) {
  using (PdfStamper stamper = new PdfStamper(reader, ms, '\0', true)) {
// do stuff      
  }    
  return ms.ToArray();
}
  • MemoryStream implémente IDisposable, donc incluez une instruction using.
  • L'instruction PdfStamperusing s'occupe de supprimer l'objet, vous n'avez donc pas besoin d'appeler Close(), et vous n'avez pas besoin de définir CloseStream propriété.
  • Votre extrait de code renvoie le tableau d'octets trop tôt, à l'intérieur de l'instruction PdfStamperusing, de sorte que votre MemoryStream est en fait un no-op. Renvoie le tableau d'octets extérieur de l'instruction PdfStamperusing, et intérieur la MemoryStreamusing déclaration.
  • En règle générale, il n'est pas nécessaire de réinitialiser la propriété MemoryStreamPosition.
  • Ignorez le constructeur PdfStamper ci-dessus - il s'agit d'un code de test que j'avais pour remplir les formulaires et utilisez le constructeur/la méthode dont vous avez besoin pour faire votre signature.
21
kuujinbo