Creating Class 1 WebDAV Server

Class 1 server provides basic WebDAV functionality. On a Class 1 server, you can create, delete, copy, move files and folders as well create, update and delete custom properties.

Engine Class

To create Class 1 WebDAV Server, you must implement IFolder and IResource interfaces and create a class derived from Engine.

The core component of WebDAV Server library is the Engine class. It parses WebDAV XML requests and generates XML output. Here is typical engine workflow for each request:

1. Create separate Engine instance for each request.
2. Call Engine.Run() method.
3. Engine calls Engine.License get.
4. Engine calls Engine.GetHierarchyItem()
5. Engine calls members of interfaces IFolder, IResource, etc.

The Engine provides overloaded Run methods optimized for use in IIS/ASP.NET-based server and in HttpListener-based server.

Here is how simple requests processing cycle in your HttpListener-based server will look like:

HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://localhost:8080/");
listener.Start();
while (true)
{
    HttpListenerContext context = listener.GetContext();
    WDEngine engine = new WDEngine(); // your class derived from Endine class
    engine.Run(context, listener.Prefixes);
    context.Response.Close();
}

For the sake of simplicity this code process only one request at a time and will block while waiting for a client request. Usually you will utilize more complex asynchronous model, that does not block while waiting for requests and each request is processed in its own execution thread. Sample servers provided with the library demonstrate this approach.

To host your server in IIS, you will have to create a class derived from IHttpHandler. More about this topic could be found here: Creating WebDAV HttpHandler

To provide Engine with info about items in your storage, you must implement GetHierarchyItem method. Engine calls this method while processing requests and passes the path of the required object. In GetHierarchyItem method, you will be searching your repository and return requested item or null if the object was not found. Here is the sample implementation if your items are stored in file system:

public class WDEngine : Engine
{
    private string repositoryPath = "C:\\WebDAVFiles";
 
    public override IHierarchyItem GetHierarchyItem(string path)
    {
        string fullPath = repositoryPath + '\\' + path.Replace('/', '\\');
 
        DirectoryInfo directory = new DirectoryInfo(fullPath);
        if (directory.Exists)
            return new Folder(directory, this); // implements IFolder
        else
        {
            FileInfo file = new FileInfo(fullPath);
            if (file.Exists)
                return new Resource(file, this); // implements IResource
        }
        return null;
    }
}

The path parameter is relative to WebDAV server root. For example, if your server root is located at ‘http://serv:8080/dav/’ and the requested item URL is ‘http://serv:8080/dav/folder/item.doc’ this parameter will be ‘/folder/item.doc’.

Storage Hierarchy Items

There are 2 types of objects in a Class 1 WebDAV repository: folders, represented by IFolder interface and resources represented by IResource interface. Both IFolder and IResource are derived from IHierarchyItem interface.

The class diargam for IHierarchyItem

Most of IHierarchyItem interface members are self-explanatory and represent properties and methods that each folder and resource have, such as the name of the item, creation and modification date, methods required to copy and move the item.

Note. Microsoft WebDAV Client requires that, creation and modification date of the item to be in Universal Coordinated Time (UTC) format.

In addition to IHierarchyItem methods and properties IResource interface has 4 more members specific for resources: methods for getting MIME type of the resource (ContentType), length of the resource content in bytes, and methods for reading and writing resource content.

IFolder interface has a property for enumerating its children and methods for creating resource and folder.

Response Interfaces

Most IT Hit WebDAV Engine interfaces methods return classes derived from WebDAVResponse class. This is required to inform WebDAV client about the result of the operation. WebDAVResponse class is converted to XML by the Engine and send to a WebDAV client. Often it is required to return different responses depending on how the operation completed. For instance simple CopyTo implementation checks, if the item with destName exists and returns CreatedResponse or NoContentResponse:

public virtual WebDAVResponse CopyTo(IFolder folder, string destName, bool deep)
{

...

WebDAVResponse resp;
if (/*no item with destName*/)
{
// copy item

...

resp = new CreatedResponse();
       }
       else // update existing item
{// update item

...

       resp = new NoContentResponse();
}
return resp;
}

WebDAV Server Engine class reference provides information what type of responses you should return from each method depending on the result of the operation.

To provide WebDAV client with more information about each item operation result when processing trees in CopyTo, MoveTo and Delete implementations of IFolder you can return an instance of MultistatusResponse class. MultistatusResponse is derived from WebDAVResponse and allows specifying what items failed to move copy or delete. MultistatusResponse has AddResponses method for adding errors specifying URL of the resource and its status.

Hierarchy Item Properties

Each item in a repository could have string properties associated with the item. Each property is represented by Property structure and has Name, Namespace, and Value. For manipulating string properties, IHierarchyItem provides GetProperties and UpdateProperties methods. Engine calls GetProperties passing the list of properties requested by client or null if all properties are requested. In your implementation, you will populate the list passed by reference to this method or create the new list and return it to the engine (see example of GetProperties implementation).

In your UpdateProperties implementation, you will create, modify and delete string properties. If any property failed to update then you should not modify any properties and rollback the entire operation. To inform WebDAV client which properties failed to update you must return MultipropResponse class instance. Each item of MultipropResponse contains the information about individual property update operation (see example of UpdateProperties implementation).

Microsoft Office, Windows 7/Vista Web Folders and WebDAV

Your Class 1 server will not support saving directly from Microsoft Office applications as well saving files from Windows 7 and Vista Web Folders client. To publish Office documents to your WebDAV Server using File Open and File Save and drag-and-drop files on 7/Vista you mast create WebDAV Class 2 compliant server. Before modifying any items on a WebDAV server, this applications issue lock commands to prevent documents overwriting by other users.

To support class 2, you must inherit your resource and folder class from ILock and IFolderLock as well as implement lock-null items with ILockNull interface. However, if you do not need the fully functional Class 2 server you can provide simplified implementation of ILock interface:

public LockInfo[] ActiveLocks
{
  get

  {
    LockInfo[] lockInfo = new LockInfo[1];
    lockInfo[0].Token = Guid.Empty.ToString();
    lockInfo[0].Shared = true;
    lockInfo[0].Deep = false;
    lockInfo[0].Owner = "Name";
    return lockInfo;
  }

}

public WebDAVResponse Lock(ref LockInfo lockInfo)

{
  lockInfo.Token = Guid.Empty.ToString();
  return new OkResponse();
}

public WebDAVResponse RefreshLock(ref LockInfo lockInfo)

{
  lockInfo.Shared = true;
  lockInfo.Deep = false;
  lockInfo.Owner = "Name";
  return new OkResponse();
}

In this case, your server will not protect against items modifications but will be accessible from Microsoft Office applications and Windows 7/Vista Web Folders client. However, you still will have to implement ILockNull and IFolderLock interfaces.

 

See Also: