0

I have a VB.NET / ASP.NET web application (on .NET 4.7) that I'm trying to add a virtual folder, and have had no success. Perhaps I'm doing it wrong, or I'm missing something; I would greatly appreciate some help with this.

After some research, I created some classes based on VirtualPathProvider, using ~/Repository for the virtual folder, and a local folder on C: for the physical path (i.e. C:\Temp\Repository).

I can see that when the ~/Repository folder is accessed that my custom class (RepositoryPathProvider) is being accessed - such as the FileExists, DirectoryExists and the GetFile functions; however, I am getting a 404 not found error on the web page for elements within the virtual folder (i.e. images or css).

Can someone look at my code, and tell me what I might be doing wrong? Or, alternately, provide a better or easier method to do this. Thanks!

Global.asax.vb:

    If Not settings.BMSRepositoryPath Is Nothing Then
        Dim rpp As New RepositoryPathProvider("~/Repository", settings.BMSRepositoryPath)
        HostingEnvironment.RegisterVirtualPathProvider(rpp)
    End If

RepositoryPathProvider.vb:

Public Class RepositoryPathProvider : Inherits VirtualPathProvider

    Private ReadOnly _virtualDir As String 'Virtual folder path, i.e. ~/VirtualFolder
    Private ReadOnly _physicalPath As String 'Physical folder path, i.e. C:\PhysicalPath\MyFolder

    Public Sub New(virtualDir As String, physicalPath As String)
        MyBase.New()
        _virtualDir = virtualDir
        _physicalPath = physicalPath
    End Sub

    Public Overrides Function FileExists(virtualPath As String) As Boolean
        If IsVirtualFolderPath(virtualPath) Then
            Dim physicalPath As String = MapVirtualToPhysicalPath(virtualPath)
            Return System.IO.File.Exists(physicalPath)
        End If
        Dim retval = Previous.FileExists(virtualPath)
        Return retval
    End Function

    Public Overrides Function DirectoryExists(virtualPath As String) As Boolean
        If IsVirtualFolderPath(virtualPath) Then
            Dim physicalPath As String = MapVirtualToPhysicalPath(virtualPath)
            Return System.IO.Directory.Exists(physicalPath)
        End If
        Return Previous.DirectoryExists(virtualPath)
    End Function

    Public Overrides Function GetFile(virtualPath As String) As VirtualFile
        If IsVirtualFolderPath(virtualPath) Then
            Dim physicalPath As String = MapVirtualToPhysicalPath(virtualPath)
            Dim retval = New CustomVirtualFile(virtualPath, physicalPath)
            Return retval
        End If
        Return Previous.GetFile(virtualPath)
    End Function

    Public Overrides Function GetDirectory(virtualPath As String) As VirtualDirectory
        If IsVirtualFolderPath(virtualPath) Then
            Dim physicalPath As String = MapVirtualToPhysicalPath(virtualPath)
            Return New CustomVirtualDirectory(virtualPath, physicalPath)
        End If
        Return Previous.GetDirectory(virtualPath)
    End Function

    Private Function IsVirtualFolderPath(virtualPath As String) As Boolean
        Dim appRelativePath As String = VirtualPathUtility.ToAppRelative(virtualPath)
        Return appRelativePath.StartsWith(_virtualDir, StringComparison.OrdinalIgnoreCase)
    End Function

    Private Function MapVirtualToPhysicalPath(virtualPath As String) As String
        Dim appRelativePath As String = VirtualPathUtility.ToAppRelative(virtualPath)
        Dim relativePath As String = appRelativePath.Substring(_virtualDir.Length).Replace("/", "\")

        If relativePath.StartsWith("\") Then relativePath = relativePath.Substring(1)

        Dim retval As String = System.IO.Path.Combine(_physicalPath, relativePath)

        Return retval
    End Function
End Class

CustomVirtualFile.vb:

Public Class CustomVirtualFile
    Inherits VirtualFile

    Private ReadOnly _physicalPath As String

    Public Sub New(virtualPath As String, physicalPath As String)
        MyBase.New(virtualPath)
        _physicalPath = physicalPath
    End Sub

    Public Overrides Function Open() As System.IO.Stream
        Return System.IO.File.OpenRead(_physicalPath)
    End Function
End Class

CustomVirtualDirectory.vb:

Public Class CustomVirtualDirectory
    Inherits VirtualDirectory

    Private ReadOnly _physicalPath As String

    Public Sub New(virtualPath As String, physicalPath As String)
        MyBase.New(virtualPath)
        _physicalPath = physicalPath
    End Sub

    Public Overrides ReadOnly Property Children() As System.Collections.IEnumerable
        Get
            Return New List(Of Object)()
        End Get
    End Property

    Public Overrides ReadOnly Property Files() As System.Collections.IEnumerable
        Get
            Dim m_files As New List(Of VirtualFile)()
            If System.IO.Directory.Exists(_physicalPath) Then
                For Each filePath As String In System.IO.Directory.GetFiles(_physicalPath)
                    Dim fileName As String = System.IO.Path.GetFileName(filePath)
                    Dim virtualPath As String = VirtualPathUtility.Combine(virtualPath, fileName)
                    m_files.Add(New CustomVirtualFile(virtualPath, filePath))
                Next
            End If
            Return m_files
        End Get
    End Property


    Public Overrides ReadOnly Property Directories() As System.Collections.IEnumerable
        Get
            Return New List(Of VirtualDirectory)()
        End Get
    End Property
End Class
7
  • 3
    To run + test virtual folders, then I suggest using full edition of iis, and thus you don't need any code, but can use the GUI to add + setup such folders (no code - you save world poverty). Keep in mind, if you ONLY using files from such folders (not web pages), then code behind can always access any folder that the web server has rights to, including folders outside of the root web folder. Hence, for reasons of security, then I NEVER map such folders (pictures, pdf documents) etc. So, only web (URL's) require virtual folders, but not code behind. Great security and no mapping required Commented Jun 4 at 14:55
  • I do have the full version of IIS, but since this is for development and testing on localhost, I want to avoid requirements for other developers to have to set up an IIS website on their local systems. Thus, I prefer to have the project use the standard localhost:99999 style URL. Commented Jun 4 at 15:26
  • 2
    Is using applicationhost.config an option? Creating virtual directories in IIS express. However, I agree with the earlier comment that using full IIS would be better: that way, you're developing and testing in the environment that it will be deployed to. Commented Jun 4 at 16:56
  • Either you switch to full IIS with IIS Manager, or you use Jexus Manager to create the actual virtual directory on your IIS Express, github.com/jexuswebserver/JexusManager. Static files are by default handled by IIS/IIS Express, not your virtual path provider as that's how IIS handlers are configured. Commented Jun 4 at 17:17
  • 1
    Oh, thanks Andrew. I don't submit questions here very often, I forgot! Commented Jun 5 at 14:47

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.