Ответ 1
Я обсуждал этот вопрос с Microsoft. Похоже, что только один способ создания вложений удаленно - это веб-сервис List.asmx. Я также попытался создать эту подпапку и не добился успеха.
У меня есть список SharePoint, к которому я добавляю новые ListItems с использованием объектной модели клиента. Добавление ListItems не является проблемой и отлично работает.
Теперь я хочу добавить вложения.
Я использую SaveBinaryDirect следующим образом:
File.SaveBinaryDirect(clientCtx, url.AbsolutePath + "/Attachments/31/" + fileName, inputStream, true);
Он работает без каких-либо проблем, пока элемент, к которому я пытаюсь добавить вложение, уже имеет вложение, которое было добавлено через сайт SharePoint, а не с помощью объектной модели клиента.
Когда я пытаюсь добавить вложение к элементу, у которого еще нет вложений, я получаю следующие ошибки (оба происходят, но не с теми же файлами, но эти два сообщения появляются последовательно):
The remote server returned an error: (409) Conflict
The remote server returned an error: (404) Not Found
Я подумал, что, возможно, мне нужно сначала создать папку вложения для этого элемента. Когда я попробую следующий код:
clientCtx.Load(ticketList.RootFolder.Folders);
clientCtx.ExecuteQuery();
clientCtx.Load(ticketList.RootFolder.Folders[1]); // 1 -> Attachment folder
clientCtx.Load(ticketList.RootFolder.Folders[1].Folders);
clientCtx.ExecuteQuery();
Folder folder = ticketList.RootFolder.Folders[1].Folders.Add("33");
clientCtx.ExecuteQuery();
Я получаю сообщение об ошибке:
Cannot create folder "Lists/Ticket System/Attachment/33"
У меня есть полные права администратора для сайта/списка SharePoint.
Любые идеи, что я могу делать неправильно?
Спасибо, Торбен
Я обсуждал этот вопрос с Microsoft. Похоже, что только один способ создания вложений удаленно - это веб-сервис List.asmx. Я также попытался создать эту подпапку и не добился успеха.
Я тоже долгое время боролся с этой проблемой, поэтому я решил опубликовать полный пример кода, показывающий, как успешно создать элемент списка и добавить вложение.
Я использую API-интерфейс Client для создания элемента списка и веб-службы SOAP для добавления вложения. Это связано с тем, что, как отмечалось в других местах в Интернете, API-интерфейс клиента можно использовать только для добавления вложений в элемент, в котором каталог загрузки элементов уже существует (например, если элемент уже имеет вложение). Иначе это не с ошибкой 409 или чем-то. Однако веб-служба SOAP справляется с этим ОК.
Обратите внимание, что еще одна вещь, которую мне пришлось преодолеть, заключалась в том, что, хотя я добавил ссылку SOAP, используя следующий URL-адрес:
https://my.sharepoint.installation/personal/test/_vti_bin/lists.asmx
URL, который VS фактически добавил в app.config:
Мне пришлось вручную изменить app.config на правильный URL, иначе я бы получил ошибку:
Список не существует. Выбранная страница содержит список, который не существует. Возможно, он был удален другим пользователем. 0x82000006
Вот код:
void CreateWithAttachment()
{
const string listName = "MyListName";
// set up our credentials
var credentials = new NetworkCredential("username", "password", "domain");
// create a soap client
var soapClient = new ListsService.Lists();
soapClient.Credentials = credentials;
// create a client context
var clientContext = new Microsoft.SharePoint.Client.ClientContext("https://my.sharepoint.installation/personal/test");
clientContext.Credentials = credentials;
// create a list item
var list = clientContext.Web.Lists.GetByTitle(listName);
var itemCreateInfo = new ListItemCreationInformation();
var newItem = list.AddItem(itemCreateInfo);
// set its properties
newItem["Title"] = "Created from Client API";
newItem["Status"] = "New";
newItem["_Comments"] = "here are some comments!!";
// commit it
newItem.Update();
clientContext.ExecuteQuery();
// load back the created item so its ID field is available for use below
clientContext.Load(newItem);
clientContext.ExecuteQuery();
// use the soap client to add the attachment
const string path = @"c:\temp\test.txt";
soapClient.AddAttachment(listName, newItem["ID"].ToString(), Path.GetFileName(path),
System.IO.File.ReadAllBytes(path));
}
Надеюсь, это поможет кому-то.
С Sharepoint 2010 не удалось загрузить первое вложение в элемент списка с помощью COM. Рекомендация заключалась в том, чтобы использовать веб-службу списков.
С Sharepoint 2013 он работает.
AttachmentCreationInformation newAtt = new AttachmentCreationInformation();
newAtt.FileName = "myAttachment.txt";
// create a file stream
string fileContent = "This file is was ubloaded by client object meodel ";
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
byte[] buffer = enc.GetBytes(fileContent);
newAtt.ContentStream = new MemoryStream(buffer);
// att new item or get existing one
ListItem itm = list.GetItemById(itemId);
ctx.Load(itm);
// do not execute query, otherwise a "version conflict" exception is rised, but the file is uploaded
// add file to attachment collection
newAtt.ContentStream = new MemoryStream(buffer);
itm.AttachmentFiles.Add(newAtt);
AttachmentCollection attachments = itm.AttachmentFiles;
ctx.Load(attachments);
ctx.ExecuteQuery();
// see all attachments for list item
// this snippet works if the list item has no attachments
Этот метод используется в http://www.mailtosharepoint.net/
Это довольно слабо отражается на команде Microsoft SharePoint, поскольку он не продвигается с подтверждением проблемы и удобным предложением о том, как ее разрешить. Вот как я справился с этим:
Я использую новый управляемый клиент SharePoint 2010, который поставляется вместе с продуктом. Следовательно, у меня уже есть клиентский клиент SharePoint с учетными данными. Следующая функция добавляет вложение в элемент списка:
private void SharePoint2010AddAttachment(ClientContext ctx,
string listName, string itemId,
string fileName, byte[] fileContent)
{
var listsSvc = new sp2010.Lists();
listsSvc.Credentials = _sharePointCtx.Credentials;
listsSvc.Url = _sharePointCtx.Web.Context.Url + "_vti_bin/Lists.asmx";
listsSvc.AddAttachment(listName, itemId, fileName, fileContent);
}
Единственным предварительным условием для приведенного выше кода является добавление в проект (я использовал Visual Studio 2008) _web_reference_ я вызывал sp2010, который создается из URL-адреса: http:///_vti_bin/Lists.asmx
Bon Chance...
Я использовал и попробовал это в своем приложении COM, и он работает для меня
using (ClientContext context = new ClientContext("http://spsite2010"))
{
context.Credentials = new NetworkCredential("admin", "password");
Web oWeb = context.Web;
List list = context.Web.Lists.GetByTitle("Tasks");
CamlQuery query = new CamlQuery();
query.ViewXml = "<View><Where><Eq><FieldRef Name = \"Title\"/><Value Type=\"String\">New Task Created</Value></Eq></Where></View>";
ListItemCollection listItems = list.GetItems(query);
context.Load(listItems);
context.ExecuteQuery();
FileStream oFileStream = new FileStream(@"C:\\sample.txt", FileMode.Open);
string attachmentpath = "/Lists/Tasks/Attachments/" + listItems[listItems.Count - 1].Id + "/sample.txt";
Microsoft.SharePoint.Client.File.SaveBinaryDirect(context, attachmentpath, oFileStream, true);
}
Примечание. Работает только в том случае, если папка с файлами уже создана.
HTML:
<asp:FileUpload ID="FileUpload1" runat="server" AllowMultiple="true" />
Событие в коде позади:
protected void UploadMultipleFiles(object sender, EventArgs e)
{
Common.UploadDocuments(Common.getContext(new Uri(Request.QueryString["SPHostUrl"]),
Request.LogonUserIdentity), FileUpload1.PostedFiles, new CustomerRequirement(), 5);
}
public static List<string> UploadDocuments<T>(ClientContext ctx,IList<HttpPostedFile> selectedFiles, T reqObj, int itemID)
{
List<Attachment> existingFiles = null;
List<string> processedFiles = null;
List<string> unProcessedFiles = null;
ListItem item = null;
FileStream sr = null;
AttachmentCollection attachments = null;
byte[] contents = null;
try
{
existingFiles = new List<Attachment>();
processedFiles = new List<string>();
unProcessedFiles = new List<string>();
//Get the existing item
item = ctx.Web.Lists.GetByTitle(typeof(T).Name).GetItemById(itemID);
//get the Existing attached attachments
attachments = item.AttachmentFiles;
ctx.Load(attachments);
ctx.ExecuteQuery();
//adding into the new List
foreach (Attachment att in attachments)
existingFiles.Add(att);
//For each Files which user has selected
foreach (HttpPostedFile postedFile in selectedFiles)
{
string fileName = Path.GetFileName(postedFile.FileName);
//If selected file not exist in existing item attachment
if (!existingFiles.Any(x => x.FileName == fileName))
{
//Added to Process List
processedFiles.Add(postedFile.FileName);
}
else
unProcessedFiles.Add(fileName);
}
//Foreach process item add it as an attachment
foreach (string path in processedFiles)
{
sr = new FileStream(path, FileMode.Open);
contents = new byte[sr.Length];
sr.Read(contents, 0, (int)sr.Length);
var attInfo = new AttachmentCreationInformation();
attInfo.FileName = Path.GetFileName(path);
attInfo.ContentStream = sr;
item.AttachmentFiles.Add(attInfo);
item.Update();
}
ctx.ExecuteQuery();
}
catch (Exception ex)
{
throw ex;
}
finally
{
existingFiles = null;
processedFiles = null;
item = null;
sr = null;
attachments = null;
contents = null;
ctx = null;
}
return unProcessedFiles;
}