Connecting to cloud using C# WebDav

Hi Tomas,

You need to add some error handling there then. Depending on the directory you redirected to which was in my sample ā€œpath/path2/subpathā€, there may or may not be any collections (sub-folders).

I donā€™t know if it is possible to download the entire directory at once using this library. You could attempt it though. FolderFiles is perhaps a rather non-fitting name, as you get ā€˜itemsā€™ back (which is either a folder or file). Just make sure you select a folder item and see if you can download it.

What kind of error handling do you mean? The class you wrote to me a few days back couls be edited to IDisposable. Then it requires the function Dispose inside the class. But here is the question - what am I disposing exactly? The called class itself or what?

After thia problem is solved, are you suggesting I should download folderā€™s files one by one? Wouldnā€™t it be much less complicated if I just uploaded .rar file instead of the folder. Would it even count as file?

Here is the problem:

ā€™PropfindResponseā€™ does not contain a definition for ā€˜FirstOrDefaultā€™ and no accessible extension method ā€˜FirstOrDefaultā€™ accepting a first argument of type ā€˜PropfindResponseā€™ could be found (are you missing a using directive or an assembly reference?)

The code for downloading a file inside my class is this (error: FirstOrDefault):

        public async Task<WebDavStreamResponse> Download(string url)
        {
            // Retrieve list of items in 'Test' folder
            var folderFiles = await GetItemsAsyncCloudItem(url);
            // Find first file in 'Test' folder
            var folderFile = folderFiles.FirstOrDefault(f => f.IsCollection == false);

            var tempFileName = Path.GetTempFileName();

            // Download item into a temporary file
            using (var tempFile = File.OpenWrite(tempFileName))
            using (var stream = await _webDavClient.GetProcessedFile(folderFile.Href))
                return await stream.CopyToAsync(tempFile);
        }

I used this function in my class to await the file

        public async Task<PropfindResponse> GetItemsAsyncCloudItem(string file)
        {
            return await _webDavClient.Propfind($"remote.php/dav/files/" + _username + "/" + file);
        }

The library in place responds in generic ā€˜webdav itemsā€™, this can be files and/or sub-folders of the given path. In case the path only contain sub-folders, the property ā€œIsCollectionā€ will always be true for all the items, if there are any files within the collection they will have IsCollection = false.

The error you are referring to is probably that you are missing out on using System.Linq;, you need that reference.

You are disposing the streams in place, one for the filestream and one for downloading it in-memory. I do not recommend disposing the HttpClient itself.

I donā€™t know if you can directly download the folder as a .zip file (or .rar), probably not, you can always test it out.

So what you basically mean is that every sub-folder in my folder (ex. main folder where everything is located) will trigger IsCollection = true ? So I thought maybe I could tell the code the home location of all my sub-folders and check for IsCollection = true and download the required sub-folder according to its name. Or will it just download the sub-folderā€™s contents as you mentioned?

The problem is, I have been using Linq and checked the projectā€™s references and, as it turns out, System.Linq.dll is checked. Is there any way to fix that error or do you want me to take a screenshot of references?

This means I just need to set the stream variable for downloading the files to NULL or just somehow reset it?

Iā€™ll give it a try.

Try thisā€¦ did not run it, but does not give any compile errors.

  public async Task Download(string url)
        {
            // Retrieve list of items in 'Test' folder
            var folderFiles = await GetItemsAsyncCloudItem(url);
            // Find first file in 'Test' folder
            var folderFile = folderFiles.Resources.FirstOrDefault(f => f.IsCollection == false);

            var tempFileName = Path.GetTempFileName();

            // Download item into a temporary file
            using (var tempFile = File.OpenWrite(tempFileName))
            using (var stream = await _webDavClient.GetProcessedFile(folderFile.Uri))
                await stream.Stream.CopyToAsync(tempFile);
        }

Note, I modified it to resources, checked also WebDavStreamResponse, it does not have any CopyToAsync.

Also, personally use this library: GitHub - skazantsev/WebDavClient: Asynchronous cross-platform WebDAV client for .NET Core

Yes, I used this and FirstOrDefault function finally gives no errors and seems to be working. But thereā€™s the other problem Iā€™ve been talking about - disposing. You see, I still get the error.

WebDavStreamResponseā€™: type used in a using statement must be implicitly convertible to ā€˜System.IDisposableā€™.

Do you think changing the library to the one you just suggested me might do the trick?

Any suggestions, please? Iā€™d fix it myself but I have never encountered error like this.

Personally Iā€™d switch to the other library I suggested.

Yeah, it worksā€¦ Thank you.

It is trying to download to temporary file in Temp folder, but somehow the 2,6GB file is downloaded immediately and if I check the fileā€™s size, I have 0Bā€¦ I think thereā€™s problem somewhereā€¦ Is it because I am trying to download a folder instead of a file?

There are a few factors to account for besides if downloading a folder will work or not. Your server / connection should not time-out for example.

Try it first on a file before figuring out if this even works on a folderā€¦

Found an easier solution to circumvent this error:

ArgumentException: Only HTTP/1.0 and HTTP/1.1 version requests are currently supported.

Add the HTTP Version explicit:

System.Version version = System.Version.Parse("1.0");
webDavSession.HttpVersion = version;

Code:

// Specify the user credentials and use it to create a WebDavSession instance.
            var credentials = new NetworkCredential("username", "pass");
            var webDavSession = new 
            System.Version version = System.Version.Parse("1.0");
	    webDavSession.HttpVersion = version;
WebDavSession(@"https://cd.wedos.com/remote.php/dav/files/username/", credentials);
            var items = await webDavSession.ListAsync(@"Talk/");

sorry to disturb you i have facing same issue,
so can you please help me or share code with me if possible.
i am also unable to upload file from my PC to Nextcloud using asp.net c#.
plz plz plz help me.