• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 1911
  • Last Modified:

System.IO.DirectoryNotFoundException for remote folder

Our setup:
- computer 1: Windows 2003 running IIS 6.0
- computer 2: Windows Storage Server on a Network Attached Storage (NAS), where all data stored
                       We have shared a folder on this computer, and computer 1 has mapped this folder as the
- We are using a 3rd pary .NET control that allows users to upload files to our this folder sitting on our NAS.
The problem to solve:
 - We get an error "System.IO.DirectoryNotFoundException for remote folder", whenever it calls the function System.IO.Directory.CreateDirectory("D:\uploads\newfolder")

I think it has something to setting up the .NET security permissions in the machine.config file or web.config file, but I am have tried lots of settings and I am stuck at this point. For you information if the  data were all stored on a folder on computer 1, then everything would works just fine.

3 Solutions
On a local machine, it should execute just fine if the ASP.NET process has read/write permissions both in the NTFS file system and also in IIS. If both are not in sync, then the opertaion will fail.

This is permission issue.

In IIS 6.0 every web application runs in a "Application pool"; Find out under which application pool your web site/web application is using. Righ click on your application pool and select properties.
Click on Identity tab. Enter a domain user account, who has necessary access to the folder where you are trying to create file.

Alos note that this domain account needs to have certain privileges as well (for ex: needs to pbe part of IIS_WPG group etc;)
The code below uses the attached code snippit. Basically you can elevate your access to a domain account with permissions for the other server. You can then revert directly after. Be warned that will need to do error handling on page to revert regardless of any error or else user has potential for continuously elevated privledges which would not be good :(

I believe this is the most resilient and scalable solution because setting password in web.config file is too open to prying eyes (identity impersonate="true") and if trying to synchronise the iusr_xxx on the other box means if its ever replaced then ya have to go "jigging" around with settings to get it going again - sure as anything, 3 years down the line nobody will be able to remember!!

You can retrieve the domain user password from an encrypted source so nothing is available for internal network sniffing or file peeking :)

The attached class for impersonation was created by somebody considerably much smarter than I alas I cannot make claim to it :)

                'set the password details
                clsImpersonate = New AliasAccount(strUserName, strPassword, gstrPDCDomain)
            Catch ex As Exception
            End Try

'copy over file here

        'undo impersonation regardless of success
        If Not IsNothing(clsImpersonate) Then
        End If
Public Class AliasAccount
    Private _username, _password, _domainname As String
    Private _tokenHandle As New IntPtr(0)
    Private _dupeTokenHandle As New IntPtr(0)
    Private _impersonatedUser As System.Security.Principal.WindowsImpersonationContext
    Public Sub New(ByVal username As String, ByVal password As String)
        Dim nameparts() As String = username.Split("\")
        If nameparts.Length > 1 Then
            _domainname = nameparts(0)
            _username = nameparts(1)
            _username = username
        End If
        _password = password
    End Sub
    Public Sub New(ByVal username As String, ByVal password As String, ByVal domainname As String)
        _username = username
        _password = password
        _domainname = domainname
    End Sub
    Public Sub BeginImpersonation()
        Const LOGON32_PROVIDER_DEFAULT As Integer = 0
        Const LOGON32_LOGON_INTERACTIVE As Integer = 2
        Const SecurityImpersonation As Integer = 2
        Dim win32ErrorNumber As Integer
        _tokenHandle = IntPtr.Zero
        _dupeTokenHandle = IntPtr.Zero
        If Not LogonUser(_username, _domainname, _password, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, _tokenHandle) Then
            win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error()
            Throw New ImpersonationException(win32ErrorNumber, GetErrorMessage(win32ErrorNumber), _username, _domainname)
        End If
        If Not DuplicateToken(_tokenHandle, SecurityImpersonation, _dupeTokenHandle) Then
            win32ErrorNumber = System.Runtime.InteropServices.Marshal.GetLastWin32Error()
            Throw New ImpersonationException(win32ErrorNumber, "Unable to duplicate token!", _username, _domainname)
        End If
        Dim newId As New System.Security.Principal.WindowsIdentity(_dupeTokenHandle)
        _impersonatedUser = newId.Impersonate()
    End Sub
    Public Sub EndImpersonation()
        If Not _impersonatedUser Is Nothing Then
            _impersonatedUser = Nothing
            If Not System.IntPtr.op_Equality(_tokenHandle, IntPtr.Zero) Then
            End If
            If Not System.IntPtr.op_Equality(_dupeTokenHandle, IntPtr.Zero) Then
            End If
        End If
    End Sub
    Public ReadOnly Property username() As String
            Return _username
        End Get
    End Property
    Public ReadOnly Property domainname() As String
            Return _domainname
        End Get
    End Property
    Public ReadOnly Property currentWindowsUsername() As String
            Return System.Security.Principal.WindowsIdentity.GetCurrent().Name
        End Get
    End Property
#Region "Exception Class"
    Public Class ImpersonationException
        Inherits System.Exception
        Public ReadOnly win32ErrorNumber As Integer
        Public Sub New(ByVal win32ErrorNumber As Integer, ByVal msg As String, ByVal username As String, ByVal domainname As String)
            MyBase.New(String.Format("Impersonation of {1}\{0} failed! [{2}] {3}", username, domainname, win32ErrorNumber, msg))
            Me.win32ErrorNumber = win32ErrorNumber
        End Sub
    End Class
#End Region
#Region "External Declarations and Helpers"
    Private Declare Auto Function LogonUser Lib "advapi32.dll" (ByVal lpszUsername As [String], _
            ByVal lpszDomain As [String], ByVal lpszPassword As [String], _
            ByVal dwLogonType As Integer, ByVal dwLogonProvider As Integer, _
            ByRef phToken As IntPtr) As Boolean
    Private Declare Auto Function DuplicateToken Lib "advapi32.dll" (ByVal ExistingTokenHandle As IntPtr, _
                ByVal SECURITY_IMPERSONATION_LEVEL As Integer, _
                ByRef DuplicateTokenHandle As IntPtr) As Boolean
    Private Declare Auto Function CloseHandle Lib "kernel32.dll" (ByVal handle As IntPtr) As Boolean
    <System.Runtime.InteropServices.DllImport("kernel32.dll")> _
    Private Shared Function FormatMessage(ByVal dwFlags As Integer, ByRef lpSource As IntPtr, _
            ByVal dwMessageId As Integer, ByVal dwLanguageId As Integer, ByRef lpBuffer As [String], _
            ByVal nSize As Integer, ByRef Arguments As IntPtr) As Integer
    End Function
    Private Function GetErrorMessage(ByVal errorCode As Integer) As String
        Dim FORMAT_MESSAGE_IGNORE_INSERTS As Integer = &H200
        Dim FORMAT_MESSAGE_FROM_SYSTEM As Integer = &H1000
        Dim messageSize As Integer = 255
        Dim lpMsgBuf As String = String.Empty
        Dim ptrlpSource As IntPtr = IntPtr.Zero
        Dim prtArguments As IntPtr = IntPtr.Zero
        Dim retVal As Integer = FormatMessage(dwFlags, ptrlpSource, errorCode, 0, lpMsgBuf, messageSize, prtArguments)
        If 0 = retVal Then
            Throw New System.Exception("Failed to format message for error code " + errorCode.ToString() + ". ")
        End If
        Return lpMsgBuf
    End Function
#End Region
End Class

Open in new window

Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Cloud Class® Course: Microsoft Office 2010

This course will introduce you to the interfaces and features of Microsoft Office 2010 Word, Excel, PowerPoint, Outlook, and Access. You will learn about the features that are shared between all products in the Office suite, as well as the new features that are product specific.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now