Thursday, October 13, 2011

Using Client Object Model, Uploading a new document to a document library which supports different type of Content Types

Sometimes we need to upload new document whose metadata is coming from a csv file. Consider that if the document library supports custom content types then before adding the item we need to know which field columns from the csv file are need to be added to the item. The csv file contains the information of Content Type and all possible Fields as columns in the csv file. Then we need to get the corresponding content type object from the content type string present in the csv file and get all the fields that belong to that content type. Then add the data to those fields only.
Below is the sample code.
We are passing  the parameters
  • Metadat List ,
  • Binary content of the file in byte array,
  • DataRow which contains the metadata information of that document.We are getting this datarow from the DataTable which is built from the csv file,
  •  Item Url :Docuemt file name in our case its a download link from another sharepoint server.
  • Contet Type.
I have written another blog post  related to this blog post that contains some of the methods descriptions like GetMappedListItem
/// <summary>
/// Uploads the document to the document library with metadata
/// </summary>
/// <param name="metaDataList"></param>
/// <param name="content"></param>
/// <param name="dataRow"></param>
/// <param name="itemURL"></param>
/// <param name="contentType"></param>
private void UploadDocument(FieldCollection metaDataList,byte[] content,DataRow dataRow,string itemURL,string contentType)
{
  ClientContext ctx = new ClientContext(targetSiteUrl);
  Web web = ctx.Web;
  FileCreationInformation newFile = new FileCreationInformation();
  newFile.Content = content;
  newFile.Url = itemURL.Substring(itemURL.LastIndexOf("/") + 1);
  List docs = web.Lists.GetByTitle(targetListName);
  ctx.Load(docs);
  ctx.ExecuteQuery();
  Microsoft.SharePoint.Client.File uploadFile = docs.RootFolder.Files.Add(newFile);
  ctx.Load(uploadFile);
  ctx.ExecuteQuery();
  ListItem item = uploadFile.ListItemAllFields;
  //Set the metadata     
  item["Title"] = newFile.Url.Substring(0,newFile.Url.IndexOf("."));

  ContentType targetDocumentSetContentType = GetContentType(ctx,docs,contentType);
  item["ContentTypeId"] = targetDocumentSetContentType.Id.ToString();
  item.Update();
  ctx.ExecuteQuery();
           
  foreach (Field field in metaDataList)
  {
   if (!field.Hidden && !field.ReadOnlyField)
      {
        if (field.InternalName != "FileLeafRef" && field.InternalName != "ContentType" && !field.ReadOnlyField && field.Title != "Title")
          {
           if(field.FieldTypeKind==Microsoft.SharePoint.Client.FieldType.Lookup)
             {
               FieldLookup lookupField =field as FieldLookup;
               ListItem mappedListItem = null;

              if (lookupField != null)
              {
                mappedListItem = GetMappedListItem(lookupField, dataRow[field.Title].ToString());
              }
              if (mappedListItem != null)
              {
               FieldLookupValue lookupValue = new FieldLookupValue();
               lookupValue.LookupId = mappedListItem.Id;
               item[field.InternalName] = lookupValue;
              }
           }
           else
             item[field.InternalName] = dataRow[field.Title];
        }
    }
  }
           
 item.Update();
 ctx.ExecuteQuery();
 ctx.Dispose();
 }

Below is the code to Get the content types

/// <summary>
/// Gets the Content Type Object of the given content type string
/// </summary>
/// <param name="ctx"></param>
/// <param name="docs"></param>
/// <param name="contentType"></param>
/// <returns></returns>
private ContentType GetContentType(ClientContext ctx,List docs,string contentType)
{
  ContentTypeCollection listContentTypes = docs.ContentTypes;
  ctx.Load(listContentTypes, types => types.Include
           (type => type.Id, type => type.Name,
             type => type.Parent));
  var result = ctx.LoadQuery(listContentTypes.Where(c => c.Name == contentType));
  ctx.ExecuteQuery();
  ContentType targetDocumentSetContentType = result.FirstOrDefault();
  return targetDocumentSetContentType;
}