Search code examples
c#sharepointsharepoint-2010

C# SharePoint Client List Attachment


I'm trying to attach a file to a list on our sharepoint.

I can create the list item programmatically but I can't attach the attachment. Either it gives me an 401 not allowed error (which can't be becouse I have Full Access to the list) or the executeQuery hangs forever until timeout.

Here's my current code: (WPF Application)

        ClientContext clientContext = new ClientContext("http://<SITE-URL>/sites/Team-Place/<TeamPlace-ID>/");
        clientContext.RequestTimeout = int.MaxValue;

        FileStream sr = new FileStream("Test.pdf", FileMode.Open);
        byte[] contents = new byte[sr.Length];
        sr.Read(contents, 0, (int)sr.Length);

        SP.List List = clientContext.Web.Lists.GetByTitle("<List Title>");

        if (List != null)
        {
            CamlQuery camlQuery = CamlQuery.CreateAllItemsQuery();
            SP.ListItemCollection Collection = List.GetItems(camlQuery);
            clientContext.Load(List);
            clientContext.Load(List.Fields);
            clientContext.Load(Collection);
            clientContext.ExecuteQuery();

            foreach (var x in List.Fields)
                Debug.AppendText(x.InternalName + "\n");

            ListItemCreationInformation creationInfo = new ListItemCreationInformation();
            SP.ListItem Item = List.AddItem(creationInfo);

            Item["Title"] = "Test";
            Item["Modell"] = "Test";
            Item["Seriennummer"] = "testserial";
            Item["Ger_x00e4_te_x002d_Typ"] = "Laptop";

            Item.Update();
            clientContext.ExecuteQuery();
            clientContext.Load(Item);
            clientContext.ExecuteQuery();

            var attInfo = new AttachmentCreationInformation();
            attInfo.FileName = "Test.pdf";
            attInfo.ContentStream = sr;
            var att = Item.AttachmentFiles.Add(attInfo);

            Item.Update();

            clientContext.Load(att);
            clientContext.Load(Item);
            clientContext.ExecuteQuery();

            //System.Diagnostics.Debug.WriteLine(att.ServerRelativeUrl);

            Item.Update();
            clientContext.ExecuteQuery();
            /*
             * Not working pice of S#@*
            string attachmentPath = string.Format("/Lists/Inventur_MOBI/Attachments/{0}/{1}", Item.Id, "Test.pdf");
            SP.File.SaveBinaryDirect(clientContext, attachmentPath, sr, false);
            */
        }
        else
            Debug.AppendText("List not found");

I did "censor" some thing out. The SaveBinardDirect method gives me an 401 not allowed and the Attachment gives an timeout. We have a Sharepoint 2013.

Does someone have an idea?

Regards BlueFire


Solution

  • Your code have two problems.

    First, using FileStream to read file, and then using it with AttachmentCreationInformation object. Change it to:

    byte[] contents = null;
    using (FileStream sr = new FileStream("Test.pdf", FileMode.Open))
    {
        contents = new byte[sr.Length];
        sr.Read(contents, 0, (int)sr.Length);
    }
    
    //...
    
    using (MemoryStream ms = new MemoryStream(contents))
    {
        var attInfo = new AttachmentCreationInformation();
        attInfo.FileName = "Test.pdf";
        attInfo.ContentStream = ms;
        // ...
    }
    

    Second, after you create your new ListItem object retreive it once again to protect you from save conflicts. Use:

    ListItem newItem = List.AddItem(creationInfo);
    newItem["Title"] = "Test";
    // ...
    
    newItem.Update();
    clientContext.Load(newItem, i => i.Id);
    clientContext.ExecuteQuery();
    
    var item = List.GetItemById(newItem.Id);
    
    using (MemoryStream ms = new MemoryStream(contents))
    {
        // ...
        var att = item.AttachmentFiles.Add(attInfo);
        item.Update();
        clientContext.ExecuteQuery();
    }
    

    Oh, and for 401 Unathorized you need to pass credentials to ClientContext:

    clientContext.Credentials = new NetworkCredential("user", "password", "domain");