Sharepoint (MOSS): Creating Document Library Items / Uploading Files to a Document Library


Creating Sharepoint (MOSS) List items is pretty straight forward using Sharepoints Webservices, it’s also straight forward to create Sharepoint Document Library items using Sharepoints Webservices, and as a bonus you don’t have use any CAML.

Using the CopyIntoItems method of the Sharepoint Copy Webservice you can upload a new file into a document library, and/or create a new document library item based on a copy from some other Sharepoint source, i.e. a  linked copy (more on this at the end of the post). When creating the document library item this method also allows you to set the items column meta data, in one operation, anyway, enough talk more code….

private void UploadToSharepointDocumentLibrary( string documentLibraryName,
                CopySoapClient spCopySvc,
                string cDescription,
                string libraryItemUrl,
                string libraryItemFileXml)
{
 string[] targetUrls = new[] { libraryItemUrl };
 byte[] libraryItemBytes = Encoding.ASCII.GetBytes(libraryItemFileXml);

 // library item meta data (columns)
 List<FieldInformation> metaData = new List<FieldInformation>();
 var fi = new FieldInformation();
 fi.DisplayName = "Description";
 fi.InternalName = "Description0";
 fi.Type = FieldType.Note;
 fi.Value = cDescription;
 metaData.Add(fi);

 // call SP wbservice
 CopyResult[] cResults;
 spCopySvc.CopyIntoItems("+", targetUrls, metaData.ToArray(), libraryItemBytes, out cResults);
 if (cResults.Length < 1)
    writeLineTrace("Unable to create a document library item");
 else if (cResults&#91;0&#93;.ErrorCode != CopyErrorCode.Success)
 {
    writeLineTrace(
       string.Format(
          "Unable to create a document library item,{0}- ErrorCode = {1}{0}- ErrorMessage = {2}{0}- Destination Url = {3}",
            Environment.NewLine, cResults&#91;0&#93;.ErrorCode, cResults&#91;0&#93;.ErrorMessage, cResults&#91;0&#93;.DestinationUrl));
 }
 else
 {
    writeLineTrace(string.Format("Created a document library item"));
    UnlinkDocumentLibraryItem(documentLibraryName, libraryItemUrl);
 }
}&#91;/sourcecode&#93;
<blockquote><strong>Note:</strong>

<em>documentLibraryName</em> is the unencoded name of (only) the document library including space characters.

<em>libraryItemUrl</em> is the full URL of the document library item, and this URL should be URL encoded (spaces replaced with %20 etc) 

The use of the <a href="http://msdn.microsoft.com/en-us/library/copy.fieldinformation.aspx">FieldInformation</a> class to assign meta data to the document library item</blockquote>
Notice the 1st parameter to the <a href="http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitems.aspx">CopyIntoItems</a> method where I pass a "+" character. This parameter should contain the source url of the item being copied (and uploaded), however very handily, you can pass anything in this parameter except the empty string, and therefore using this technique you can introduce/upload new document library items and not just new items based on copies of items from elsewhere. The <a href="http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitems.aspx">CopyIntoItems</a> method does not validate the source url passed, so it's safe to put anything in there, except the empty string, in which case the method call fails.
<h3>Linked Copies.</h3>
Using the technique described above creates a new document library item which is based on a copy of the source item (1st parameter), what Sharepoint calls a Linked Copy. If you look at the properties for a document library item which is a linked copy you'll see something like;
<p style="text-align:center;"><img class="size-full wp-image-253 aligncenter" title="linkedcopy" src="https://platinumdogs.files.wordpress.com/2009/01/linkedcopy.jpg" alt="Linked Copy Properties" width="799" height="186" /></p>

If you pass a valid URL as the 1st parameter to <a href="http://msdn.microsoft.com/en-us/library/copy.copy.copyintoitems.aspx">CopyIntoItems</a>, then this is what you'll see when you view the new items properties. This may be a problem, or not, and as you can see you can unlink the new item (the copy!) from it's source. If you pass a space character, or the "+" sign as I've done, as the 1st parameter, when you view the new items properties you won't see this message at all, Sharepoint "mostly" treats it as if it weren't a copy. I say mostly, because if you expand the items control menu, you'll see the "Go to Source Item" menu command displayed, clicking on this however does nothing.
<p style="text-align:center;"><img class="size-full wp-image-254 aligncenter" title="ctlmenu" src="https://platinumdogs.files.wordpress.com/2009/01/ctlmenu.jpg" alt="Linked Copy Control Menu" width="418" height="274" /></p>

So, how do you completely "Unlink" a copy (even if it's a fake copy!) from it's source. The answer for me turns out not to work, however, other people seem to have had it working though so I'll present my code here, which also demonstrates nicely how you can use <a href="http://msdn.microsoft.com/en-us/library/bb387098.aspx">LINQ to XML</a> classes with Sharepoint. The UnlinkDocumentLibraryItem(...) method attempts to set the document library items internal "_CopySource" field to an empty string in order to get rid of the command menus "Go to Source Item" command, for me this doesn't work, although I get no error message, though other people have reported this to work.

private void UnlinkDocumentLibraryItem(string documentLibraryName, string libraryItemUrl)
{
 string listsSvcUrl = ConfigurationManager.AppSettings["mboscatlistsurl"];
 if (string.IsNullOrEmpty(listsSvcUrl) || string.IsNullOrEmpty(documentLibraryName) ||
         string.IsNullOrEmpty(libraryItemUrl))
  return;
 // create a service binding with security
 var svcBinding = CreateBinding<BasicHttpBinding>(new TimeSpan(0, 10, 0));
 CreateSecurityBinding(svcBinding);
 // create the svc
 EndpointAddress listsSvcEndpoint = new EndpointAddress(listsSvcUrl);
 var spListsSvc = new ListsSoapClient(svcBinding, listsSvcEndpoint);
 spListsSvc.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Impersonation;
 // create the CAML query
 var caml = new XElement("Batch"
         , new XAttribute("OnError", "Continue")
         , new XAttribute("PreCalc", "TRUE")
         , new XElement("Method"
              , new XAttribute("ID", "1")
              , new XAttribute("Cmd", "Update")
              , new XElement("Field"
                   , new XAttribute("Name", "ID")
               )
              , new XElement("Field"
                   , new XAttribute("Name", "FileRef")
                   , new XText(libraryItemUrl.Replace("%20", " "))
               )
              , new XElement("Field"
                   , new XAttribute("Name", "_CopySource")
                   , new XText("")
               )
          )
  );
 XmlNode ndResults = spListsSvc.UpdateListItems(documentLibraryName, caml.GetXmlElement());
 var listItemResult = CheckListUpdateResults(ndResults);
 if (listItemResult.Key < 1)
    writeLineTrace(string.Format("Unable to Unlink system exception report @ Mbos: {0}", listItemResult.Value));
 else
    writeLineTrace(string.Format("Unlinked system exception report @ Mbos"));
}&#91;/sourcecode&#93;
<blockquote><strong>Note:</strong>
<em>documentLibraryName</em> is the unencoded name of (only) the document library including space characters.

<em>libraryItemUrl</em> is the full URL of the document library item, and this URL should not be URL encoded (%20 replaced with space etc).

The use of the <em>FileRef</em> field in the CAML query which is used to locate the document library item to update, in contrast to updating List items which requires the <em>ID</em> field be used to locate the list item to update.

Check here for the <a href="https://platinumdogs.wordpress.com/2008/12/16/checking-sharepoint-updatelistitems-xml-result/">CheckListUpdateResults(...)</a> method.</blockquote>
In order to use <a href="http://msdn.microsoft.com/en-us/library/bb387098.aspx">LINQ to XML</a> classes with Sharepoint Webservices, you'll need to convert an <a href="http://msdn.microsoft.com/en-us/library/system.xml.linq.xelement.aspx">XElement </a>to say an <a href="http://msdn.microsoft.com/en-us/library/system.xml.xmlnode.aspx">XmlNode</a> and vice versa, and C# 3.0 extension methods are perfect for this

public static class MyExtensions
{
 public static XElement GetXElement(this XmlNode node)
 {
     XDocument xDoc = new XDocument();
     using (XmlWriter xmlWriter = xDoc.CreateWriter())
     {
        node.WriteTo(xmlWriter);
     }
     return xDoc.Root;
 }

 public static XmlNode GetXmlNode(this XElement element)
 {
     var xnNode = (XmlNode)GetXmlDocument(element);
     return xnNode;
 }

 public static XmlDocument GetXmlDocument(this XElement element)
 {
     using (XmlReader xmlReader = element.CreateReader())
     {
         XmlDocument xmlDoc = new XmlDocument();
         xmlDoc.Load(xmlReader);
         return xmlDoc;
     }
 }

 public static XmlElement GetXmlElement(this XElement element)
 {
     var xeNode = GetXmlDocument(element).DocumentElement;
     return xeNode;
 }
}

.

Published by

Phil Harding

SharePoint Consultant, Developer, Father, Husband and Climber.

6 thoughts on “Sharepoint (MOSS): Creating Document Library Items / Uploading Files to a Document Library

  1. CopyIntoItems will overwrite the target file if the target file exists. Is there a simple method to check whether the target file already exists?

    Thanks

  2. Hi Phil,
    Have you heard of any issues with using copyintoitems for libraries with versioning enabled? I’m trying to “copy” a file from my local machine. The CopyResult error message keeps telling me that the underlying collection has been modified while enumerating – and none of my metadata gets applied. It works fine on doc libs without versioning.

    Scratching head…

  3. Hi Eve, I’ve not come across this before, have you tried his sequence: Checkout, Upload, Checkin?

    The Lists webservice has methods to do the CheckIn/Out

  4. 0

    down vote
    favorite
    share [fb]
    share [tw] **I am trying to assign Title to already existing document in document library using copyIntoItems(). I am giving inoput as : Title,ID,FileName

    Method giving an error as “Value does not fall within expected range”

    But if I provide SourceFullPath,Title,ID,FileName

    Then it works fine. But I dont want to provide D:\test.txt here.

    Can anybody suggest solution???**

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.