correct use of API

Jan 16, 2015 at 5:41 AM
I followed examples and do the following to login and list the root folder content:
            System.Net.ICredentials credentials = new WebDavCredential("xxx", "zzz");
            WebDavSession webDavSession = new WebDavSession(@"https://xxx.thexyz.com", credentials as WebDavCredential);
            var responseTask = webDavSession.ListAsync(@"/");
The responseTask shows:
base = Id = 1, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}"

which does not look good...any ideas what am I doing wrong? bad URL? (the url is valid for xxx and zzz were substituted for real username and password.
Jan 16, 2015 at 5:58 AM
The code looks good so far, but you should consider an 'await' for the ListAsync call:
var responseTask = await webDavSession.ListAsync(@"/");
What's your WebDAV server?
Jan 16, 2015 at 4:47 PM
the server is ownCloud. I will try your suggestion today.
Is there non-async version of List?
Jan 16, 2015 at 5:14 PM
securigy wrote:
the server is ownCloud. I will try your suggestion today.
The library was tested against ownCloud. So it should work with every ownCloud instance.

securigy wrote:
Is there non-async version of List?
Unfortunately not. It is specifically designed the same way as the System.Net.Http.HttpClient which uses async methods a lot as part of the fast&fluid design guidelines derived from the Windows Phone design guidelines.

But this should not cause any problems: You could make your 'caller methods' async and await all the calls to the WebDAV library. This way you should not face any problems specific to asynchronous programming. It's pretty straightforward.
A good starting point into the whole async-await model is this MSDN article.
Jan 17, 2015 at 1:28 AM
Strange, but I still having problems:

Error 23 The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.

I added
using System.Threading.Tasks

and changed var responseTask to:
Task<System.Collections.Generic.IList<WebDavSessionListItem>> responseTask

but it did not help...

I also looked at the source and ListAsync is marked with async so I am not sure what's going on...
In some Unit tests, however, you do not use await
Jan 17, 2015 at 7:48 AM
Edited Jan 17, 2015 at 7:49 AM
securigy wrote:
Error 23 The 'await' operator can only be used within an async method. Consider marking this method with the 'async' modifier and changing its return type to 'Task'.

I added
using System.Threading.Tasks

and changed var responseTask to:
Task<System.Collections.Generic.IList<WebDavSessionListItem>> responseTask

but it did not help...
When using await in a method, this method needs the return type Task or void. So, your method where you call WebdavSession.ListAsync needs Task or void as return type. Then you can do something like this:
return await webDavSession.ListAsync(@"/");
Could you post the whole method where you do this call?

securigy wrote:
I also looked at the source and ListAsync is marked with async so I am not sure what's going on...
In some Unit tests, however, you do not use await
Yes, this is kind of a shortcut just to avoid making the unit test methods async.
But this is not recommended, because these calls will probably block on mobile devices.
Jan 17, 2015 at 6:30 PM
here is the entire code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Http;
using System.Threading.Tasks;


using DecaTec.WebDav;

namespace GravityStormsOutlookAddIn
{
    public class DecaTecWebDav
    {
        public void Initialize()
        {
            // Speficy the user credentials and use it to create a WebDavSession instance.
            System.Net.ICredentials credentials = new WebDavCredential("XXX", "YYY");
            //WebDavSession webDavSession = new WebDavSession(@"https://gravitystorms.thexyz.com/remote.php/webdav", credentials as WebDavCredential);
            //WebDavSession webDavSession = new WebDavSession(@"https://gravitystorms.thexyz.com", credentials as WebDavCredential);
            var webDavSession = new WebDavSession(@"https://gravitystorms.thexyz.com/webdav/", credentials as WebDavCredential);
            ______var responseTask = wait webDavSession.ListAsync("/");______

            // Wait for the response to get processed (it is an async method).
            responseTask.Wait();

            // You get a list of WebDavSessionListItems which can be used to get the properties of the single items.
            var items = responseTask.Result;

            foreach (var item in items)
            {
                Console.WriteLine(item.Name);
            }
        }

    }
}

The bold line indicates error (red wavy underlined) and won't compile
Jan 18, 2015 at 4:42 PM
Let's have a look at the method call webDavSession.ListAsync("/") (your line where an error is indicated):
  • If you await this call (var responseTask = await webDavSession.ListAsync("/");), this method returns a IList<WebDavSessionListItem> which is then saved in the variable responseTask. This is the recommended way to call this function. But then you have to mark your method as async (e.g. your method's signature will be public async void Initialize()) and you have to remove the lines responseTask.Wait(); and var items = responseTask.Result; because the variable responseTask will not be of type Task.
  • If you do not await this call (e.g. remove the "await"), than your variable responseTask will be of type Task<IList<WebDavSessionListItem>>. Then you have to wait for the Task to complete and get the result with the Task's property result.
To sum it up, when using async/await, then the whole method should look like this:
public async void Initialize()
        {
            // Speficy the user credentials and use it to create a WebDavSession instance.
            System.Net.ICredentials credentials = new WebDavCredential("XXX", "YYY");
            //WebDavSession webDavSession = new WebDavSession(@"https://gravitystorms.thexyz.com/remote.php/webdav", credentials as WebDavCredential);
            //WebDavSession webDavSession = new WebDavSession(@"https://gravitystorms.thexyz.com", credentials as WebDavCredential);
            var webDavSession = new WebDavSession(@"https://gravitystorms.thexyz.com/webdav/", credentials as WebDavCredential);
            var items = await webDavSession.ListAsync("/");

            foreach (var item in items)
            {
                Console.WriteLine(item.Name);
            }
        }
Jan 18, 2015 at 10:18 PM
Thank you, that was really a stupid mistake on my part...

I listed listed all folders and files under the root by passing in the whole URL (passing "/" won't work)
and now for each item I get:
ContentType
Created
IsDirectory
Modified
Name
Size
Uri

So my question is how do I obtain the URL that I pass to other people to download a file?
Jan 19, 2015 at 12:46 PM
securigy wrote:
So my question is how do I obtain the URL that I pass to other people to download a file?
Can't you use the Uri property of the WevDavSessionListItem?

Or do you mean an ownCloud specific share link?
Jan 19, 2015 at 4:58 PM
I mean the URL that I can send in email to other people that do not have any DropBox accounts and they will be able to download a file without any prompts and confirmation by DropBox. Is the above mentions Uri can be used for that?
Jan 19, 2015 at 5:05 PM
I don't think that ownCloud supports downloads from a WebDAV account without credentials. For this, you'll have to use the share functionality of ownCloud I think.
Jan 19, 2015 at 5:14 PM
wow! I did not realize that... the whole purpose of my application is sharing files using the ownCloud...
So what should I use with ownCloud then in the terms of some kind of C# ownCloud library that allows that? C# REST client? Any recommendations?
Jan 20, 2015 at 2:21 PM
You can find out the URL of a specific file in your ownCloud by concatenation of the base URI you passed to the method ListAsync and the URI property of the specific WebDavSessionListItem. But ownCloud enforces that you'll pass some (valid) credentials when accessing the file. Otherwise this would be a security disaster.

The only way (afaik) to share a file to the public is ownCloud's share mechanism. There you can share a file with a link (like: http://www.mycloud/public.php?service=files&t=<ID>). But the share activation has to be done manually - the same way as Dropbox, OneDrive, etc.

I'm not into ownCloud, so I can't ell you how to access the ownCloud API by C#, sorry. But you could try to get an answer in the ownCloud community forums.