Tuesday, October 23, 2007

Upload a File to a SharePoint Document Library - Part I

The following helper class demonstrates a few techniques that allow documents to be uploaded to a SharePoint document library programmatically without using the API or a custom web service. You don't need to specify a document library name, and it will create any folders specified in the URL as required. File meta data will be updated if any properties are passed.

To use this code add a reference to the SharePoint Lists service (/_vti_bin/Lists.asmx) and name it ‘ListsService’. The code was written against MOSS 2007.

To download files use the GetItem method of the SharePoint Copy service (/_vti_bin/Copy.asmx). While it’s possible to upload files using the CopyIntoItems method of this service, it won’t create folders as needed, and you’d probably want to remove the copy link that is created.

It's also possible to use Front Page Server Extensions and RPC calls to upload files with meta data - the code for which is a bit more efficient as it doesn't require web service calls. Using RPC calls is covered in Part II.

Update: You can download a comprehensive c# class library to automate RPC calls - including uploading files to a SharePoint document library. See this blog post for more information.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Xml;
 
namespace DevHoleDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            DocLibHelper docLibHelper = new DocLibHelper();
            Dictionary<string, object> properties = new Dictionary<string, object>();
            properties.Add("Title", "Test Title");
            //Create or overwrite text file test.txt in 'Docs' document library creating folder 'Test Folder' as required.
            docLibHelper.Upload("http://localhost/Docs/Test Folder/test.txt", System.Text.Encoding.ASCII.GetBytes("Test text."), properties);
        }
    }
 
    public class DocLibHelper
    {
        ListsService.Lists m_listService;
        ICredentials m_credentials;
        ListInfoCollection m_lists;
 
        public DocLibHelper()
        {
            m_credentials = CredentialCache.DefaultCredentials;
            m_listService = new ListsService.Lists();
            m_listService.Credentials = m_credentials;
            m_lists = new ListInfoCollection(m_listService);
        }
 
        public class ListInfo
        {
            public string m_rootFolder;
            public string m_listName;
            public string m_version;
            public string m_webUrl;
            public ListInfo(XmlNode listResponse)
            {
                m_rootFolder = listResponse.Attributes["RootFolder"].Value + "/";
                m_listName = listResponse.Attributes["ID"].Value;
                m_version = listResponse.Attributes["Version"].Value;
            }
            public bool IsMatch(string url)
            {
                try
                {
                    url += "/";
                    return url.Substring(0, m_rootFolder.Length) == m_rootFolder;
                }
                catch { }
                return false;
            }
        }
 
        public class ListInfoCollection : IEnumerable<ListInfo>
        {
            ListsService.Lists m_listService;
            Dictionary<string, ListInfo> m_lists = new Dictionary<string, ListInfo>();
            public ListInfoCollection(ListsService.Lists listService)
            {
                m_listService = listService;
            }
            public IEnumerator<ListInfo> GetEnumerator()
            {
                return m_lists.Values.GetEnumerator();
            }
            IEnumerator IEnumerable.GetEnumerator()
            {
                return this.GetEnumerator();
            }
            public ListInfo Find(FileInfo fileInfo)
            {
                if (m_lists.ContainsKey(fileInfo.LookupName))
                    return m_lists[fileInfo.LookupName];
                foreach (ListInfo li in m_lists.Values)
                    if (li.IsMatch(fileInfo.LookupName)) return li;
                string webUrl = fileInfo.m_URL;
                if (fileInfo.m_listInfo != null && !string.IsNullOrEmpty(fileInfo.m_listInfo.m_listName))
                {
                    ListInfo listInfo = new ListInfo(CallService(ref webUrl, delegate { return m_listService.GetList(fileInfo.LookupName); }));
                    listInfo.m_webUrl = webUrl;
                    return listInfo;
                }
                else
                {
                    XmlNode lists = CallService(ref webUrl, delegate { return m_listService.GetListCollection(); });
                    if (lists == null) throw new Exception("Could not find web.");
                    //Find list by RootFolder (which doesn't seem to be populated in GetListCollection response so must iterate GetList response)
                    foreach (XmlNode list in lists.ChildNodes)
                    {
                        ListInfo listInfo = new ListInfo(m_listService.GetList(list.Attributes["Name"].Value));
                        listInfo.m_webUrl = webUrl;
                        m_lists.Add(listInfo.m_listName, listInfo);
                        if (listInfo.IsMatch(fileInfo.LookupName))
                            return listInfo;
                    }
                }
                throw new Exception("Could not find list.");
            }
            private delegate XmlNode ServiceOperation();
            private XmlNode CallService(ref string webURL, ServiceOperation serviceOperation)
            {
                try
                {
                    webURL = webURL.Substring(0, webURL.LastIndexOf("/"));
                    try
                    {
                        m_listService.Url = webURL + "/_vti_bin/Lists.asmx";
                        return serviceOperation();
                    }
                    catch
                    {
                        return CallService(ref webURL, serviceOperation);
                    }
                }
                catch
                {
                    webURL = null;
                    return null;
                }
            }
        }
 
        public class FileInfo
        {
            public string m_URL;
            public byte[] m_bytes;
            public Dictionary<string, object> m_properties;
            public ListInfo m_listInfo;
            public bool m_ensureFolders = true;
            private Uri m_uri;
            public bool HasProperties
            {
                get { return m_properties != null && m_properties.Count > 0; }
            }
            public string RelativeFilePath
            {
                get { return m_URL.Substring(m_URL.IndexOf(m_listInfo.m_rootFolder) + 1); }
            }
            public Uri URI
            {
                get
                {
                    if (m_uri == null) m_uri = new Uri(m_URL);
                    return m_uri;
                }
            }
            public string LookupName
            {
                get
                {
                    if (m_listInfo != null && !string.IsNullOrEmpty(m_listInfo.m_listName))
                        return m_listInfo.m_listName;
                    return URI.LocalPath;
                }
            }
            public FileInfo(string url, byte[] bytes, Dictionary<string, object> properties)
            {
                m_URL = url.Replace("%20", " ");
                m_bytes = bytes;
                m_properties = properties;
            }
        }
 
        public bool Upload(string destinationUrl, byte[] bytes, Dictionary<string, object> properties)
        {
            return Upload(new FileInfo(destinationUrl, bytes, properties));
        }
 
        public bool Upload(FileInfo fileInfo)
        {
            if (fileInfo.HasProperties)
                fileInfo.m_listInfo = m_lists.Find(fileInfo);
            bool result = TryToUpload(fileInfo);
            if (!result && fileInfo.m_ensureFolders)
            {
                string root = fileInfo.URI.AbsoluteUri.Replace(fileInfo.URI.AbsolutePath, "");
                for (int i = 0; i < fileInfo.URI.Segments.Length - 1; i++)
                {
                    root += fileInfo.URI.Segments[i];
                    if (i > 1) CreateFolder(root);
                }
                result = TryToUpload(fileInfo);
            }
            return result;
        }
 
        private bool TryToUpload(FileInfo fileInfo)
        {
            try
            {
                WebRequest request = WebRequest.Create(fileInfo.m_URL);
                request.Credentials = m_credentials;
                request.Method = "PUT";
                byte[] buffer = new byte[1024];
                using (Stream stream = request.GetRequestStream())
                using (MemoryStream ms = new MemoryStream(fileInfo.m_bytes))
                    for (int i = ms.Read(buffer, 0, buffer.Length); i > 0; i = ms.Read(buffer, 0, buffer.Length))
                        stream.Write(buffer, 0, i);
                WebResponse response = request.GetResponse();
                response.Close();
                if (fileInfo.HasProperties)
                {
                    StringBuilder sb = new StringBuilder();
                    sb.Append("<Method ID='1' Cmd='Update'><Field Name='ID'/>");
                    sb.AppendFormat("<Field Name='FileRef'>{0}</Field>", fileInfo.m_URL);
                    foreach (KeyValuePair<string, object> property in fileInfo.m_properties)
                        sb.AppendFormat("<Field Name='{0}'>{1}</Field>", property.Key, property.Value);
                    sb.Append("</Method>");
                    System.Xml.XmlElement updates = (new System.Xml.XmlDocument()).CreateElement("Batch");
                    updates.SetAttribute("OnError", "Continue");
                    updates.SetAttribute("ListVersion", fileInfo.m_listInfo.m_version);
                    updates.SetAttribute("PreCalc", "TRUE");
                    updates.InnerXml = sb.ToString();
                    m_listService.Url = fileInfo.m_listInfo.m_webUrl + "/_vti_bin/Lists.asmx";
                    XmlNode updatesResponse = m_listService.UpdateListItems(fileInfo.m_listInfo.m_listName, updates);
                    if (updatesResponse.FirstChild.FirstChild.InnerText != "0x00000000")
                        throw new Exception("Could not update properties.");
                }
                return true;
            }
            catch (WebException)
            {
                return false;
            }
        }
 
        private bool CreateFolder(string folderURL)
        {
            try
            {
                WebRequest request = WebRequest.Create(folderURL);
                request.Credentials = m_credentials;
                request.Method = "MKCOL";
                WebResponse response = request.GetResponse();
                response.Close();
                return true;
            }
            catch (WebException)
            {
                return false;
            }
        }
    }
}

69 comments:

  1. What's wrong with HTTP "PUT"?

    ReplyDelete
  2. Nothing - the code above does use HTTP PUT to write the file, and if a simple write is all you want to do then you're right - that's all you need.

    If you want to write meta data though you have to do a bit more than that. The code above goes a step beyond that, because it discovers the document library name from the URL, creates any folders, and persists the list information so it doesn't have to re-query the web service.

    ReplyDelete
  3. It works for a document library, like intended.
    But is it possible to make it work with a custom list? I've tried it it, but no success.

    ReplyDelete
  4. ! The code DOES seem to work , because i can see the file in the custom list. But i do get an error: 0x81020016 wich seems to mean that it thinks the file does not exist.

    So if i just ignore this "error" it should work.

    ReplyDelete
  5. Yeah, could be a bit dodgy. For custom lists, you might want to take a look at the AddAttachment operation that the Lists web service provides. It won't work for uploading files to document libraries but it might be what you're after.

    ReplyDelete
  6. Oooh, I've been looking for something like this, but what I'd really like is to be able to post a chunk of HTML up to a specified Sharepoint Wiki page. How would one go about that?

    ReplyDelete
  7. Hey!

    I use your code in a case. Everything works fine with doc files. But when I try to upload a docx file some bytes are lost and the document gets corrupted. Please help!

    ReplyDelete
  8. Hi!

    Can you please test this with docx and doc documents with som images in it?

    ReplyDelete
  9. I tested for docx and it works ok for me, e.g.:

    docLibHelper.Upload("http://localhost/Docs/Test Folder/Test.docx", File.ReadAllBytes(@"D:\Temp\Test.docx"), properties);

    If all the bytes are getting uploaded, I would guess it's a machine related issue. Try testing on a different machine or user profile. Clearing your temporary internet files can sometimes fix browser problems. Also, there's a second post (Part II) that uses a different technique for uploading if you're convinced it's the code in this example.

    ReplyDelete
  10. Part II worked fine with uploading both docx and doc.
    Now I have problem with uploading the metadata with docx in Part II. With doc everything workes fine.
    Thank you for your help.

    ReplyDelete
  11. Receiving error 0x80070005 (Error occurred when updating list.)

    I have admin privledges, so I wouldn't expect it to be a security issue, but everything I've read points to that...Any ideas?

    ReplyDelete
  12. hi

    iam getting an error like file not found(404) . i tried to upload a document to document library and even when i try to create a folder , i got the same error. can you help me in fixing this ?

    ReplyDelete
  13. Hi,

    Great code! I noticed that the version history is incremented by a version once the file metadata has been added. It would be nice if when uploading it would keep the same version when the initital file metadata is added (i.e. for custom content types/columns on the document library). Do you think that this is actually possible using your code?

    ReplyDelete
  14. First let me say that I appreciate this code a lot. Now the problem:

    I am trying to hit a server elsewhere in out environment. I am creating a new NetworkCredential and passing in args that work when I enter them manually to hit my SharePoint site.

    However, when I try to use them TryToUpload method I get an error at

    WebResponse response = request.GetResponse();

    The error is:


    base {System.InvalidOperationException} = System.InvalidOperationException

    base {object} = object
    _COMPlusExceptionCode = -532459699

    This appears to be a security issue.

    Any thoughts? The credentials work fine to interrogate the lists and such. It seems to be tripping up on the upload.

    Thanks,

    Sean

    ReplyDelete
  15. Sean - I'm not sure that I've come across that one before. Someone posting here seemed to have a similar issue - perhaps adding a line like -

    request.Proxy = m_listService.Proxy;

    immediately after the line

    request.Credentials = m_credentials;

    - might help. If not, take a look at the RPC code posted in Part II of this article for an alternative remote upload method.

    ReplyDelete
  16. Have anyone got the VB version of this code.

    ReplyDelete
  17. Hi, very good code!!! But I have a problem! When I try upload a file with parameters I received the error "0x80070005" The file was upload, but my fields are not updated.

    ReplyDelete
  18. André - error code 0x80070005 can indicate that the user credentials passed to the lists web service do not have rights to update the list.

    ReplyDelete
  19. Hey to start I want to say Thanks A LOT for this post it really helped me out getting something going.

    If you have time, I was wondering what I would have to do to remove the "overwrite" fuctionality. If the file already exists, I need it to error out.

    Thanks again.

    ReplyDelete
  20. Frank,

    Take a look at the If-None-Match request header.

    e.g.:

    request.Method = "PUT";
    request.Headers.Add("If-None-Match", "*");

    Alternatively, the RPC method in Part II of this post includes an overwrite "putOption".

    ReplyDelete
  21. Nice idea and good coding!
    I used another hack for uploading to a DocLib using existing Web Services:
    1. Upload the file to an ImageLib with Imaging.Upload
    2. Copy/Move the file with Copy.CopyIntoItemsLocal

    since it uses existing Web Services, it only needs ~70 lines of code.

    Source and sample project is available at http://blog.janus.cx/archives/251-Uploading-any-file-to-a-SharePoint-DocumentLibraray-using-WebServices.html

    ReplyDelete
  22. Great post!

    I'm following the basic structure of the article to upload to a document library via HTTP PUT. It works great.

    Here's one problem I'm having though ... if versioning is turned on for the document library AND require check out is set to yes for the document library, then after the doc is uploaded it remains checked out. See this URL for more details:

    http://sharemypoint.wordpress.com/2007/12/20/automatically-checkin-files-after-uploading/

    So you think solving this problem would be easy -- just use the Lists.CheckInFile web service call to execute the check in. However, this is not working. WSS is returning the following error:

    The system cannot find the file specified. (Exception from HRESULT: 0x80070002)

    After playing around some more, if I take the URL to the newly uploaded file (the same one I pass to CheckInFile) and paste that URL into a new browser window, the browser window returns a 404 PAGE NOT FOUND error. However, if open a new browser window, login to my SharePoint site, *then* paste the URL into the browser window, the document opens fine.

    Thus, for new documents that have yet to be checked in, SP is apparently throwing a 404 unless you are already logged in. Thus, the CheckInFile web service call must be failing for the same reason.

    Other ways you can think of to work around this? Can check in be done via a RPC call or something?

    Here's what I'm after:

    - Configure doc library to enable versioning (major OR minor/major) and Require Check Out = "yes"
    - Upload document via HTTP PUT, as outlined in your post
    - Immediately after upload, check document in

    Thanks in advance!

    ReplyDelete
  23. Yep - check-in can be done via FrontPage Server Extensions RPC calls (see the checkin document method on MSDN).

    Check out the post below - you can download code from our site that wraps most of the FPSE methods and provides additional functionality.

    http://geek.hubkey.com/2008/07/programatically-manage-remote-documents.html

    ReplyDelete
  24. Hello!

    Just wanted to start by saying Great Work! and thanks for sharing.

    If you have some time, I was wondering what this was doing --

    if (updatesResponse.FirstChild.FirstChild.InnerText != "0x00000000") throw new Exception("Could not update properties.");


    I get that exception randomly from users. Some times they can close out and redo it and it works. So, I'm guessing that "0x00000000" means that it was successful. But, is there anyway to determine why it wasn't?

    Thanks a lot!

    -Mike

    ReplyDelete
  25. Mike, yep error code 0 means success. You can get a description of the error code by parsing the returned xml for the ErrorText element if the error code is non-zero, e.g.

    throw new Exception(updatesResponse.FirstChild.FirstChild.NextSibling.InnerText);

    ReplyDelete
  26. Hi, It is working great! But i have one question: how do i fill in metadata for datetime fields?

    ReplyDelete
  27. Ben, format your DateTime fields in the ISO 8601 format with a time zone designator for the zero UTC offset after it (a 'Z'). The DateTime field should in the local time zone (i.e. not actually converted to UTC).

    e.g.

    properties.Add("dateandtime", DateTime.Now.ToString("s") + "Z");

    ReplyDelete
  28. This is great. Thank you!!!

    ReplyDelete
  29. I am new to development with Sharepoint. Why would it be beneficial to write to solve the upload problem INDEPENDENT OF THE SHAREPOINT API?

    ReplyDelete
  30. apg - the API is implemented through dlls that are installed on the server only. Even if you have the dlls installed on a client machine, you'll receive a FileNotFoundException when trying to connect to a remote server. This is because the "SharePoint object model can only be used when the application is run on a server in the SharePoint farm. It cannot be executed remotely." (See the first problem resolution in the SharePoint Development and Programming FAQ.)

    An example of uploading a file that resides locally on the server using the API can be found here.

    ReplyDelete
  31. Thanks a lot, it worked with Doc Libs but i have a problem with Custom Lists. I just have one field "Title", when i had the property it returns:

    "0x81020016Item does not exist\n\nThe page you selected contains an item that does not exist. It may have been deleted by another user."

    I need help over here, how can a page "COUNTAINS" something that does not exist :S

    ReplyDelete
  32. Juan - this code will only work with document libraries. We'll be posting about an easy way to remotely update SharePoint lists in the near future. Thanks.

    ReplyDelete
  33. The code works, but I haven`t understood why some files are well uploaded, but another - otherwise!
    The code retruns me the error 409, when WebResponse response = request.GetResponse(); was executing! Could you please make me clear in this problem?

    ReplyDelete
  34. What a great solution! Everything worked on first try! Thanks, it saved my day!

    ReplyDelete
  35. Great Piece of code. Thank you

    I've a question. If I want to retain Id, Create, Modified, Author and Editor how would I do that. I tried sending as a properties but, it didn't seems to be working.

    Any help will be appreciated

    ReplyDelete
  36. Hi Ramesh,

    Take a look at my reply to the first comment in Part II of this post - hopefully that'll point you in the right direction re authorship. ID is an uniquifier assigned by SharePoint so you won't be able to specify that - the creation date/time is also written by SharePoint.

    ReplyDelete
  37. Thanks Txs8311 for the quick reply.

    hmm. if we do the content migration they are able to retain all the info. Is it possible if I do a OM then?

    Also, for the custom list I made small change to the code so that it updates custom list bymaking changes to TrytoUpload as follows

    private bool TryToUpload(FileInfo fileInfo)
    {
    try
    {
    WebRequest request = WebRequest.Create(fileInfo.m_URL);
    request.Credentials = m_credentials;
    request.Method = "PUT";
    if (fileInfo.m_bytes != null)
    {
    byte[] buffer = new byte[1024];
    using (Stream stream = request.GetRequestStream())
    using (MemoryStream ms = new MemoryStream(fileInfo.m_bytes))
    for (int i = ms.Read(buffer, 0, buffer.Length); i > 0; i = ms.Read(buffer, 0, buffer.Length))
    stream.Write(buffer, 0, i);
    WebResponse response = request.GetResponse();
    response.Close();

    if (fileInfo.HasProperties)
    {
    StringBuilder sb = new StringBuilder();

    'removed the code for the fields here


    System.Xml.XmlElement updates = (new System.Xml.XmlDocument()).CreateElement("Batch");
    updates.SetAttribute("OnError", "Continue");
    updates.SetAttribute("ListVersion", fileInfo.m_listInfo.m_version);
    updates.SetAttribute("PreCalc", "TRUE");
    updates.InnerXml = sb.ToString();
    m_listService.Url = fileInfo.m_listInfo.m_webUrl + "/_vti_bin/Lists.asmx";
    XmlNode updatesResponse = m_listService.UpdateListItems(fileInfo.m_listInfo.m_listName, updates);
    if (updatesResponse.FirstChild.FirstChild.InnerText != "0x00000000")
    throw new Exception("Could not update properties.");
    }
    }
    else
    {
    UpdateListItem(fileInfo);
    }
    return true;
    }
    catch (WebException)
    {
    return false;
    }
    }


    //New Method to update the custom list

    private bool UpdateListItem(FileInfo fileInfo)
    {
    System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
    System.Xml.XmlElement batchElement = doc.CreateElement("Batch");
    batchElement.SetAttribute("OnError", "Continue");
    batchElement.SetAttribute("ListVersion", "1");
    batchElement.SetAttribute("PreCalc", "TRUE");
    //batchElement.SetAttribute("ViewName", strViewID);

    StringBuilder sb = new StringBuilder();

    'removed code for the method


    batchElement.InnerXml = sb.ToString();
    m_listService.Url = fileInfo.m_listInfo.m_webUrl + "/_vti_bin/Lists.asmx";
    XmlNode updatesResponse = m_listService.UpdateListItems(fileInfo.m_listInfo.m_listName, batchElement);
    if (updatesResponse.FirstChild.FirstChild.InnerText != "0x00000000")
    throw new Exception("Could not update properties.");
    return true;

    }


    and when you call Upload pass null for the File bytes

    docLibHelper.Upload("http://localhost/NewSite/Lists/" + listName, null, properties);

    Thanks
    Ramesh

    ReplyDelete
  38. Hi,
    Please help a newbie: When I use VS2008, should I create a ServiceReference or a webreference to make this work?
    No matter what I try, I get this:
    (It is driving me nuts!)

    "The type or namespace name 'ListsService' could not be found (are you missing a using directive or an assembly reference?) D:\SP_uploader_using_web_services\SP_uploader_using_web_services\Program.cs 69 13 SP_uploader_using_web_services
    "
    Thanks in advance!
    /Björn

    ReplyDelete
  39. Hey Björn,

    When you create the Web Reference to the SharePoint Lists service (/_vti_bin/Lists.asmx) and name it ‘ListsService’, VS2008 automatically generates code with the default namespace (e.g. ConsoleApplication1) for your project (to change this, see the properties tab - right click on your project in the solution explorer). Couple of easy fixes: either change the default namespace to DevHoleDemo before adding the reference, or change the namespace from DevHoleDemo to your default namespace. You can also view the code that is generated when the reference is added by clicking the Show All Files button in the solution explorer, and then expanding the web references tree until you get to Reference.cs - you'll be able to see what namespace is being used in the generated code there.

    ReplyDelete
  40. Thanks, this is very useful. One question, when I add lists.asmx as a service reference in a test dialog app in vs2008 it says it cannot find "Lists", I'm using MOSS2007?

    ReplyDelete
  41. Hi Ramesh!
    Great application! I learned a lot when studying your source code!

    Unfortunately I get the same error 409 when using the web request.
    Can you give me a hint?

    I also tried it with adminstrative credentials - no difference. The URL seemed to be OK, too.

    Kind regards,
    Howy

    ReplyDelete
  42. Sharepoint noob here. How do I use this code to upload all files in a local directory to a document list?

    ReplyDelete
  43. Something like this:

    static void Main(string[] args)
    {
    DocLibHelper docLibHelper = new DocLibHelper();
    DirectoryInfo di = new DirectoryInfo(@"C:\Temp");
    foreach (FileInfo fi in di.GetFiles())
    docLibHelper.Upload(string.Format("http://localhost/Docs/{0}", fi.Name), File.ReadAllBytes(fi.FullName), null);
    }

    ReplyDelete
  44. Does this code support all column data types? If so, what is the format that they should be passed in?

    For example, I'm having a problem with People column type in my code. Is it as simple as "DOMAIN\\User"?

    Please send me a message at jonathancifuentes(at)live.com
    if you know.

    ReplyDelete
  45. Interestingly, if you upload a file where the document library does not exist you do not get an error. Something DOES get uploaded because if you then create the library, the url of it has a 1 appended (as if it found a conflicting name). Weird.

    ReplyDelete
  46. Hi,
    I tried uploading a document using this class, the document get uploaded with no issues. But how can I get the Id of the document uploaded. On the updateRespose i can only see ErrorCode node. No z:row node is returned.

    ReplyDelete
  47. Hi txs8311 and Björn,
    I get the same error as the "The type or namespace name 'UserProfileService' does not exist in the namespace 'CreateUserProfile.UserProfileService' (are you missing an assembly reference?)"

    Can you pl elaborate what you meant by looking into the Reference.cs file. I don't think I understood properly.
    Thanks.
    Zullu

    ReplyDelete
  48. Hi Zullu,

    This looks a bit off topic, but you're trying to use the UserProfileService web service?

    If so, take a look at the following code:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using ConsoleApplication1.CreateUserProfile;

    namespace ConsoleApplication1
    {
    class Program
    {
    static void Main(string[] args)
    {
    UserProfileService proxy = new UserProfileService();
    PropertyData[] d = proxy.CreateUserProfileByAccountName("newAccountName");
    }
    }
    }

    I added the namespace ConsoleApplication1.CreateUserProfile with the line "using ConsoleApplication1.CreateUserProfile;"

    This will include the code that was generated automatically when I added a reference to the web service. If you show all files in the VS solution explorer (use the show all files button at the top) and then expand the reference until you see the code (reference.cs) you'll see the namespace you need to add.

    Hope this helps.

    ReplyDelete
  49. txs8311,
    Thanks for your prompt reply.
    Yes, I am using the UserProfileService web service. But here I have the same problem as any other web service.
    I understand what you are trying to explaing here with your code. I already have that line "using CreateUserProfile.UserProfileService;" in my code, but I still get the same error.
    I am not sure why you are not a compile error while instantiating the "proxy" in line:
    UserProfileService proxy = new UserProfileService();
    I am stuck, can you provide some more help.
    Thanks in advance.
    Zullu

    ReplyDelete
  50. Hey! Has anyone had any trouble with file overwrite using this method? I have implemented this technique in my own document provider, however once I've uploaded once, any subsequent uploads do not overwrite. No exceptions are thrown, and I can step through the whole process, however the same file remains in WSS afterwards. How can this be?!

    ReplyDelete
  51. Hi,
    I used your file uploading code and it is working like a charm in MOSS2007/Win2003 environment. But when I tried the same thing in MOSS2007/Win2008/Vista environment, the Upload function throws "405 Method Not Allowed" error. Is there anything I have to change in the code in order to work with MOSS2007 hosted on Win2008.
    Thanks
    NK

    ReplyDelete
  52. Hi!
    I tried the solution but every time I run I receive a catch that says that it cannot find the list.
    I have tried different variations of the list but cannot get by the message.
    I changed the sharepoint location to my own and put in a structure that didn't exist. Other than that there are no changes.

    Whate else might be wrong.

    ReplyDelete
  53. Hi, can you help me
    How upload file from sharepoint to ms crm 4 annotations for example?
    I have full url to file

    ReplyDelete
  54. It was bugging out with bigger files, so I switched the byte[] to a FileStream derived from File.OpenRead(filepath).. Hope that helps someone else!

    ReplyDelete
  55. Great post... Also agree with the comment about swithing the code to make use of file stream rather than byte array...

    ReplyDelete
  56. A few people have noted that they cannot find the Lists object in their ListService object.

    Error: The type or namespace name 'Lists' does not exist in the namespace 'ListsService' (are you missing an assembly reference?)

    Make sure you add Lists.asmx service as a Web Reference, not a Service Reference. This MSDN article on Web Service Guidelines sheds some light on how to do that. http://msdn.microsoft.com/es-es/library/ms458094.aspx. Scroll down to Guidelines for Using the ASP.NET Web Services.

    1. Go to Add Service Reference Dialog.
    2. Click Advanced... to open Service Reference Settings
    3. Click Add Web Reference
    4. In Add Web Reference dialog box, enter your web service url, click green arrow, set your Web Reference name and click Add Reference.

    3.

    ReplyDelete
  57. When uploading a document from CRM to SharePoint, the first version of the document is 2. This is because versioning is turned on and when you upload the document it is Version 1 and when you update the Meta data it is considered as Version 2. Is there a solution for this issue. I want the version to remain as 1.

    ReplyDelete
  58. The code works just fine. However, I received an error "Could not locate list."

    Some digging showed me that in your IsMatch method of your list service has this line:

    return url.Substring(0, m_rootFolder.Length) == m_rootFolder;

    If the first parameter used in the DocLibHelper.Upload method isn't the same case as the list name, I got an error, so I changed it to this:

    return url.Substring(0, m_rootFolder.Length).ToLower() == m_rootFolder.ToLower();

    which meant I was always comparing the same case. Hope this helps someone.

    ReplyDelete
  59. Thanks for the great code! I have found it works well when used with a MOSS2007 server. However, when I try to implement it into a MOSS2010 environment I come across a problem. Everything seems to work fine until it comes time to update the metadata within the 'TryToUpload' function. The file uploads fine but when it tries to update the data at 'UpdateListItems' I get the error that the file doesn't exist when in fact it does.
    Has anyone had this problem? Any clues...PLEASE!!!

    Thanks everyone.

    ReplyDelete
  60. Further to my previous post, more correctly, the error I get is...

    "The URL 'Doc Library/899/SJMSCL5EUBQ.pdf' is invalid. It may refer to a nonexistent file or folder, or refer to a valid file or folder that is not in the current Web."

    If you open Sharepoint you can actually see the file and the path is correct.

    ReplyDelete
  61. On 2007, this code works flawlessly. On a SharePoint 2010 platform, was having same issues as last poster with failure to update errors.

    Using the copy service as outlined in the solution on this page:
    http://social.msdn.microsoft.com/Forums/en-US/sharepointdevelopment/thread/f135aaa2-3345-483f-ade4-e4fd597d50d4

    documents are uploaded with properties. Need to figure out how to remove the linked copy flag when viewing the item properties... But the linked solution will get documents up into 2010.

    ReplyDelete
  62. Earlier in the month I had posted about a problem with updating column data in MOSS2010 (where it had worked fine in 2007). The cause was that 2010 requires the doc ID where 2007 was happy with just a doc reference.

    To fix this, I added a function to get the doc id and then added this to the update xml.

    The function i added was...

    Private Function GetDocID(ByVal s_URL As String) As String
    Dim m_sitedataService As New svc_sharepoint_sitedata.SiteData
    Dim s_DocPath As String
    s_DocPath = Replace(s_URL, Path.GetFileName(s_URL), "")
    m_sitedataService.Url = s_DocPath & "_vti_bin/sitedata.asmx"
    m_sitedataService.Credentials = m_credentials

    Dim s_webId As String = String.Empty
    Dim s_listId As String = String.Empty
    Dim s_itemId As String = String.Empty
    Dim s_bucketId As String = String.Empty

    Dim ret As Boolean = m_sitedataService.GetURLSegments(s_URL, s_webId, s_bucketId, s_listId, s_itemId)

    Return s_itemId

    End Function

    and then I just added a call to it just before "Dim sb As New StringBuilder()"...

    Dim DocGUID As String = GetDocID(fileInfo.m_URL)

    Now we just add the DocGUID to the ID field.

    Now it all works sweet with SP 2010!

    Q.

    ReplyDelete
  63. Great article
    Thank you Kevin for your code for 2010.
    I had the same issue...

    ReplyDelete
  64. I referenced the webservice and named it ListsService

    However I cannot find a type
    ListsService.Lists

    I only see ListsService.ListsSoapChannel

    Please help. Thank you.

    ReplyDelete
  65. hi,
    Please help this newbee..

    I am getting an error "couldnot update properties" while uploading a document into a document library in sharepoint 2007.

    Please find the code below.

    if (fileInfo.HasProperties)
    {

    StringBuilder sb = new StringBuilder();

    sb.Append("");

    sb.AppendFormat("{0}", fileInfo.m_URL);

    foreach (KeyValuePair property in fileInfo.m_properties)

    sb.AppendFormat("{1}", property.Key, property.Value);

    sb.Append("");


    Please help me.

    ReplyDelete
  66. Love the post... it a wonderful piece of work.. Thank you so much.. it helped me a ton...

    @vnroopa@gmail.com :

    I am sure you would have fixed the error by now.. if anybody else faces the issue :

    Check if the column names to which you are trying to update values are right. If it is a custom column, then sharepoint internally appends 00x20 in between for the spaces. Open the site in the sharepoint designer,check for the column name and put that here... it works like a charm..

    ReplyDelete
  67. just a quick query... the code you have given.. first uploads the doc and then updates the meta data where it creates new version of the doc... is there a way tat i can upload the doc with the properties inserted together without creating a new version ???

    ReplyDelete
  68. Hi All,

    First of all: What a GREAT post !

    I also had the nonexistent file or folder error in 2010 but managed to solve this easy by adding the doc ID (which I retrieved from SiteData)

    3 steps to follow:
    - add SiteData webreference (_vti_bin/SiteData.asmx)
    - Change code where Field TAG is set :
    Field Name='ID'>" + GetDocID(fileInfo.m_URL) + "< /Field>"
    -add method getDocID:

    private String GetDocID(String sUrl)
    {

    String sWebId,sBucketId,sListId;
    String sReturn = "";
    DevHoleDemo.SiteData.SiteData data = new DevHoleDemo.SiteData.SiteData();

    data.Credentials = m_credentials;
    try
    {
    data.GetURLSegments(sUrl, out sWebId, out sBucketId, out sListId, out sReturn);
    }
    catch (Exception e)
    {

    }


    return sReturn;
    }

    ReplyDelete
  69. It would be nice if when uploading it would keep the same version when the initial file metadata is added.

    ReplyDelete