为什么这个 Sharepoint Files.Add() 会导致 I/O 错误?
Why does this Sharepoint Files.Add() result in an I/O Error?
使用此代码:
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/O 发生错误”(在 IOException 捕获块中)。就是这一行:
site.Files.Add(destination, ms);
...引发错误。是我的目的地还是内存流导致了问题? "destination" 是 Sharepoint 文档库 (DirectPayPDFForms) 的名称加上文件的生成名称。如果没有这个新代码,该方法运行良好并将 PDF 文件放在服务器上(但这不是我们想要的位置 - 我们需要它首先转到文档库)。
更新
我得到了同样的异常,将上面有问题的代码块替换为对此的调用:
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);
}
}
这种类型的代码在另一个实例中有效(我可以通过这种方式成功地将值保存到列表中),所以问题一定是特定于文档库的。我是否需要将文档保存到文档库中的特定 字段?
更新 2
我也试过这个:
string saveloc = String.Format(@"{0}\{1}", doclib, filename);
...结果相同
还有这个:
string saveloc = String.Format(@"{0}\{1}\{2}", siteUrl, doclib, filename);
...至少提供了一些变化,但例外情况是,“无效的 URI:无法解析主机名。”
有了这个:
string saveloc = String.Format("{0}/{1}/{2}", siteUrl, doclib, filename);
...我又回到了旧的 "I/O Error Occurred" 口头禅。
更新 3
由于 Sharepoint 站点的 "AllItems.aspx" 页面同时包含 "Documents" 和 "Lists",我想知道在这种情况下我是否不应该使用 List,而是使用 Document。 IOW,也许我的代码应该是这样的:
SPDocTemplateCollection spdoctemplatecoll = web.DocTemplates;
SPDocumentLibrary spdoclib = spdoctemplatecoll[doclib];
SPListItem spli = spdoclib.Items.Add();
...当前位置:
SPList list = web.Lists[doclib];
SPListItem spli = list.Items.Add();
SPListItem spli = list.Items.Add();
...但是这个猜测没有成功,因为它不会编译(我明白了,"The best overloaded method match for 'Microsoft.SharePoint.SPDocTemplateCollection.this[int]' has some invalid arguments" 和 "Argument 1: cannot convert from 'string' to 'int'")
这个有效:
. . .
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();
}
}
}
我改编自 Henry Zucchini 的回答 here。
使用此代码:
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/O 发生错误”(在 IOException 捕获块中)。就是这一行:
site.Files.Add(destination, ms);
...引发错误。是我的目的地还是内存流导致了问题? "destination" 是 Sharepoint 文档库 (DirectPayPDFForms) 的名称加上文件的生成名称。如果没有这个新代码,该方法运行良好并将 PDF 文件放在服务器上(但这不是我们想要的位置 - 我们需要它首先转到文档库)。
更新
我得到了同样的异常,将上面有问题的代码块替换为对此的调用:
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);
}
}
这种类型的代码在另一个实例中有效(我可以通过这种方式成功地将值保存到列表中),所以问题一定是特定于文档库的。我是否需要将文档保存到文档库中的特定 字段?
更新 2
我也试过这个:
string saveloc = String.Format(@"{0}\{1}", doclib, filename);
...结果相同
还有这个:
string saveloc = String.Format(@"{0}\{1}\{2}", siteUrl, doclib, filename);
...至少提供了一些变化,但例外情况是,“无效的 URI:无法解析主机名。”
有了这个:
string saveloc = String.Format("{0}/{1}/{2}", siteUrl, doclib, filename);
...我又回到了旧的 "I/O Error Occurred" 口头禅。
更新 3
由于 Sharepoint 站点的 "AllItems.aspx" 页面同时包含 "Documents" 和 "Lists",我想知道在这种情况下我是否不应该使用 List,而是使用 Document。 IOW,也许我的代码应该是这样的:
SPDocTemplateCollection spdoctemplatecoll = web.DocTemplates;
SPDocumentLibrary spdoclib = spdoctemplatecoll[doclib];
SPListItem spli = spdoclib.Items.Add();
...当前位置:
SPList list = web.Lists[doclib];
SPListItem spli = list.Items.Add();
SPListItem spli = list.Items.Add();
...但是这个猜测没有成功,因为它不会编译(我明白了,"The best overloaded method match for 'Microsoft.SharePoint.SPDocTemplateCollection.this[int]' has some invalid arguments" 和 "Argument 1: cannot convert from 'string' to 'int'")
这个有效:
. . .
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();
}
}
}
我改编自 Henry Zucchini 的回答 here。