Upload files to SharePoint using OData!

I posted yesterday about some pain I felt when working with SharePoint and the OData API, to balance the story this post cover some pleasure of working with it – that being uploading a file to document library using OData!

This is really easy to do, once you know how – but it’s the learning curve of Everest here which makes this really hard to get right, as you have both OData specialisations and SharePoint quirks to contend with. The requirements before we start is we need a file (as a stream), we need to know it’s filename, we need it’s content type and we need to know where it will go.

For this post I am posting to a document library called Demo (which is why OData generated the name of DemoItem) and the item is a text file called Lorem ipsum.txt. I know it is a text file, which means I also know it’s Content Type is plain/text.

The code, below, is really simple and here are what is going on:

  • Line 1: I am opening the file using the System.IO.File class, this gives me the stream I need.
  • Line 3: To communicate with the OData service I use the DataContext class which was generated when I added the service reference to the OData service and passed in the URI to the OData service.
  • Line 8: Here I create a DemoItem - remember in SharePoint everything is a list or a list item, even a document which means I need to create the item first. I set the properties of the item over the next few lines. It is vital you set these and set them correctly or it will fail.
  • Line 16: I add the item to the context, this means that it is being tracked now locally – it is not in SharePoint yet. It is vital that this be done prior to you associating the stream.
  • Line 18: I associate the stream of the file to the item. Once again, this is still only happening locally – SharePoint has not been touched yet.
  • Line 20: SaveChanges handles the actual writing to SharePoint.
using (FileStream file = File.Open(@"C:\Users\Robert MacLean\Documents\Lorem ipsum.txt", FileMode.Open))
{
    DataContext sharePoint = new DataContext(new Uri("http://<sharepoint>/sites/ATC/_vti_bin/listdata.svc"));                

    string path = "/sites/ATC/Demo/Lorem ipsum.txt";
    string contentType = "plain/text";
    DemoItem documentItem = new DemoItem()
    {
        ContentType = contentType,
        Name = "Lorem ipsum",
        Path = path,
        Title = "Lorem ipsum"
    };

    sharePoint.AddToDemo(documentItem);

    sharePoint.SetSaveStream(documentItem, file, false, contentType, path);

    sharePoint.SaveChanges();
}

Path Property

The path property which is set on the item (line 12) and when I associate the stream (line 18, final parameter) is vital. This must be the path to where the file will exist on the server. This is the relative path to the file regardless of what SharePoint site you are in for example:

  • Path: /Documents/demo.txt
    • Server: http://sharepoint1
    • Site: /
    • Document Library: Documents
    • Filename: demo.txt
  • Path: /hrDept/CVs/abc.docx
    • Server: http://sharepoint1
    • Site: /hrDept
    • Document Library: CVs
    • Filename: abc.docx

Wrap-up

I still think you need to still look at WebDav as a viable way to handle documents that do not have metadata requirements, but if you have metadata requirements this is a great alternative to the standard web services.

RHM's picture

Hi

I have tried your method but I am getting the following error

""<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?>\r\n\r\n \r\n The content type 'image/jpeg' is not supported.\r\n""

Please tell me

foreach (SPFile thisfile in folder.Files)
{
string strname = thisfile.Name;
Stream s = thisfile.OpenBinaryStream();
TasksItem newtask = new TasksItem()
{
Title = workflowProperties.Item.Title,
ContentType = "plain/text",
Path = thisfile.Url
};
context.AddToTasks(newtask);
context.SetSaveStream(newtask, s, false,"plain/text",thisfile.Url);
context.SaveChanges();
}

Visitor's picture

U'm trying toget this to work, but my sharepoint datacontext object does not have a SetSaveStream Method. Any Idea Why?

Robert MacLean's picture
Permissions when you created it could cause the SetSaveStream to not be generated if you cannot post to it or it does not have documents/attachements in the list?
Visitor's picture

I'm a site collection admin. What permissions should the user generating the proxy have to get the set setsavestream method?

Robert MacLean's picture
They'd need permissions to read the list at least.
PawelGr's picture

How to create folder in documents library this way?
I was trying to set ContentType to "Folder", also ContentTypeID to that from existing folder but nothing work correctly. When i set save stream item is saved as normal document, when not set save stream exception ocures:
System.InvalidOperationException: The entity type WindowsFormsApplication1.RESTServiceReference.MyLibraryItem is marked with MediaEntry attribute but no save stream was set for the entity.

miso's picture

Got the very exact problem like you :(( any ideas how to get rid of this?

Nick's picture

I have not looked at this in a long time, but I do know the order of how you set the properties is important. It took a ton of trail and error. It is not documented well at all, or it wasn't at the time.

miso's picture

hey! thanx for the hint... I'm undergoing the trial now :(( ... it's still not documented at all...
can not delete attachment, that I have created via the context... but I can delete attachments created via sharepoint website... aaaargggg this makes me crazy, and furthermore, I can not create an empty folder... if I attach a stream with length 0, it creates an empty document, If I dont attach... it throws exception that it needs a stream...

tearing my hair off... should have made release last friday... boss freaking out...

...Im in my happy place Im in my happy place Im in my happy place...

Nick's picture

Also I remember one thing that helped was looking at the old SOAP way of doing it. It led me to figure out what I was missing on what was being set in the SOAP function before.

miso's picture

Thank you for those tips

Andreas's picture

Hello!

Did you ever create a new folder in your documentlibrary via odata?

Best regards
Andreas

Nick's picture

Is it possible for you to post an example when the Content Type is a custom type or image? I am trying to find examples and I coming up empty. Otherwise, your example rocks. Thank you!

Robert MacLean's picture

Do you one better, here is a list of common content types based on extensions: http://www.webmaster-toolkit.com/mime-types.shtml

They are also known as MIME types (which maybe why you not finding them). Why MIME types? Wikipedia knows: http://en.wikipedia.org/wiki/Internet_media_type

Nick's picture

Thank you, I am still getting an error on save now. Error: "An error occurred while processing this request."

I am doing the Slug similarly to you and this error is leading me nowhere.

Nick's picture

Never-mind I got it working finally! Everything you had was correct, my Name in the slug and entity object were ill formatted. I had to remove a colon out of it and it is now working. Bu YAW! Thanks!

Funny how it took looking at the old soap version to figure this out.

//Old Code below
copyClient.CopyIntoItemsAsync("http://null", new string[] { "http://site/OneLibrary/" + attachment.fileName.Replace(':', '_') }, metadata, attachment.bytes);

//New code
var fileNameNoColon = attachment.fileName.Replace(':', '_');
string slug = string.Concat("/OneLibrary/",fileNameNoColon );

//Then set Entity Name to fileNameNoColon
//Then add and Save changes
context.SetSaveStream(entity, new MemoryStream(attachment.bytes), true, entity.ContentType, slug);

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Post new comment

The content of this field is kept private and will not be shown publicly. If you have a Gravatar account associated with the e-mail address you provide, it will be used to display your avatar.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • Syntax highlight code surrounded by the <pre class="brush: lang">...</pre> tags, where lang is one of the following language brushes: as3, applescript, bash, csharp, coldfusion, cpp, css, delphi, diff, erlang, groovy, jscript, java, javafx, perl, php, plain, powershell, python, ruby, sass, scala, sql, vb, xml.

More information about formatting options