skazantsev / webdavclient Goto Github PK
View Code? Open in Web Editor NEWAsynchronous cross-platform WebDAV client for .NET Core
License: MIT License
Asynchronous cross-platform WebDAV client for .NET Core
License: MIT License
Hi, I try to use Copy with DestLockToken (with overwrite option). Firstly, I create lock token for destination file (via Lock, that creates new empty locked file) and then specify this in DestLockToken, call Copy(), then obtain Precondition Failed 412. It is strange, because I have actual lock token for file. Same trick works for PutFile(), where I lock rewritable file (even it is does not exists) and use this lock token for writing data. My WebDAV server bytemark/webdav logs that header "If:" was received but resource not found.
.net core 3.1
Thank you for attention
Hello,
i'm using your library with an asp.net core 2.2 api. Everything works fine.
now i tried to push the version to .net core 3.1.
Building and running is fine, but the application is not able to connect to the webdav-server.
It says the server would be unavailable (Http Status Code 503)
Do somebody know how to handle this issue? Is there a breaking Change in Http Requests maybe i didnt get?
Greetings,
Glorfinkel
Cannot connect to OwnCloud
WebDAV response - StatusCode: 401, Description: Unauthorized
I run a apache webserver, which has an OwnCloud instance running. I also host some docker instances, and one uses WebDavClient to send files to OwnCloud. For this I have a few unit test that test uploading a file and creating directories. When I run this locally from Visual Studio 2017, it makes a connection to my server and all tests are ok.
A short while ago, I ported all my code to .Net Core 2.0. I tried to deploy my site as the docker instance, and while building the code it also runs the test again. And they fail. So, my first thought was that from Docker, the test couldn't connect to my host webserver, or maybe something with https issues (but actually, before going to 2.0 it also worked). I therefor added a manual httpClient call to the same webdav url, with basic authentication. And this tests works.
I monitored the apache logs of owncloud, and what I noticed, that every time my local unit test starts, there is a request with a 407 message, and second a 207 request with my username in it:
31.x.x.x - - [06/Sep/2017:11:23:03 +0200] "PROPFIND /remote.php/webdav/ HTTP/1.1" 401 306 "-" "-"
31.x.x.x - peter [06/Sep/2017:11:23:04 +0200] "PROPFIND /remote.php/webdav/ HTTP/1.1" 207 2021 "-" "-"
But when I run the docker unit test, only the first one occurs. I checked the code, but can't seem to find why and how the 2 calls are made, and why in Docker only the first occurs.
I did find a solution. By added a manual header with the basic authentication to the client parameters, my problem is resolved. But, how does this work? Is this a feature of HttpClient to detect the authentication request and add the credentials? Is it possible to override this behaviour from the code. I did try the PreAuthenticate setting, but it doesn't seem to affect anything.
WebDAV at Synology DS 215+ (DSM 5.2-5644 Update 1).
WebDavClient.Propfind("file name") throws an exception:
{"The character set provided in ContentType is invalid. Cannot read content as string using an invalid character set."} System.Exception {System.InvalidOperationException}
InnerException {"'"utf-8"' is not a supported encoding name.\r\nParameter name: name"} System.Exception {System.ArgumentException}
StackTrace:
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
at WebDav.WebDavClient.d__2.MoveNext()
Hi, I try read file name on webdev and displayname is null??
Trying to create a file named "Córdoba" in a directory named "España" will result in mangled (i.e. URL-encoded) file and directory names.
Please support the full range of applicable UTF 8 characters by transparently URL-decoding the file and directory names returned from API methods.
Please consider adding support for IHttpClientFactory, HttpPolicies
In the web client params, we should be able to pass an AuthenticationHeaderValue to support MSAL, for example the following from the Microsoft MSAL tutorial
httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue(Constants.BearerAuthorizationScheme,
accessToken);
Currently this Web DAV Client does not support Microsoft sharepoint since I can't pass the needed access token as part of the header. I might add this in myself if it would be desired.
How do I create a file in a directory in asp.net core
See #18.
issue is with ConfigureHttpClient method in WebDavClient.cs.
Consider the following code:
_clientParams = new WebDavClientParams()
{
BaseAddress = new Uri(url),
Credentials = new NetworkCredential() { UserName = "test", Password = "test" },
UseDefaultCredentials = false
};
using (var webDavClient = new WebDavClient(_clientParams))
{
var result = await webDavClient.Propfind(_fileToGet);
if (result.IsSuccessful){}
// continue ...
else{}
// handle an error
return "";
}
Even though i'm explicitly setting credentials, i must also set UseDefaultCredentials to false for it to auth correctly. If you update this code to remove UseDefaultCredentials=false, you'll get a 403 when trying to .Propfind
I have a branch with fix already, or make the following change to ConfigureHttpClient:
if (@params.Credentials != null)
{
httpHandler.Credentials = @params.Credentials;
httpHandler.UseDefaultCredentials = false;
}
This is also likely the cause of the other issue reported.
Since I upgraded to version 2.5.0, in my program I am using synchronous IO (since I am working in a Windows Form background worker)
Sample code:
var retRemoteGetTask1 = client.GetRawFile(filename1);
retRemoteGetTask1.Wait(); // Works !
var retRemoteResult1 = retRemoteGetTask1.Result; // retRemoteResult1 is fully filled
var retRemoteGetTask2 = client.GetRawFile(filename2);
retRemoteGetTask2.Wait(); // Infinite wait unless I break the debugger and "quick watch the retRemoteGetTask2 variable) !
//Quick Watching retRemoteGetTask2 : { Id = 41, Status = WaitingForActivation, Method = "{null}", Result = "{Not yet computed}" }
var retRemoteResult2 = retRemoteGetTask2.Result; // NEVER Reaching this line
It would be nice if the ContentType of the RequestParameters-object could be changed from outside WebDavClient class. By default, it is set to "text/plain; charset=utf-8". For example, right now I would like it to be "application/xml; charset=utf-8".
Use cases
IWebDavClient
instead of WebDavClient
to be able to mock it if necessaryHi, I have a WebDAV server which uses the digest method for authentication.
This appears a problem for WebDavClient. Any advice on how to change WebDavClientParams to use digest credentials?
The error I got is:
{PROPFIND WebDAV response - StatusCode: 417, Description: Expectation Failed}
Many thanks
Ning
Hey,
i couldn't find a documentation so: Am i doing something wrong or is there a bug?
Im trying to connect to my nextcloud webdav and get some Proeprties:
var param = new PropfindParameters();
param.Namespaces = new List<NamespaceAttr>()
{
new NamespaceAttr("oc", "http://owncloud.org/ns"),
new NamespaceAttr("nc", "http://nextcloud.org/ns")
};
param.CustomProperties = new List<XName>()
{
XName.Get("fileid", "oc:"),
XName.Get("size", "oc:"),
XName.Get("owner-display-name", "oc:"),
XName.Get("mount-type", "nc:"),
};
param.ApplyTo = ApplyTo.Propfind.ResourceAndAncestors;
var result = await _client.Propfind("remote.php/webdav/", param);
The Result ist valid and i get all my Resources, but without any CustomProperties.
But i know these Properties exist, because using curl i get all my CustomProperties
I'm doing a vsto and it calls the IWebdavClient certainly because of interoperability, does this lib support this?
I wanted to use this library to implement a CalDAV (which is based on WebDAV) library, but CalDAV requires a REPORT request which is not supported by this. If there was a way to send custom requests I could use this good library instead of using my own (small) implementation of WebDAV.
Running Propfind with an empty path throws an exception. However, this should be allowed as the BaseAddress may contain a URI that is entirely valid without having to add anything to it.
This is easily circumvented by creating your own empty Uri and giving it to Propfind, but still.
Hi, I am trying to use this nice client to download a large data file (>2GB) and would like to monitor the progress and download speed.
Is there any build-in API for doing so? Otherwise I guess I will need to read the stream returned by GetRawFile(), something like
using (var response = await client.GetRawFile("data.mp4"))
{
using (fileStream = new FileStream("data.mp4", FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
{
var totalRead = 0L;
var totalReads = 0L;
var buffer = new byte[8192];
var isMoreToRead = true;
do
{
var read = await response.Stream.ReadAsync(buffer, 0, buffer.Length);
if (read == 0)
{
isMoreToRead = false;
}
else
{
await fileStream.WriteAsync(buffer, 0, read);
totalRead += read;
totalReads += 1;
if (totalReads % 2000 == 0)
{
Console.WriteLine(string.Format("total bytes downloaded so far: {0:n0}", totalRead));
}
}
}
while (isMoreToRead);
}
}
Your help is much appreciated.
Hi.
I could not find documentation to PROPPATCH and looked up your tests to determine how to place custom properties into the propfind Dictionary with a certain schema.
Here is the code I am using:
var _space = "http://example.com";
var _spaceNs = "{" + _space + "}";
// Construct properties
var propDict = new Dictionary<XName, string>
{
{ _spaceNs + "uploader", "chrakker" },
{ _spaceNs + "vertragstyp", item.Get_Property("Type") },
{ _spaceNs + "loeschdatum", item.Get_Property("ReminderDate02") }
};
// Construct Namespaces
var ns = new[]
{
new NamespaceAttr("oc", "http://owncloud.org/ns"),
new NamespaceAttr("nc", "http://nextcloud.org/ns"),
new NamespaceAttr("te", _space)
};
// Construct the parameters
var propParam = new ProppatchParameters {
PropertiesToSet = propDict,
Namespaces = ns
};
// Call the Response
var response = _client.Proppatch(ncPath, propParam).Result;
I expect something like this:
<?xml version=""1.0"" encoding=""utf-8""?>
<D:propertyupdate xmlns:D=""DAV:"" xmlns:te=""http://example.com/"" xmlns:oc=""http://owncloud.org/ns"" xmlns:nc=""http://nextcloud.org/ns"">
<D:set>
<D:prop>
<te:uploader>chrakker</X:prop1>
<te:vertragstyp>XYZ</X:prop1>
<te:loeschdatum>01012044</X:prop1>
</D:prop>
</D:set>
</D:propertyupdate>;
Sadly, it only takes the last Property from the Dict (here "loeschdatum") and sets it, not the other Properties, disregarding the length of the Dictionary completely.
Can you help me out there?
PutFile incorrectly reports that the file has no content when overwriting an already existing file.
I'm using https with basic authentication, I can connect and read a file with GetProcessedFile but the methods PutFile and GetRawFile returns allways 403 Forbidden
// Tls1.2
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
// Ignore certificate check
ServicePointManager.ServerCertificateValidationCallback +=
(se, cert, chain, sslerror) =>
{
return true;
};
WebDavClientParams clientParams = new WebDavClientParams();
clientParams.BaseAddress = new Uri(config.host); // HTTPS URI
clientParams.Credentials = new NetworkCredential(config.user, config.pass);
var client = new WebDavClient(clientParams);
foreach (string file in Directory.EnumerateFiles(this.localFolder, "*", SearchOption.AllDirectories))
{
string dirName = file.Replace(this.localFolder, "");
dirName = dirName.Replace("\\", "/");
string dest = config.host + config.remoteFolder + dirName;
var response = await client.GetRawFile(config.host + "/test.txt"); ->status code 403
var response2 = await client.GetProcessedFile(config.host + "/test.txt"); -> status code 200
var response1 = await client.PutFile(dest, File.OpenRead(file)); -> status code 403
}
I want to upload local files to the server
any idea?
As full disclosure: I'm using dotnetcore and the 3.0 preview 6; so this might not be an issue with this library per se.
I'm trying to upload a large file to the webdav but I get hit with an exception:
Unable to read data from the transport connection: The I/O operation has been aborted because of either a thread exit or an application request..
The application certainly isn't requesting a cancel; at least not from my code. And this works for smaller files, as well as the webdav client I've written in Python.
Thanks for creating this well-designed WebDAV client library. I've used it to good effect and so far without any problems whatsoever.
For the strong named version of one of my NuGet packages I need to reference WebDavClient as a signed assembly. I'd much prefer to reference a NuGet package of WebDavClient signed by its author to including a re-signed version of the library in my own packages.
I'm using the example code
var result = await _client.Propfind(baseAddress);
if (result.IsSuccessful)
{
foreach (var res in result.Resources)
{
Trace.WriteLine("Name: " + res.DisplayName);
Trace.WriteLine("Is directory: " + res.IsCollection);
Trace.WriteLine("Content Type: " + res.ContentType);
Trace.WriteLine("Content Length: " + res.ContentLength);
}
}
It's showing me the content type, content length also telling about if it's a directory. But I can't get name from there. Name is empty. Why is that?
Hello,
I'm trying to download a file locally using WebDAC.Client. The file is being created but it is empty. Any ideas how to solve this?
Thanks.
I am using this library in my multi-platform Xamarin app and attempt to use the native HttpClientHandler on each platform (Windows -> HttpClientHandler, iOS -> NSUrlSessionHandler, Android -> AndroidClientHandler).
In the case of Android:
var httpHandler = new AndroidClientHandler() { AutomaticDecompression = DecompressionMethods.Deflate | DecompressionMethods.GZip };
httpHandler.Credentials = new NetworkCredential(credentials.Username, credentials.Password);
var client = new WebDavClient(new HttpClient(httpHandler, true) { BaseAddress = new Uri(credentials.URL) });
Unfortunately, this causes the following exception when using the WebDavClient
:
Java.Net.ProtocolException: Expected one of [OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, PATCH] but was PROPFIND
A few possible solutions/workarounds are mentioned here: https://stackoverflow.com/questions/25163131/httpurlconnection-invalid-http-method-patch (X-HTTP-Method-Override, Reflection, ...)
I understand that this is not a bug in your library, but maybe you are interested in adding a workaround anyways...
NuGet version: 2.3.1
I am having a weird issue using this library in my Xamarin.Android & Xamarin.iOS project. I am connecting with a Nextcloud 15.0.2.0. I am providing correct URL, username but WRONG password.
Now, on iOS & Android I get only "OK" responses however, no matter what methods I call, e.g.:
PROPFIND WebDAV response - StatusCode: 200, Description: OK
In my UWP project, I am getting the expected result:
PROPFIND WebDAV response - StatusCode: 401, Description: Unauthorized
Tried to debug with Fiddler, but for some reason the web traffic didn't show up.
Запрос PROPFIND свойств для одного отдельного файла должен содержать в заголовке "Depth: 0" (а не "Depth: 1", как сейчас), "Depth: 1" обычно используется для запроса свойств каталога.
curl -i -X PROPFIND http://example.com/webdav/filename.ext --upload-file - -H "Depth: 1" <<EOF
<?xml version="1.0"?>
<a:propfind xmlns:a="DAV:">
<a:prop><a:resourcetype/></a:prop>
</a:propfind>
EOF
curl -i -X PROPFIND http://example.com/webdav/filename.ext --upload-file - -H "Depth: 0" <<EOF
<?xml version="1.0"?>
<a:propfind xmlns:a="DAV:">
<a:prop><a:resourcetype/></a:prop>
</a:propfind>
EOF
We want to upload WebDAV files using this .NET API. However, in order to connect to our WebDAV server, we are required to use a proxy (with authentication). Could this library work behind a proxy?
Thank you in advance
It seems that the GetAbsolutePath & CreateUri methods do not encode the urls, such as using "%20" for whitespace and so on...
To reproduce the issue, just use Copy or Move method with file(s) that contain whitespaces in filename.
exp :
Move([AbsolutePath] + File 1.txt, [AbsolutePath2] + File 1.txt)
Or :
Move([AbsolutePath] + File%201.txt, [AbsolutePath2] + File%201.txt)
Getting same result.
Hi.
I'm planning to use your library with Nextcloud.
They support chunked upload for large files.
https://docs.nextcloud.com/server/15/developer_manual/client_apis/WebDAV/chunking.html
Is it something you plan on adding?
Thanks for your awesome work
When using PutFile(. . . ) and the upload takes more then 100 seconds to upload, I get this exception
InnerException = {System.ObjectDisposedException: Cannot access a closed file.
at System.IO.__Error.FileNotOpen()
at System.IO.FileStream.get_Position()
at StackSharing.Lib.StackClient.UploadFile(UploadStatus status, OnlineItem folder, String filePath)
It's probably because when creating a HttpClient, there is no possible override from the default timeout from 100 seconds:
https://github.com/skazantsev/WebDavClient/blob/master/src/WebDav.Client/WebDavClient.cs#L711
Hi,
I'm actually facing some issues while using the API to connect to a webdav with TLS1.2
Question: Is the TLS1.2 supported by the HTTPClient ?
I'm sharing this to hopefully help others scratching their heads with a similar issue.
I was changing code originally using HttpWebRequest, in order to tidy up & make use of your library instead.
In my example I have 2 MemoryStreams, stream1 has dummy text as used in your example code, and stream 2 contains some serialized xml.
var stream1 = new MemoryStream(Encoding.UTF8.GetBytes("<content/>"));
var stream2 = new MemoryStream();
var streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8)
serializer.Serialize(streamWriter, sampleXml);
var resPutFile1 = await client.PutFile(exportFile1, stream1);
var resPutFile2 = await client.PutFile(exportFile2, stream2);
Stream 1 was succesfully written to exportFile1.
Stream 2 wasn't written to exportFile2 - the file itself was created but with no content.
The issue (fixed) was with the memory stream position - it needed to be set to 0 before calling PutFile, in order to read the whole stream and write it out to the file.
stream2.Position = 0;
var resPutFile2 = await client.PutFile(exportFile2, stream2);
I thought thought I'd flag this since HttpWebRequest happily seems to take care of that itself, and I never needed to specify the position, it just reads the stream from the beginning.
Use cases:
HttpClient
that are not exposed by WebDavClientParamsHttpClient
for unit testsHi,
The plugin as I see currently only supports options to fetch properties for resource itself, resource + children and the infinite one.
In a situation where I need to fetch the files tree I want to fetch only children for each call and that can be done with "1,noroot" depth setting.
For clarification, at the moment when I fetch the "Images" folder props I get => Images folder, image1.jpg, image2.jpg etc. I want only the images, not the selected folder.
How do I set the WebDavClient to allow GetRawFile to stream a file larger than 2GB
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.