2010-06-03 7 views
13

Mam listę programu SharePoint, do której dodaję nowe elementy ListItem za pomocą modelu obiektu klienta. Dodawanie ListItems nie stanowi problemu i działa świetnie.SharePoint 2010 - Model obiektu klienta - Dodaj załącznik do ListItem

Teraz chcę dodać załączniki.

Używam SaveBinaryDirect w następujący sposób:

File.SaveBinaryDirect(clientCtx, url.AbsolutePath + "/Attachments/31/" + fileName, inputStream, true); 

Działa bez problemu tak długo jak element, który próbuję dodać załącznik do, ma już załącznik, który został dodany za pośrednictwem witryny programu SharePoint, a nie za pomocą modelu obiektu klienta.

Gdy próbuję dodać załącznik do elementu, który nie robi żadnych załączników jeszcze, otrzymuję następujące błędy (zarówno zdarzyć, ale nie z tych samych plików - ale te dwa komunikaty pojawiają się konsekwentnie):

The remote server returned an error: (409) Conflict
The remote server returned an error: (404) Not Found

Pomyślałem, że być może najpierw muszę utworzyć folder załącznika dla tego elementu. Kiedy próbuję następujący kod:

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(); 

otrzymuję komunikat o błędzie:

Cannot create folder "Lists/Ticket System/Attachment/33"

mam pełne prawa administratora dla witryny SharePoint/listy.

Jakieś pomysły, co mógłbym zrobić źle?

Dzięki, Thorben

Odpowiedz

9

Omówiłem to pytanie z firmą Microsoft. Wygląda na to, że tylko jeden sposób na zdalne tworzenie załączników to serwis internetowy List.asmx. Próbowałem również utworzyć ten podfolder i bez powodzenia.

+0

Dzięki za odpowiedź, MaxBeard. Przynajmniej świadomość, że nie jest to możliwe, jest lepsza niż próbowanie i niepowodzenie - wydaje się, że powinno być możliwe. Przy okazji, fajny blog. – Thorben

+0

To rzeczywiście wygląda tak ... zobacz moją odpowiedź na pełną próbkę kodu, jak to zrobić. –

4

Odzwierciedla to raczej słabo zespół Microsoft SharePoint, ponieważ nie ujawnił problemu i użyteczne sugestie, jak go rozwiązać. Oto, jak sobie z tym poradziłem:

Korzystam z nowego klienta zarządzanego przez SharePoint 2010, który jest dostarczany z produktem. Dlatego już mam ClientContext SharePoint z poświadczeniami. Poniższa funkcja dodaje załącznik do elementu listy:

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); 
} 

Jedynym warunkiem powyższego kodu jest dodanie do projektu (użyłem Visual Studio 2008) _web_reference_ nazwałem sp2010 który jest tworzony z adresu URL http: // /_vti_bin/Lists.asmx

Bon Chance ...

12

Walczyłem przez długi czas z tym problemem też, więc pomyślałem, że pisać kompletny przykładowy kod pokazujący jak aby pomyślnie utworzyć element listy i dodać załącznik.

Używam interfejsu API obiektu klienta do utworzenia elementu listy oraz usługi WWW SOAP w celu dodania załącznika. Dzieje się tak, ponieważ, jak zauważono w innych miejscach w Internecie, API obiektu klienta można używać tylko do dodawania załączników do elementu, w którym katalog do przesłania przedmiotu już istnieje (np. Jeśli przedmiot już posiada załącznik). W przeciwnym razie błąd 409 lub coś podobnego.Serwis internetowy SOAP radzi sobie jednak z tym OK.

Zauważ, że inną rzeczą miałem do pokonania było to, że mimo tego, że dodaje odniesienie SOAP za pomocą następującego adresu URL:

https://my.sharepoint.installation/personal/test/_vti_bin/lists.asmx

URL że VS faktycznie dodane do app.config było:

https://my.sharepoint.installation/_vti_bin/lists.asmx

musiałem ręcznie zmienić app.config z powrotem do właściwego adresu URL indziej pojawia się błąd:

List does not exist. The page you selected contains a list that does not exist. It may have been deleted by another user. 0x82000006

Tutaj jest kod:

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)); 
    } 

Mam nadzieję, że to komuś pomaga.

+1

Dzięki. Zrobiłem to dla mnie. –

+0

Używam programu Visual Studio 2012 i próby zapisania załączników pozycji listy do programu SharePoint 2010. Nie mogę znaleźć żadnych usług internetowych na moim serwerze SharePoint 2010, którego klasy i metody proxy pasują do powyższego przykładu. – Zarepheth

+2

Ok, znalazłem mój problem. W Visual Studio 2012, należy dodać "Web Reference" zamiast "Service Reference". W oknie dialogowym "Dodaj usługę odniesienia" kliknij przycisk "Zaawansowane ...". Następnie kliknij przycisk "Dodaj referencję do sieci ...". Teraz wyświetlane jest znane okno dialogowe "Dodaj odwołanie do sieci" z wcześniejszych wersji Visual Studio. – Zarepheth

0

Użyłem i próbowałem to na mojej aplikacji COM i to działa na mnie

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); 
       } 

Uwaga: Działa tylko jeśli folderu element został stworzony już

5

z SharePoint 2010 nie było mowy wgrać pierwszy załącznik do elementu listy za pomocą COM. Zalecano użycie inmstead usługi sieci Web Lists.

Z programem Sharepoint 2013 działa.

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 

Ta metoda jest stosowana w http://www.mailtosharepoint.net/

+0

Wow, dziękuję bardzo. Działa to świetnie z programem SharePoint (2013) Online i aplikacją MVC. –

+0

@sam Jeśli czegoś nie brakuje, to nie działa, chyba że używasz istniejącego ListItem. Jeśli tworzysz nowy element za pomocą metody AddItem, to nie działa. Występuje błąd informujący, że należy najpierw zapisać element, a następnie zapisać załącznik. – Thierry

+0

@sam, odbieram to, działa :) ale nie tak, jak masz to opisane w twoim fragmencie. Musisz dodać element najpierw wywołując AddItem, a następnie wywołać kod z 'GetItemById' i działa bardzo ładnie. – Thierry

0

HTML:

<asp:FileUpload ID="FileUpload1" runat="server" AllowMultiple="true" /> 

zdarzeń w kodzie za:

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; 
} 
+0

Samo opublikowanie bloku kodu nie stanowi dobrej odpowiedzi na pytanie. Proszę wyjaśnić, * jak * twoje rozwiązanie rozwiązuje zadanie OP i co dodaje do innych odpowiedzi już obecnych na pytanie. – TZHX

Powiązane problemy