Sunday, October 19, 2008

Using ASP.NET to Write Files to a Remote UNC Share

Scenario: Let's say you have an ASP.NET site on a public web server.  The server itself is in an un-trusted domain, e.g. a workgroup server, and the site needs to write files to a UNC share that is in the domain.  There are many reasons you may need to do this, but the difficulty is that you cannot specify NetworkCredentials for the DirectoryInfo class.  You cannot, therefore, authenticate against the UNC share programmatically, and since your application is running in an un-trusted domain, the ASP.NET process identity is of no help.  If possible, the easiest thing to do is write the file locally and have the system that needs the file pull from there via a UNC.  Of course, if you're attempting to share the file across web applications, you'd likely be in the same scenario.

Solution: The solution I have developed for a slightly more complex scenario utilizes a few relatively little known facilities:.  Basically, we'll use an ASP.NET FileUpload to receive a file, write it to a temporary location, perform any needed processing, and then use the WebClient class to perform an HTTP PUT to a local virtual directory that points to an UNC share.  Let's start with the page that receives the file.

Using the FileUpload control couldn't be easier.  Add it to your page and call its SaveAs(string) method to save the file locally.  Of course, that doesn't help us get that file to a remote UNC share, does it?  What we'll do is save that file to a temporary location on the web server, do any necessary processing, and then upload that file.  Here's the code to do that.

    WebClient wc = new WebClient();
string tempFileName = Path.GetTempFileName();
wc.UploadFile(uploadUrl, "PUT", tempFileName);

Let's talk about that uploadUrl variable.  You are probably already familiar with GET and POST, but you may not have had occasion to use PUT and DELETE.  When specifying PUT in an HTTP request, the request URL is the location where the request's file payload should be stored by the web server.  IIS 6 supports HTTP PUT requests via its WebDAV module, but the functionality is disabled by default.  Turn it on the same way you turn on ASP.NET, by clicking Allow after selecting WebDAV in the Web Extensions in IIS manager.  Once it's turned on, the IIS server hosting your application will now accept HTTP PUT requests.  If you do not turn on WebDAV, PUT requests will result in 405 Not Implemented being returned by IIS.

Having enabled PUT, you now need a place to put the files.  Let's create a virtual directory in our site that points at the UNC path that is our final destination.  There are three key points here.  First, we need to ensure that the new virtual directory has Write access.  Second, we need to tell IIS to connect as an account with the same username and password as an account on the machine where the UNC share exists.  Finally, we have to allow Anonymous access to the virtual directory.  If the UploadFile call returns a 401 Unauthorized, one of these three things is wrong.  The account that authenticates to the UNC share should have the necessary permissions to to the share of course, including write access.

There you have it a few lines of code and a virtual directory.  You're not likely to find a simpler solution to this problem.