Search code examples
c#webdavwinscpnextcloud

How to access nextcloud files in C# by using WebDav?


When trying to access the WebDav API of nextcloud via WinSCP, I am facing several problems with the right usage of root folder, remote path, etc. To save others some time, here is the working code I came up with to upload a file into a remote (shared) folder.

Lessons learned:

  1. server name is provided without protocol, this is defined by the SessionOptions.Protocol
  2. root folder may not be empty, must be at least "/"
  3. the next cloud provider / the configuration defines the root url, so "webdav" or "dav" after remote.php are predefined. Normally you can see it in the lower left corner when using the webapp of nextcloud in the settings section
  4. "files/user" or "files/username" is not necessarily required - defined by the hoster / configuration as well
  5. the connecting user must have access rights to the given directory you should provide file access permissions to others (if wanted) by providing FilePermissions in the TransferOptions

However, there is no working example in the WinSCP, the nextcloud documentation, nothing to find here as well.


Solution

  • // Setup session options
    var sessionOptions = new SessionOptions
    {
        Protocol = Protocol.Webdav,
        HostName = server,
        WebdavRoot = "/remote.php/webdav/" 
        UserName = user,
        Password = pass,
    };
    
    using (var session = new Session())
    {
        // Connect
        session.Open(sessionOptions);
    
        var files = Directory.GetFiles(sourceFolder);
    
        logger.DebugFormat("Got {0} files for uploading to nextcloud from folder <{1}>", files.Length, sourceFolder);
    
        TransferOptions tOptions = new TransferOptions();
        tOptions.TransferMode = TransferMode.Binary;
        tOptions.FilePermissions = new FilePermissions() { OtherRead = true, GroupRead = true, UserRead = true };
    
        string fileName = string.Empty;
        TransferOperationResult result = null;
    
        foreach (var localFile in files)
        {
            try
            {
                fileName = Path.GetFileName(localFile);
    
                result = session.PutFiles(localFile, string.Format("{0}/{1}", remotePath, fileName), false, tOptions);
    
                if (result.IsSuccess)
                {
                    result.Check();
    
                    logger.DebugFormat("Uploaded file <{0}> to {1}", Path.GetFileName(localFile), result.Transfers[0].Destination);
                }
                else
                {
                    logger.DebugFormat("Error uploadin file <{0}>: {1}", fileName, result.Failures?.FirstOrDefault().Message);
                }
            }
            catch (Exception ex)
            {
                logger.DebugFormat("Error uploading file <{0}>: {1}", Path.GetFileName(localFile), ex.Message);
            }
        }
    }
    

    Hope this saves some time for others.