Custom WebDAV Server Using .NET

As I discussed in a previous post "ASP.NET Web Application without ASPX Extension", I’ve been working on a custom WebDAV server for a client. The initial proof-of-concept was just to see if we could get some .NET code that would respond to all paths for a given web application. From there I had to make WebDAV work.

What is WebDAV

To recap: WebDAV is an IETF Standard Protocol. It is an extension to the ubiquitous HTTP standard, adding on request methods to get property information about files and folders, make folders (called collections in WebDAV parlance), change properties, lock files, etc. Basically anything that you would want on a distributed file system. WebDAV is natively supported by Windows 2000 and XP, Mac OS X, and Linux (using davfs). When using this native support, you’re able to interact with WebDAV just like you are using a local filesystem or a network share. There are also many standalone client implementations that act more like FTP clients.

Why Would You Write Your Own DAV Server?

Sharing files over a network is nothing new of course. Using Windows File Sharing, many people are used to using network shares to store files on a server and to share with their coworkers. The limitation of most of these file sharing systems is that they share exactly what is on the filesystem. What if you want to integrate file sharing with an application that stores file meta-data in a database? What if you want to programmatically control the files and folders that you show to your users? By building your own WebDAV server you can query a database to get all of the meta-data (and even file contents) to serve to your users.

How To Build a WebDAV Server

I did quite a bit of searching and found WebDAV server implementation in Python, Ruby, and Java, but could not find anything done in a .NET language which my client uses for all of their application infrastructure. So, I built one!

As I mentioned in my previous post, we can take over the complete HTTP request for all requested paths. I use a Command Pattern to handle the different types of WebDAV requests. The Commands are responsible for getting information from the HTTP Request that they need to fulfill the request and for writing the proper HTTP Response. Each of the Commands delegates the actual File manipulation to a set of provider classes. Those classes are accessed through an Abstract Factory which allows for me to easily change the backend implementation. This allows for a good separation of concerns. The WebDAV Service layer knows how to read and write WebDAV and the File Provider layer knows how to get and store information about files and folders. (The abstraction between the Commands and the File Providers is a bit leaky still, but I’m confident I’ll be able to refactor it into a cleaner separation.)

The first backend provider that I created for testing was a FileSystem provider. I’ve mapped the WebDAV server to a specific directory and use standard System.IO commands to manipulate files. This is a lot easier because it allowed me to focus on implementing the protocol without worrying about interacting with a less familiar data access layer.

Test Your Implementation

The WebDAV folks have built a great test suite called Litmus that you can use to validate your server implementation. It performs all of the basic operations on files and collections to validate that the server performs to the specification. Start with Litmus and you’ve got your entire functional test harness written for you. That is some TDD in action!
Litmus goes a long way to get you to protocol compliance, but it took a bit of cleaning and tweaking before Windows Explorer would happily mount the Web Folder.

In addition to Litmus I found a couple of other tools really handy for debugging:

  • Ethereal - a very nice protocol analyzer that will let you inspect a series of requests and responses.
  • DAVExplorer - a Java WebDAV client that will write detailed logs of requests and responses.

Don’t be afraid to write your own WebDAV server, it’s really fun!

References

WebDAV Reference Book:
WebDAV: Next-Generation Collaborative Web Authoring by Lisa Dusseault

88 Responses to “Custom WebDAV Server Using .NET”

  1. RefuX writes:

    The only thing better than writing a WebDAV server is seeing the developer do his end-zone happy dance when he gets the darn thing to finally mount from Windows Explorer!

  2. Kavitas writes:

    Hi
    Can you give me some insight on sending the HTTPResponse to client for a WebDAV request ??

    Regards

  3. DMA writes:

    I do need to create webdav server using C#, which can return documents and their properties (from databse) . Can you please provide some initial pointers to start on this.

  4. Geoff Lane writes:

    Kavitas,
    I built the WebDAV server using a custom IHttpModule. As I described, it was mapped to handle all incoming requests. When you get a Request you will have access to the HttpApplication object that contains both the incoming HttpRequest object as well as an HttpResponse object.

    The HttpRequest object gives you access to all of the HTTP Header information. That header information will contain the kind of WebDAV request you are getting (PROPFIND, PUT, MOVE, COPY, GET). Using that information along with other information in the header such as the Path, the Depth, and possibly the Destination you have to fulfill that response.

    Basically there are a couple of different kinds of responses:

    1. PROPFIND for example responds with an XML document defining the resources available at a given path. Some basic headers are set (app.Request.Headers.Add(”Content-Type”, “text/xml”)) and then the XML is written to the Request.Ouptut stream.
    2. COPY and MOVE don’t write a response to the output stream, but generally just set HTTP Response Codes.
    3. GET Requests are just like a regular HTTP GET. The person is requesting the contents of a file. In that case you set the Response status code, set the Content-Type, and then just stream the contents of the file to the Response.Output stream.

    All of the specifics about the status codes and things are available at http://www.webdav.org. The Response status codes are really important for protocol compliance.

    Hope That Helps.

  5. Geoff Lane writes:

    DMA,
    I thought I did give some initial pointers, as that is exactly what I described building. I just provided some more information in my Response to Kavitas. Maybe that will help you out a bit?

    If you have specific questions, I can try to answer them.

    The best place to start is probably with the specs from http://www.webdav.org. It tells you basically everything you need to implement the protocol. The only tricky part for me was figuring out the IIS Mapping to get my code to respond to every incoming request. I describe that in ASP.NET Web Application Without ASPX Extension

  6. Kavitas writes:

    Hi Geoff

    I tried configuring IIS to handle all request to my website by the way you described in your article “ASP NET Web Application Without ASPX Extension” but as soon as I make the extensions to .* and try to open my website, it starts asking me for my username and password and on suppling my credentials also, it gives 401.1 error “You are not authorozed to view this page.” So please suggest how should i trap all my request

    Thanks

  7. Geoff Lane writes:

    Kavitas,
    Did you map an HttpModule that you created in your site’s Web.config?

    In your Web.config:

    
    <system.web>
        <httpModules>
            <add name="DavModule" type="Zorched.Dav.DavModule, DavModule"/>
        </httpModules>
    </system.web>
    

    Zorched.Dav.DavModule implements System.Web.IHttpModule. It’s the code that gets the incoming request and then writes the response. You could start with something simple by just writing some plain-text back to the browser.

    If you’ve already done that, then I would recommend looking at authentication and permissions. You shouldn’t be getting a login prompt unless you have authentication enabled or you’re trying to access something that your webserver doesn’t have access to. Unfortunately, authentication an IIS are not an easy subject, so I don’t know exactly what it could be.

  8. DMA writes:

    Geoff,

    Thanks a ton for initial pointers. I tried out on the basis of your response. Basically I derived a class from IHttpModule and registered in web.config. Using this I am able to trap all requests to my web site (including WebDav requests).

    But when writing to response for a WebDav request, the App.User object is returning me “”. Appreciate your help on this.

    - DMA

  9. Geoff Lane writes:

    DMA,

    Great to see you got it started!

    As for the User issue, I would imagine that you just don’t have any authentication going on. The User object is an IPrincipal. See the documentation of HttpApplication for details. Basically, you can’t create a log-in form, so you’re going to have to use Basic or Digest authentication. Depending on your needs, I guess the built-in IIS Authentication might work (although I don’t know if that will set the IPrincipal that you need), otherwise you are going to need to implement your own Authentication and set your own IPrincipal on each Request.

    Just for your info:
    Basic authentication sends the username and password in clear-text (technically base64 encoded) so should only be used over an SSL connection. Windows Explorer (in some versions) will not send Basic Authentication credentials over an non-secure connection.

  10. Johan writes:

    I tried a few different ways of doing this - but I’m trying to build a webdav-imlementation on top of an application I can’t modify - and the application hi-jacks the IIS but doesn’t supply the correct Response headers (Allow OPTIONS for instance). This made it quite difficult to handle.

    But then I stumbled on the ISAPI_Rewrite filter which can do pretty much the same as your described wildcard mapping, but is much more easy to implement. Just a hint.

    – Johan

  11. DMA writes:

    1. My requirement is to create a custom webdav server, which will return me documents and their meta data from database (instead of physical directory). Users may access this webdav server from windows exploer, so requirment is to display folders/documents similar to windows folders.

    2. What I have done :

    a. I have created a custom webdav server using httpmodule that traps all request and if the request contains a WebDAV method, it returns a Custom response.

    b. The response that I am sending is below.

    
    <a>
      </a><a>
        </a><a>http://localhost/test/</a>
        <a>
          </a><a>HTTP/1.1 200 OK</a>
          <a>
            </a><a>0</a>
            <a>2005-12-02T04:42:45.033Z</a>
            <a>test</a>
            <a>"36d979d6faf6c51:c46a"</a>
            <a>Fri, 02 Dec 2005 04:42:45 GMT</a>
            <a>
              </a><a / rel="nofollow">
            </a>
            <a / rel="nofollow">
            </a><a>0</a>
            <a>1</a>
            <a / rel="nofollow">
          </a>
    

    header

    c. Along with this response I am sending these headers,
    Server : Microsoft-IIs/5.1
    X-Powered by : ASP.NET
    ContentLocation : http://localhost/test
    ContentType : text/xml
    TransferEncoding : chunked

    d. After accessing my custom webdav server from explorer, the following error occurs.
    “\\localhost\CustomWebDAVServer is not accessible. You might not have permission to use this network resource. Contact the administrator of this server to find out if you have access permissions.The directory name is invalid.”

    e. I am using “integrated windows authentication” in IIS. Also I am administrator on my machine so I have full access.

    Can you please advise if I am missing anything (either in header or response format or with code)

  12. Geoff Lane writes:

    DMA,
    Are you literally sending back a response that uses <a> wrapped around the values? That’s not gonna work of course.

    Content-Location and Content-Type also have dashes in them.

    You’re trying to access \\localhost\CustomWebDAVServer but sending back a Content-Location and an href of http://localhost/test. It expects a URL that corresponds to the URL requested.

    Implementing a protocol is all about details. The details really matter a lot.

  13. Geoff Lane writes:

    Johan,
    The URL rewriting is a great idea as well. It might make things quite a bit simpler.

    I’ve gotten the whole thing working - mapping from Explorer, working with Office and its own WebDAV implementation, etc. So it can definitely be done either way.

  14. DMA writes:

    Geoff,

    One again thanks a lot for your valuable response. My mistake was I was sending wrong content location. After correcting that, I am able to open the folder that is requested. But IE does not show the contents inside the folder. As long as I am sending only the root folder to be shown in response it works fine, but when I give one document to be shown then it throws error of “Network path not found”.
    I am sending the response in XML format but XML is not able to upload on your website and it shows only the value inside the xml tags. Can you please give some insight on this.

  15. Alfred writes:

    Geoff,

    thanks for this article.

    I found myself excactly in your words: “”I did quite a bit of searching and found WebDAV server implementation in Python, Ruby, and Java, but could not find anything done in a .NET language…”

    We need to implement a webdav server for some kind of document management system. I’ve got a two questions:

    1. If you handle all incoming request, can you run normal http on the same server - can i run normal asp.net pages and webdav on the same iis?

    2. Are you interested in selling your code? I’m not a developer and don’t like the idea of reinventing the wheel. It would be a nice idea to save some time and spend some money :-)

    Thanks Alfred

  16. Geoff Lane writes:

    Alfred,

    1. You can map WebDAV to a virtual location (a sub-directory) under a main site or as a virtual host, so yes you can run it alongside other applications. You can also use URL rewriting as Johan suggested to accomplish this.

    2. The code was done as a work-for-hire (I’m a consultant), so does not belong to me. Email me privately if you are interested in consulting services.

  17. stacy writes:

    HI Geoff

    Thanks a ton for your valuable article. It greatly helped me to start with my webdav server.

    But I am stuck at one point can you help me with that.

    1. I need to get my documents from database and for that i need guid of the folder clicked by user. But IE seems to send only the path of folder along with the webdav method.Is there any way by which we can get a property back from IE along with a Propfind request.

    2. The opaquelocktoken sent with the Lock response is a unique GUID. How to generate it?? I read about some algos creating UUId but they talk of some NodeId and version — which i am not very clear on.

    Thanks in advance

    Regards

  18. Geoff Lane writes:

    Stacey,
    1. As long as you are going to be WebDAV compliant, the Path is all you are going to get. You will need a way to query the database and get an item based on its virtual path. The WebDAV useage is probably very different from the how your other applications are using the database, so consider creating creating views or “reporting tables” to help make the data access easier.

    2, In .NET there is a System.Guid class that has a NewGuid method. For all pratical purposes you could use a few random characters, your host name and a timestamp or something like that if you weren’t programming with a language that had easy GUID generation.

  19. stacy writes:

    OK I have used .Net’s System.GUID class. GUId (lock-token) now gets generated on LOCK request. But, the problem is I do that on every lock request (even if it is for the same resource) received by the server. I want to have exclusive locks on a resource. Would I have to keep a track within my custom webdav server as to which resource is currently locked and what’s the lock-token?

  20. stacy writes:

    One more thing, I found that anyone can find any one else’s lock token by DAV:lockdiscovery property. How can we use this property?

  21. Geoff Lane writes:

    Stacy,
    1. Yes you will have to keep track of the lock status/token for a given resource. You also have to check whether a resource is locked (and if the user supplies the proper lock token) for requests that modify the resource. The exact command are specified in the WebDAV RFC. This is easily done in a database or with a simple Hash structure mapping a resource to a lock. One caveat, a collection can be locked which means all of the children of that collection have an implied lock as well.

    2. lockdiscovery returns information about the lock. It can include things like who has the lock, when the timeout expires and the locktoken itself. The RFC also states: “The server is free to withhold any or all of this information if the requesting principal does not have sufficient access rights to see the requested data.” So, basically, don’t give back the lock token to a user who should not be able to override that lock in some way.

  22. stacy writes:

    HI Geoff

    I am stuck on one point now. A Non Microsoft office documnet (like tiff) files does not send a LOCK or PUT request so they cant be saved if are modified by some user. So is it a general phenomena or its only with some formats that PUT request is not sent.

    Thanks

  23. Geoff Lane writes:

    Stacy,
    The Mini-Redirector (the one that allows you to map a network location to a drive letter) does not support locking. When you open an Office document, they are actually handed off to Office and Office uses its own WebDAV implementation to open it. The Office WebDAV supports LOCK and UNLOCK.

    I have not see applications that won’t do a PUT. What happens if you drag and drop a TIFF file? Does it save then?

    If you add a network location in ‘My Network Places’ and use a defined port or https, then you will uses the Office Web Folders all the time. When you do that, I’ve see it where you can’t double-click non-Office files to GET them.

    In general, I’m coming to the conclusion that the Microsoft WebDAV implementations are pretty weak. I’ve had to open multiple support cases with Microsoft to get information on what deviations they have from the standard to work around them. You might need to do the same thing.

  24. Fahad writes:

    I am trying to implement the WebDav for Readonly access to documents.
    I tried your idea and got “ASP.NET Web Application without ASPX Extension” working.
    Now when I tired to open the same location (http://localhost/WebDav)
    by typing \\localhost\WebDav in the Explorer
    i am getting the error

    “\\localhost\WebDav is not accessible. You might not have permission to use this network resource. Contact the administrator of this erver to find out if you have access permission”

    “The network path was not found”

    Thanks

  25. Germinal Ibarrola writes:

    Geoff,

    I am in the process of completing a webdav server framework in C# and was wondering the best way to distribute the codebase to the public (I was initially thinking CodeProject or Sourceforge). I have been working on the framework for approx 1 week and am almost done (NDoc comments soon to come!). The framework will allow a developer to easily expose webdav server functionality for any custom solution (I am including a filesystem adapter example to show how easy it is to use).

    I decided to create this framework after being unable to find any good articles on the web regarding webdav and C# and also to webdav enable my company’s Ayos File Managment System (formerly Spheros File Managment Server).

    Let me know!

  26. Geoff Lane writes:

    Germinal,
    I would go with SourceForge if you plan on making it Open Source. That way you could build up a development community around the project. Code Project is only good for one-off examples and not for real, working code.

  27. Geoff Lane writes:

    Fahad,
    You don’t want to use a UNC path (\\example\Path) to connect to a WebDAV share. You want to map a network drive and use the HTTP path (http://example/Path). From Internet Explorer you can also do File -> Open and use the HTTP path along with checking the checkbox on the form.

    In general, the “No permission” or “Can’t map network location” kind of errors could be just about any sort of problem with the response. So, unfortunately, I can’t tell you a lot about what the specific error might be.

  28. Fahad writes:

    Germinal Ibarrola,
    When you will be releasing the code? I am really interested in that.
    Thanks

  29. Germinal Ibarrola writes:

    Thanks Geoff,

    All… I’ll be releasing the code on SourceForge in the next month or so (as time permits!) and will also have the latest code available on http://www.sphorium.com.

  30. stacy writes:

    Hi Geoff

    I am in the process of making my webdav server. But when i try to create a new folder through webdav, it sends me a Head request to whose my response is “200″ and other necessary headers. But I always get an error that
    “A folder named ‘New Folder’ already exists. Please enter a different name.”
    Other then this whenever i get a Head request, the processing is fine but while creating a new folder, i get this error.I dont get MKCOL request as expected.

    Thanks

  31. Geoff Lane writes:

    Stacy,

    If it’s sending a HEAD (or most other verb really) request for a path like ‘/webdav/example/New Folder’ and New Folder does not exist, the proper response is returning a 404 to indicate that the resource is not found on the server.

    It sounds like your WebDAV client is probing to see if the resource exists.

    The only command this doesn’t apply to that I can recall is the LOCK command. A client can LOCK a non-existant resource. Basically they lock in anticipation of creating that resource to ensure that no one sneaks in and takes the name behind them.

  32. Cesar Guinovart writes:

    Hi,
    All the info here has been very helpful and while i am reading rfc 2518 and 3253 i wanted to ask a question.
    I got as far as being able to intercept any calls for files but not for directories.
    Also , how would i intercept the first call that displays the root of the virtual directory and its files and folders.
    I am trying to not show the file system but instead show my own files which are on a database.

    Thanks in advance

  33. Oleg writes:

    If you have IIS 6.0, this article will helpful to enable wildcards: http://www.ureader.com/message/1251379.aspx

  34. Geoff Lane writes:

    Thanks Oleg, that’s a great link that might help people out.

  35. Germinal Ibarrola writes:

    Guys,

    I’ve initial ASP.NET WebDav Server framework (beta 2) has finally been released https://sourceforge.net/projects/webdav/. It currently supports RFC2518 (http://www.webdav.org/specs/rfc2518.html) and I am in the process for supporting RFC3253 (http://www.webdav.org/specs/rfc3253.html)

    It includes all source code in addition to a custom file implementation demo project.

    I’m open for suggestions!

    Thanks.

  36. Fahad Azeem writes:

    Thanks a lot !

  37. Yahia writes:

    looks really good :-))

    though one thing is not clear - the license: is it GPL or LGPL ?

    Yahia

  38. Kavita writes:

    Hi Geoff

    when an application sends a LOCK request,my WebDAV server locks the file in my database as well as on web server. But if any problem occurs like application hangs then UNLOCK of webDAV server is not called hence i am not able to unlock it from my database. but the server unlocks it on its own.

    Any Idea how to solve it??

    Thanks

  39. Geoff Lane writes:

    Kavita,

    A LOCK command should have a timeout value. You can store the timeout value with the LOCK and check and see if the timeout has expired when you check the database. If it’s expired, then remove the lock from the database.

    A client will resend LOCK commands to keep the lock fresh if it needs to hold on to it, so you would then just update the timeout/timestamp when you get a LOCK request to update an existing lock.

  40. Miss Lane writes:

    My IT team is trying to connect to a WebDAV connection offsite. We’re able to connect to it at times, but periodically we’re receiving the message “You might not have permission to use this network source. Contact the administrator of this server to find out if you have access permissions.”

    I’ve called the guy who handles the WebDAV service there, and he remarked that everything seemed fine on his side. We ended up recreating our connections and everything was fine.

    One thing that came to mind was password expirations, but he said that flag had not been set on his side.

    Are there any other evident solutions to this problem, or are we to believe that the best way to evade this situation is to have to recreate an isntance of the connection everytime we are prompted with this error message.

    Anyhelp will be muchos graciasly appreciated.

  41. Stacy writes:

    Hi

    In my WebDAV server, i do not allow user to delete files which exist in the lowest level of my hierarchy. so whenever a request for file deletion comes, i am sending a status code of 405.

    But when an XP machine sends a deletion request, it always sends delete request for the lowest level object.
    Now since i am denying the file deletion, i am not able to delete even folders if the requesting client machine is an XP.
    However it works fine with 2003 server machine as it directly sends request for the selected resource.

    can anyone suggest how to deal with this situation.

  42. JJ writes:

    Sorry… I don’t understand… where is this custom Webdav server?

    Thanks

  43. Geoff Lane writes:

    JJ,
    Sorry, the code I did was for a client, so I was not able to share it. I just wanted to share some ideas in case anyone else was doing the same thing.

    One of my blog readers has implemented an Open Source project available at https://sourceforge.net/projects/webdav/
    if you would like to look at someone else’s code.

  44. Stacy writes:

    Geoff

    I have been working on Custom WebDAV server and am about to complete it.I have developed it on a Windows 2003 server machine and it works perfectly fine but when I tested it with an XP client (IIs v5.1), I found it is sending me different requests from a windows 2003 server(IIS v6.0) client.

    Like the “COPY” operation on an XP machine sends request to first create a collection by sending ‘MKCOL’ and then getting the files from the source of copy location (’Get’ request)and then putting them on to newly created collection by a ‘PUT’ request. It never sends a ‘COPY’ command.

    Did u also face this and can you suggest how to get rid of this because my implementation of MKCOL and COPY are different. did u apply any update to get it fixed??

    Thanks in Advance

    stacy

  45. Geoff Lane writes:

    Stacy,
    The IIS version on the client won’t matter (IIS would only matter on the server receiving the requests). What might matter is the version of the mini-redirector and/or the version of Microsoft Office installed on the client machine. I never had to deal with the problem myself, all of the client machines were going to be running Windows XP.

    In general, the standards support in Windows is pretty bad. There are a lot of things that they do that I would consider incorrect with regards to the WebDAV standard. In general I found though that if my code passed the WebDAV litmus tests, then Windows XP would work, even if it was doing more or different commands from what I would expect.

    Check out my other WebDAV article. It’s got some information on the different implementations as well as some useful (I hope) links that talk about the different WebDAV implementations in various version of Windows.

  46. Mux writes:

    Hi DMA, try this one: http://www.webdavsystem.com/

    ed. I need to start charging for these links

  47. Anton writes:

    Hi

    Tell me please which external tool can I use to track the request and response packets send to/from WebDav server?

    I tried Ethereal, but I can’t cath any packets. I created a web application in visual studio 2005, so the address of the page, which I run from VS is like http://localhost:1233/WebDavServer. Even when I use no filters in Etherreal I can’t see any packets.

    Thaks for your Consideration
    Anton

  48. Geoff Lane writes:

    Anton,
    Windows does not provide an interface to capture packets against the localhost. To get around this, I actually set up 2 virtual servers, one to host the server and the other to use as a client. That way I could capture packets with Ethereal going to the “remote” server (really a virtual instance on the same machine).

    You could do the same thing by connecting to your development machine from another machine on the same network.

    Hope that helps.

  49. Anton writes:

    Thanks, Geoff
    I will try to deploy my web application to IIS.

    Other thing I would like to aks you: What is the specific behaviour of Mini-Redirector while mounting http connection.

    I tried to use Stasys WebDAV.Net framework and the test server. DAVExplorer successfully mounts the http connection, but Windows Mini-Redirector fails.

    Any suggestions?

    Best Regards
    Anton

  50. Anton writes:

    I have more one weird issue which I can not figure out. Maybe you could clear if for me.

    While browsing through Stacys WebDav Demo Server, it does not handle PROPFIND requests on folders. I mean when I put a breakpoint In DavModule, which is inherited from IHttpModule and click on the folder in DAVExplorer, the execution does not hit the breakpoint. But it’s hit while sending any other requests.

    Do you have any ideas whats wrong?

    Thanks
    Anton

  51. Anton writes:

    Oh also I forgot to add that the response in the case with folders is in HTML and says 404 FORBIDDEN

  52. Geoff Lane writes:

    Anton,
    Please take a look at my other WebDAV article for information and links about the Mini-Redirector.

    404 is a Not Found error
    403 is Forbidden

    I can’t comment specifically on Germinal’s code as I haven’t looked at it much. If it’s not allowing PROPFIND on a folder, then it is broken. I would recommend you see if there is a mailing list for that and see if you can ask a question.

    I would double check the IIS mappings for the IHttpModule though. By default IIS is only going to pass requests to things that have an extension. You need to map the IIS request to handle all incoming request or using URL rewriting to get that to work. See my article about mapping asp.net applications without extensions for some information on that.

  53. Anton writes:

    Hi Zorched.
    I’ve been developing my own web dav server for a while. A few days ago I tried to deploy it to IIS 6.0 under windows 2003.

    A few days of pain, and finally I managed to see webdav folder contents through DavExplorer.
    Then I tried to map the drive using Windows Explorer. And here Im stuck now. Explorer actually mounts a network drive, but for some reason it is not a web folder but a usual network folder \\server\folder. So when I try to see its contents from explorer, it does not try to communicate with it as with web folder using mini redirector.
    At the same time I can successfully mount a directory from the URL created by Visual Studio.

    Any ideas how to fix that issue?

  54. Geoff Lane writes:

    Anton,
    Take a look at my other post Web DAV Tips and Tricks and look at the section on Server Discovery. I think that might help you out. It’s definitely not to the WebDAV spec, but there are a few things you need to do to get Explorer to work.

  55. Jonas writes:

    I’ve built a fully functional WebDAV server (though it may not be fully up to the specifications at webdav.org; I’ve built it for Windows XPs WebDAV client) using the techniques you’ve described and I must say I’m excited when I see the result! Works great together with SQL Server, and with a web interface to manage versions it will be a great end-user experience.

    But it’s when I wish to deliver the service to an end-user I run into problems. I determine if an incoming request is a normal request or a WebDAV request using a flag (eg. “filelibrary”) in the request URL. This works great on my development machine, but when I set it up on another server and add a web folder in windows to a public URL, it does not work. Let me clarify with an example: If I use a local webbserver, and add a web folder with a url like “http://localhost:1067/TemplateBusiness/filelibrary” it works great. The “filelibrary”-flag is found in the URL and therefore the request is a WebDAV request. But when I place the application on a production server, and try to add a webb folder using a URL like “http://www.mydomain.com/filelibrary” I have no luck at all. Internet Explorer tells me it’s not a WebDAV server (up yours, IE =), because I know it is) without even sending a request to my server! I log all requests, but there are no incoming requests at all! You have any ideas why this happens? What I know is that it got nothing to do with DNS or other problems, all other requests for web pages goes fine (and is logged).

    Thanks in advance!

  56. Geoff Lane writes:

    Jonas,
    Did you see my other post More WebDAV Tips, Tricks and Bugs? Specifically the section about server discovery. That might help you?

  57. Jonas writes:

    Thanks for your reply.

    Yes, I’ve seen that post, but the strange part is that the client does not even send a OPTIONS-request to the root node of the URL. I’ve placed Request.SaveAs(”file.txt”) in my BeginRequest-eventhandler but there is nothing in that file after the webfolder mapping fails.

    Normal HTTP requests to the same website is being saved in the file though…

  58. Geoff Lane writes:

    Jonas,
    Well, the OPTIONS command will get sent to the ROOT of the web server, so it will not get sent to your code or handler. I had to manually modify the properties of IIS to return PROPFIND, etc when an OPTIONS command is issued to any path.

    So it won’t send it to “http://www.mydomain.com/filelibrary/”, but to “http://www.mydomain.com/” instead. You probably don’t have .NET code running there to capture the request?

    If that’s not what you meant, then I’m not entirely sure…

  59. Jonas writes:

    You’re right, because of some strange reason my .NET-code does not catch request sent to the root. If I enter the domain http://www.mydomain.com/ it redirects to http://www.mydomain.com/Default.aspx though. Seems IIS takes care of all root requests so that it can redirect them to the correct standard page. Makes no difference if I disable standard pages either.

    Thanks for your help this far; would be great if you gave a little more details on how you configured IIS to respond to OPTIONS-requests, that seems to be what I’m missing here. Alternatively I should get the .NET-runtime to handle root requests as well, but I can’t find out what I’m missing there.

  60. Geoff Lane writes:

    Jonas,
    I have an article that explains how I set up IIS to not require the .aspx extension to load .NET code.

    For the OPTIONS, I just modifed the default setting of IIS to change the values returned for an OPTIONS request (I can’t remember the details at this point, but will try and look through my notes in the next few days at some point). I think I also had to add a header for MS-Author-Via: DAV to get windows to work.

  61. Jonas writes:

    Aaha, I hadn’t seen that article. Now it works perfectly. Looked a little different here compared to those screenshots though, but basically I did what you did. Removed all “interpreters” and then added the aspnet_isapi.dll to all. Now my .NET HttpModule catches ALL incoming request, no matter what path is requested. I did not configure IIS to answer to certain verbs though (like OPTIONS or PROPFIND), I let .NET handle everything instead.

    Thanks for your help and continue blogging! (you might consider tagging up that article you tipped me about with the “webdav” tag aswell, might help others)

  62. Marc writes:

    Hi Geoff,

    Under IIS 6, mapping an isapi extension to .* doesn’t work. How can I get around that? And could you help me on the way with some DAV Server source code?
    Thanks!

  63. Geoff Lane writes:

    Marc,
    Under Windows Server 2003: .* is not allowed, there is an extra ‘all extensions’ section where you can add the aspnet_isapi.dll.

    Let me know what questions you have about the code, I hope I can help.

  64. Jonas writes:

    Geoff, did you build your webdav server with asynchronous transfers? I’m a bit curios on how to do that. As it is now, im using Response.BinaryWrite to send a file to the client and Request.InputStream to receive a file. When receiving a file, the client does not show any progress on the current file.

    Any tips or ideas would be greatly appreciated.

  65. Geoff Lane writes:

    Jonas,
    The HttpContext is handled asynchronously in the fact that it responds to BeginRequest events. Actually writing the data doesn’t need to be done asynchronously though. All that would do would allow your application to remain responsive, but since it’s already handling each request in a separate thread, that’s not an issue.

    How are you sending data?

    The following code snippet is a standard method of writing buffered data in chunks to an output stream. Maybe that will help?

    
    byte[] buf = new byte[1024];
    int read = 0;
    using (Stream outs = resp.OutputStream) {
      do {
             read = content.Read(buf, 0, buf.Length);
            outs.Write(buf, 0, read);
         } while (read > 0);
         outs.Flush();
      }
    

  66. Jonas writes:

    This is how I am sending data to the client:

    if (!data.IsBinaryDataNull) {
    response.BinaryWrite(data.GetBinaryDataReference());

    And this gives no status what-so-ever to the client, so I will try the code you suggested instead.

    But that still leaves me with the problem when the client sends (puts) data to the server… can I receive that in chunks aswell? I suppose it doesn’t matter if the Request.InputStream is read in chunks… anyhow, this is my code (almost pseudo-code, there are some more logic but this is the core):

    // Get the data from the request
    data = new byte[request.InputStream.Length];
    request.InputStream.Read(data, 0, data.Length);
    request.InputStream.Close();
    request.InputStream.Dispose();
    // Save the data into the database through the filedata-object
    filedata.SetBinaryDataReference(ref data);
    filedata.Insert();

    Thanks for your quick answers and your patience!

  67. Geoff Lane writes:

    Jonas,
    If you make your byte array the same length as the input stream, then you are not reading it in chunks. If you notice in my previous example, I read/write in a 1k chunk. That’s done in a loop so you get the whole thing in 1k chunks.

    Basically you just change the input stream and the output stream to change from reading to writing.

    When dealing with IO, you should also always use a using() block or a try/finally block and close the stream in the finally block, otherwise if an exception is thrown the IO won’t get closed properly.

  68. Jonas writes:

    I just recently discovered that SharePoints WebDAV does not show status on ongoing transfers either (on large, single files that is). Seems to be a limitation in the Windows WebDAV-client.

    I am aware of that my data is not read/written in chunks. What I am wondering is why I would bother - there is no difference to the client, right? Also, I think I will have a hard time writing data in chunks into my database, but I used your example when reading and outputting data to the client. That could be done with the GetBytes()-method on the SqlDataReader-object.

    I do not have try-catch-blocks in my code because I am using a database as the back data store.

    Have you tried your WebDAV-solution on Windows Vista? Mine did not work :P

  69. Pascali writes:

    I have a problem with WebDav on Windows Vista Enterprice (in Windows XP all work normal) Did you meet the same problem

  70. Steve Thomas writes:

    A sharepoint web folder contains a nicer looking interface then the basic web dav - web folder. Do you have any idea how they accomplish this. It looks like an html page or a stylesheet. does webdav support sending a folder template to use?

  71. Geoff Lane writes:

    Steve,
    I don’t think that there is any way to change the look of a WebDAV folder. The protocol does not have any means of returning view related information back to the client. Basically all it does is describe the files and folders, it’s up to the WebDAV client how to display that information. Generally that display is the same as if you were looking at local files. So on Windows it looks like Explorer, and on Mac OS X it looks like the Finder.

  72. Jonas writes:

    Steve Thomas: I think the SharePoint web folder looks different because it “pretends to be” a normal windows file share.

    I’m having problems with Windows Vista (as Pascali does) and WIndows Server 2003, really strange. My IIS-logs shows nothing, seems the client never even tries to connect.

  73. Simon Hendry writes:

    Hi,

    I have been developing a webdav server in .net with a backend SQL store. It all works great ( thanks to a number of your tips ). I was wondering however if you (or any of your readers) had worked out how to get the properties out of a word document. If I load a word document from my webdav server and then select file->Properties then MS word fires a PROPFIND back to my server asking for a “save-profile-form-location” property, and word load a single “OK” dialog that says “Verifying Web Properties”.

    Word sends a PROPFIND request that looks like this.


    and I am current replying as below but have tried lots of different schemas

    test.doc

    HTTP/1.1 200 OK

    /WDClient/profile.doc

    I have tried to return all sorts of data (href, htm , aspx etc etc ) back to word via my webdav server to get word to do anything but it seems to totally ignore my servers PROPFIND response for this property and loads the properties dialog as normal. I was hoping that this would give me some way of prompting the user for custom properties that I could save on the server.

    Just wondering if you had come across this. I am using Office 2003.

  74. Simon Hendry writes:

    Sorry my propfind headers got mangled here they are again, with [ ]

    Word Sends

    [a:propfind xmlns:a="DAV:" xmlns:b="urn:schemas-microsoft-com:datatypes"]
    [a:prop xmlns:c="urn:schemas-microsoft-com:office:office"]
    [c:save-profile-form-location /]
    [/a:prop]
    [/a:propfind]

    I am replying

    [D:multistatus xmlns:b="urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882" xmlns:MS="urn:schemas-microsoft-com:office:office" xmlns:D="DAV:"]
    [D:response]
    [D:href]test.doc[/D:href]
    [D:propstat]
    [D:status]HTTP/1.1 200 OK[/D:status]
    [D:prop]
    [MS:save-profile-form-location]/WDClient/profile.doc[/MS:save-profile-form-location]
    [/D:prop]
    [/D:propstat]
    [/D:response]
    [/D:multistatus]

  75. Geoff Lane writes:

    Simon,
    To start with, you might want to use the same namespace that is being sent to you in your reply. So, instead of MS:save-profile-form-location, try using c:save-profile-form-location.
    Second, you’ll need to find out what it means - what data it expects to come back. It’s likely that it doesn’t just want a path to a file, but something else.

    Your best bet is to probably call Microsoft support. I couldn’t find any details about it on the web.

  76. Jonas writes:

    Geoff,

    May I ask how you solved the authentication with your WebDAV-server? In my implementation I am using forms authentication with a “remember me” option. Then Windows XPs and Windows 2000s WebDAV clients sends the remembered authentication information, and the user is identified. But in Windows Vista, this forms authentication is not sent when accessing the WebDAV-folder. Vista uses a new client (Mini-Redirector-6 or something like that), and I guess that is why it does not work anymore.

    Is there another way to authenticate users? I wish to provide a single-point-of-logon, and that I can do today with forms authentication.

    Thanks in advance!

  77. Geoff Lane writes:

    Jonas,
    I used Digest authentication. You could also use HTTP Simple Authentication. Digest is more secure if you are running on an unencrypted connection. The WebDAV spec says that “WebDAV applications MUST support the Digest authentication scheme”. So, I’d got that route if I was you. If you send an HTTP 401 Unauthorized response to the client with the proper WWW-Authenticate header, Windows should automatically show a dialog box.

    HTTP Basic and Digest Authentication RFC

    I think it’s a bit of an accident that a user that logged into a web application and got a cookie would be able to authenticate against your WebDAV server. I wouldn’t rely on that.

  78. Jonas writes:

    Thanks for the advice, I’ve now implemented Digest Authentication according to the RFC specifications and it works great! I removed all form-based logins so now Http Authentication is used for the whole web application and for the WebDAV-server, looks exactly like SharePoint.

  79. Bill Seddon writes:

    I’m adding this post because this blog post is the one I first saw when searching around for some code and information to help implement a webdav server. The solution I implemented will not suit everyone but for those that may benefit the code is on CodeProject (http://www.codeproject.com/useritems/NET_WebDAV_Server.asp).

    I’ve no doubt there’s better code out there but it may give someone a head start.

    I think I’ve the answer to a couple of the questions posted here. One is about being able to use a pretty file list that Excel and Word present when interacting with Sharepoint. The short answer is that you can’t. Although Sharepoint is a WebDAV server, it’s also Frontpage server and, in fact, the Office tools use the Frontpage RPC protocol when communicating with Sharepoint. You can see this if you install Fiddler2 (www.fiddler2.com) a free local proxy implemented by a Microsoft employee that allows you to see all headers and body information sent to and received from an HTTP server. Because this is a proprietary protocol, Microsoft can and do extend it to do things that are useful to them such as return a nice file listing.

    Whenever any of Microsoft’s re-directors are used they will default to use Frontpage and this probably explains why the MS header must be returned in response to the OPTIONS verb.

    One of the regular question is about installing a WebDAV server. The example WebDAV server in the CodeProject article can be installed either at an IIS root or at a virtual directory. In principle it shouldn’t matter where the WebDAV is installed. The Microsoft WebDAV clients will issue an OPTIONS request to the URL specified and issue a PROPFIND if the OPTIONS response is satisfactory. If it’s not, they will then query the web server root. The chances are that this will generate a good response and so Excel or Word will try to work with it though the result amy not be what you expect.

    As suggested here, the WebDAV server is implemented as a IhttpHandler so that the WebDAV serve can be installed using a wildcard map.

  80. Geoff Lane writes:

    Bill,
    Thanks for the great comment and the link to the code.

  81. pramod writes:

    I have configured WebDAV Application on my server win 2003 and everything working fine but i am not able to set password protectet. plz help me how to over come this problem. ASA

  82. Hoju Saram writes:

    Hi geoff,

    Just thought I would let you know that I have just posted a post on my blog about C# webdav server with SQL backend. I have included the full source so it may be useful to anyone wanting to have a look at how you might go about building something like this. You can check it out at:

    http://thehojusaram.blogspot.com/2007/06/c-webdav-server-with-sql-backend-source.html

    Thanks

  83. Surendran writes:

    Hi

    I want to send documents generated by a buisiness process to different clients by FTP over SSL. That applicaion is working fine. But a few of the clients do not have FTP server but using secure HTTP (WebDAV). I need to copy files from folders on local drive or IIS virtual folders to remote web site folders.

    The code I found on MSDN is for copying files from one folder to another on the same web site. In my case I need to copy it either from a local folder or virtual folder in localhost. In the MSDN code I couldn’t figure out a way of providing different credential for accessing resources from localhost and remote host.
    Can someone help me to fix the code. Or can someone suggest a different way of doing it in .NET?

    [STAThread]
    static void Main(string[] args)
    {
    System.Net.HttpWebRequest Request;
    System.Net.WebResponse Response;
    System.Net.CredentialCache MyCredentialCache;
    string strSourceURI = “http://localhost/Extracts/Client1/test.csv”;
    string strDestURI = “https://200.150.100.50/Uploads/test.csv”;
    string strUserName = “UserName”;
    string strPassword = “password”;
    string strDomain = “Domain”;

    try
    {
    // Create a new CredentialCache object and fill it with the network
    // credentials required to access the server.
    MyCredentialCache = new System.Net.CredentialCache();
    MyCredentialCache.Add( new System.Uri(strSourceURI),
    “NTLM”,
    new System.Net.NetworkCredential(strUserName, strPassword, strDomain)
    );

    // Create the HttpWebRequest object.
    Request = (System.Net.HttpWebRequest)HttpWebRequest.Create(strSourceURI);

    // Add the network credentials to the request.
    Request.Credentials = MyCredentialCache;

    // Specify the COPY method.
    Request.Method = “COPY”;

    // Specify the destination URI.
    Request.Headers.Add(”Destination”, strDestURI);

    // Specify that if a resource already exists at the
    // destination URI, it will not be overwritten. The
    // server would return a 412 Precondition Failed status code.
    Request.Headers.Add(”Overwrite”, “F”);

    // Send the COPY method request.
    Response = (System.Net.HttpWebResponse)Request.GetResponse();

    // Close the HttpWebResponse object.
    Response.Close();

    Console.WriteLine(”Item successfully copied.”);

    }
    catch(Exception ex)
    {
    // Catch any exceptions. Any error codes from the COPY
    // method request on the server will be caught here, also.
    Console.WriteLine(ex.Message);
    }
    }
    }

    Many thanks.

  84. Germinal Ibarrola writes:

    Guys,

    After a long hiatus, I’m back on the project… the code has been upgraded to VS 2005

    https://sourceforge.net/projects/webdav/

    Comments and suggestions welcome!

    Germinal

  85. geetha writes:

    hi all,could somebody help me sending an OPTIONS request to a webdav server from a client.

  86. David writes:

    Is it possible to download your WebDAV server?

  87. gprakash writes:

    hi anybody developed the webdav with sql backend database share the coding
    with me

  88. gokul writes:

    hi i downloaded from the following site http://sourceforge.net/projects/webdav
    this one is maintaining the filesystem only
    in that i want with sql database also
    hi anybody developed the webdav with sql backend database share the coding
    with me

Leave a Reply