Search code examples
c#sharepoint-2010sharepointdocumentlibraryspwebspsite

Why does this Sharepoint Files.Add() result in an I/O Error?


With this code:

    using (var ms = new MemoryStream())
    {
        using (var doc = new Document(PageSize.A4, 25, 25, 10, 10)) 
        {
            //Create a writer that's bound to our PDF abstraction and our 
stream
            using (var writer = PdfWriter.GetInstance(doc, ms))
            {

                //Open the document for writing
                doc.Open();

                . . .

            }
        // File has been generated, now save it
        try
        {
            var bytes = ms.ToArray();
            String pdfFileID = GetYYYYMMDDAndUserNameAndAmount();
            String pdfFileName = String.Format("DirectPayDynamic_{0}.pdf", 
pdfFileID);
            String fileFullpath = 
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirector
y), pdfFileName); 
            String fileLinkBase = "Generated PDF: <a href=\"{0}\">{1}</a>";
            String filelink = String.Format(fileLinkBase, fileFullpath, 
pdfFileName);

            File.WriteAllBytes(fileFullpath, bytes);
            AddVerticalSpace();                    

            var pdflink = new Label
            {
                CssClass = "finaff-webform-field-label",
                Text = filelink
            };
            this.Controls.Add(pdflink); 

    // NOTE: This is the new (non-working, exception-throwing) part of the 
code, where we're trying to save the PDF file to a Sharepoint Document Library
            string destination = String.Format("DirectPayPDFForms/{0}", 
pdfFileName); 
            SPSite siteCollection = new SPSite(siteUrl);
            SPWeb site = SPContext.Current.Web; 
            site.Files.Add(destination, ms); // this is the line that fails
    // end of new code      
        }
        catch (DocumentException dex)
        {
            exMsg = dex.Message;
        }
        catch (IOException ioex)
        {
            exMsg = ioex.Message;
        }
        catch (Exception ex)
        {
            exMsg = ex.Message;
            ; // for debugging: What is "ex" here?
        }
    } // using (var ms = new MemoryStream())            
} // GeneratePDF

...I get, "I/O Error Occurred" (in the IOException catch block). It is this line:

site.Files.Add(destination, ms);

...that throws the error. Is it my destination, or the memory stream, that is causing the problem? "destination" is the name of the Sharepoint Document Library (DirectPayPDFForms) plus a generated name for the file. Without this new code, the method runs fine and places the PDF file on the server (but that's not where we want it - we need it to go first to a Document Library).

UPDATE

I get the same exception replacing the problematic code block above with a call to this:

private void SavePDFToDocumentLibrary(MemoryStream memstrm)
{
    string doclib = "DirectPayPDFForms";
    try
    {
        using (SPSite site = new SPSite(siteUrl))
        {
            using (SPWeb web = site.RootWeb)
            {
                SPList list = web.Lists[doclib];
                SPListItem spli = list.Items.Add();
                spli["Title"] = String.Format("DirectPayPDFForms-{0}-{1}", GetUserId(), GetListTitleTimeStamp());

                if (null != memstrm)
                {
                    web.Files.Add(doclib, memstrm); 
                }
                // If this works, update at least some of the fields, such as Created, CreatedBy, etc.
                spli.Update();
            }
        }
    }
    catch (Exception ex)
    {
        String s = String.Format("Exception is {0}", ex.Message);
    }
}

This type of code works in another instance (I can successfully save values to a List this way), so the problem must be something Document-Library-specific. Do I need to save the document to a specific field in the Document Library?

UPDATE 2

I also tried this:

string saveloc = String.Format(@"{0}\{1}", doclib, filename);

...with the same result.

And this:

string saveloc = String.Format(@"{0}\{1}\{2}", siteUrl, doclib, filename);

...which at least provided some variety, exceptioning with, "Invalid URI: The hostname could not be parsed."

With this:

string saveloc = String.Format("{0}/{1}/{2}", siteUrl, doclib, filename);

...I'm back to the old "I/O Error Occurred" mantra.

UPDATE 3

Since the "AllItems.aspx" page for the Sharepoint site has both "Documents" and "Lists", I am wondering if I should not be using List in this case, but Document. IOW, perhaps my code should be something like:

SPDocTemplateCollection spdoctemplatecoll = web.DocTemplates;
SPDocumentLibrary spdoclib = spdoctemplatecoll[doclib];
SPListItem spli = spdoclib.Items.Add();

...where it is currently:

SPList list = web.Lists[doclib];
SPListItem spli = list.Items.Add();
SPListItem spli = list.Items.Add();

...but that guess misses fire, as it won't compile (I get, "The best overloaded method match for 'Microsoft.SharePoint.SPDocTemplateCollection.this[int]' has some invalid arguments" and "Argument 1: cannot convert from 'string' to 'int'")


Solution

  • This works:

    . . .
    SavePDFToDocumentLibrary(fileFullpath); // instead of trying to send the memory stream, using the file saved on the server
    . . .
    
    private void SavePDFToDocumentLibrary(String fullpath)
    {
        String fileToUpload = fullpath;
        String sharePointSite = siteUrl;
        String documentLibraryName = "DirectPayPDFForms";
    
        using (SPSite oSite = new SPSite(sharePointSite))
        {
            using (SPWeb oWeb = oSite.OpenWeb())
            {
                if (!System.IO.File.Exists(fileToUpload))
                {
                    throw new FileNotFoundException("File not found.", fileToUpload);
                }
    
                SPFolder doclib = oWeb.Folders[documentLibraryName];
    
                // Prepare to upload
                Boolean replaceExistingFiles = true;
                String fileName = System.IO.Path.GetFileName(fileToUpload);
                FileStream fileStream = File.OpenRead(fileToUpload);
    
                // Upload document
                SPFile spfile = doclib.Files.Add(fileName, fileStream, replaceExistingFiles);
    
                // Commit 
                doclib.Update();
            }
        }
    }
    

    I adapted it from Henry Zucchini's answer here.