tag vs. fullPath in custom FileBrowserContentProvider

4 posts, 0 answers
  1. Carl
    Carl avatar
    2 posts
    Member since:
    Jul 2008

    Posted 08 Jul 2008 Link to this post

    I'm tring to implement a custom FileBrowserContentProvider, but i have a few questions.

    Why does "selectedUrl" and "selectedItemTag" never differ? Even though I set "fullPath" and "tag" different when i create DirectoryItems. I would like the fullPath to be viewed to the user, but the tag do be an ID for my internal representation.

    Also, you should point out more in the documentation that you shall look up "selectedItemTag" and not "path", when ResolveRootDirectoryAsTree(string path) is exectued. (which indeed is very non-logic too)

    greetings /Carl
  2. Axe
    Axe avatar
    88 posts
    Member since:
    Feb 2007

    Posted 10 Jul 2008 Link to this post

    I was going to ask a similar question as Carl. I have implemented a custom FileBrowserContentProvider to browse files from a non-virtual path and although it works I can't really work out the difference between some members in the DirectoryItem class constructor and what effect they would have it different contexts as they seem to have different behaviors particularly in the ResolveDirectory Method (I will need to confirm that. I will check my code again and post another thread). If you could elaborate a bit more on the differences between location, fullPath & tag that would be great. In my ResolveDirectory method I pass string.Empty to all 3 and it still works but can have strange side effects in the visible path textbox. It seems to add the sub folders regardless of what I put in either of those 3.

    Regards
    Axe
  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Shaun Peet
    Shaun Peet avatar
    571 posts
    Member since:
    Aug 2004

    Posted 18 Aug 2008 Link to this post

    This is funny.  I just opened a bug report about the exact same thing.  Seems we're all working on the same problems!

    What I was doing for my implementation was trying to get a way for my users to know which folders were "uploadable" and which ones weren't.  I decided that the best way was to append the text " (upload)" next to the names of the folders (which should be obvious enough).  This caused all kinds of problems until I used the full path as the "Tag" instead of String.Empty.  But it all seems a little irrelevant in the end because the GenericFileLister control ignores the Tag anyway when sending arguments to the DeleteDirectory / DeleteFile methods.

    I've even done all the grunt work for Telerik and fixed their code for them:

    "Using Reflector, I've found exactly where this needs to be changed.  In Telerik.Web.UI.Widgets.FileManager:

    Private Sub FileLister_DeleteItem(ByVal sender As Object, ByVal e As FileListerDeleteEventArgs)
        If (e.SelectedItem.Type = FileItemType.Directory) Then
            Me.ContentProvider.DeleteDirectory(e.SelectedItem.Path)
        Else
            Me.ContentProvider.DeleteFile(e.SelectedItem.Path)
        End If
    End Sub
    

    This should probably become:

    Private Sub FileLister_DeleteItem(ByVal sender as ObjectByVal e As FileListerDeleteEventArgs)  
      Dim path As String = IIf(e.SelectedItem.Tag = String.Empty, e.SelectedItem.Path, e.SelectedItem.Tag)  
      If e.SelectedItem.Type = FileItemType.Directory Then 
        Me.ContentProvider.DeleteDirectory(path)  
      Else 
        Me.ContentProvider.DeleteFile(path)  
      End If 
    End Sub 

    "
    I've asked for a custom build with the fix but at the very least hopefully this will be changed for the Q2 2008 SP1 release.

    Here's my complete custom provider class, for those who are interested:

    Public Class MyFileSystemContentProvider     
        Inherits FileSystemContentProvider     
        
      Public Sub New(ByVal context As HttpContext, ByVal searchPatterns As String(), ByVal viewPaths As String(), ByVal uploadPaths As String(), ByVal deletePaths As String(), ByVal selectedUrl As StringByVal selectedItemTag As String)     
        MyBase.New(context, searchPatterns, viewPaths, uploadPaths, deletePaths, selectedUrl, selectedItemTag)     
        Me.ProcessPaths(MyBase.ViewPaths)     
        Me.ProcessPaths(MyBase.UploadPaths)     
            Me.ProcessPaths(MyBase.DeletePaths)     
            MyBase.SelectedUrl = FileBrowserContentProvider.RemoveProtocolNameAndServerName(Me.GetAbsolutePath(MyBase.SelectedUrl))     
        End Sub    
        
      Public Overrides Function StoreBitmap(ByVal bitmap As System.Drawing.Bitmap, ByVal url As StringByVal format As System.Drawing.Imaging.ImageFormat) As String    
        Dim quant As OctreeQuantizer = New OctreeQuantizer(128, 8)     
        Return MyBase.StoreBitmap(quant.Quantize(bitmap), url, format)     
      End Function    
        
      Public Overrides Function StoreFile(ByVal file As UploadedFile, ByVal path As StringByVal name As StringByVal ParamArray arguments As String()) As String    
        Dim relFolder As String = path     
        Dim relFull = IO.Path.Combine(relFolder, name)     
        Dim mapFolder As String = MyBase.Context.Server.MapPath(relFolder)     
        Dim mapFull As String = MyBase.Context.Server.MapPath(relFull)     
        If file.GetExtension = ".zip" Then    
          Dim lastValidFile As String = ""    
          Using ZIS As New ZipInputStream(file.InputStream)     
            Dim ZE As ZipEntry = ZIS.GetNextEntry     
            While Not IsNothing(ZE)     
              Dim strDir As String = IO.Path.GetDirectoryName(ZE.Name)     
              Dim strFil As String = IO.Path.GetFileName(ZE.Name)     
              If strDir.Length > 0 Then    
                IO.Directory.CreateDirectory(mapFolder & strDir)     
              End If    
              If strFil <> String.Empty Then    
                If IsValidFileTypeAfterUnZip(ZE.Name) Then    
                  DeleteFileIfAlreadyExists(mapFolder & ZE.Name)     
                  lastValidFile = relFolder & ZE.Name     
                  Using FS As FileStream = IO.File.Create(mapFolder & ZE.Name)     
                    Dim i As Integer = 2048     
                    Dim b As Byte() = New Byte(2048) {}     
                    While True    
                      i = ZIS.Read(b, 0, b.Length)     
                      If i > 0 Then    
                        FS.Write(b, 0, i)     
                      Else    
                        Exit While    
                      End If    
                    End While    
                  End Using     
                End If    
              End If    
              ZE = ZIS.GetNextEntry     
            End While    
          End Using     
          DeleteEmptyDirectoriesAfterZip(mapFolder)     
          Return lastValidFile     
        Else    
          DeleteFileIfAlreadyExists(mapFull)     
          file.SaveAs(mapFull)     
          Return relFull     
        End If    
        End Function    
        
      Private Sub DeleteFileIfAlreadyExists(ByVal mapFull As String)     
        If IO.File.Exists(mapFull) Then    
          IO.File.Delete(mapFull)     
        End If    
      End Sub    
        
      Private Sub DeleteEmptyDirectoriesAfterZip(ByVal mapFolder As String)     
        For Each Dir As String In IO.Directory.GetDirectories(mapFolder)     
          DeleteEmptyDirectoriesAfterZip(Dir)     
          If IO.Directory.GetFiles(Dir).Count = 0 And IO.Directory.GetDirectories(Dir).Count = 0 Then    
            IO.Directory.Delete(Dir)     
          End If    
        Next    
      End Sub    
        
      Private Function IsValidFileTypeAfterUnZip(ByVal fileName As StringAs Boolean    
        Dim strExt As String = Right(fileName, fileName.Length - fileName.LastIndexOf(".")).ToLower     
        If strExt = ".zip" Then    
          Return False    
        Else    
          For Each s As String In MyBase.SearchPatterns     
            s = Right(s, s.Length - s.LastIndexOf(".")).ToLower     
            If s = strExt Then Return True    
          Next    
        End If    
        Return False    
        End Function    
        
        Public Overrides Function ResolveRootDirectoryAsTree(ByVal path As StringAs DirectoryItem     
            Dim dir As New DirectoryInfo(MyBase.Context.Server.MapPath(path))     
            If Not dir.Exists Then    
                Return Nothing    
            End If    
            Dim virtualName As String = IIf((path = "/"), String.Empty, VirtualPathUtility.GetFileName(path))     
            Dim location As String = IIf((path = "/"), "/", VirtualPathUtility.AppendTrailingSlash(VirtualPathUtility.GetDirectory(path)))     
            Dim fullPath As String = path     
            Dim tag As String = path     
            Dim permissions As PathPermissions = Me.GetPermissions(fullPath)     
            Dim flag As Boolean = IIf(IsListMode, TrueMe.IsParentOf(fullPath, Me.SelectedUrl))     
            Dim flag2 As Boolean = Me.IsParentOf(fullPath, Me.SelectedUrl)     
            Dim directories As DirectoryItem() = IIf(flag, GetDirectories(dir, fullPath), New DirectoryItem(0 - 1) {})     
            Dim files As FileItem() = IIf(flag2, GetFiles(dir, permissions, (fullPath & "/")), New FileItem(0 - 1) {})     
            'If CanUpload(path) Then virtualName = "<span style=""color:green;"">" & virtualName & "</span>"      
            If CanUpload(path) Then virtualName += " (upload)"    
            If path.ToLower.Contains("secure/documents"Then virtualName += " (secure)"    
            Return New DirectoryItem(virtualName, location, fullPath, tag, permissions, files, directories)     
        End Function    
        
        Protected Function GetDirectories(ByVal directory As DirectoryInfo, ByVal parentPath As StringAs DirectoryItem()     
            Dim directories As DirectoryInfo() = directory.GetDirectories     
            Dim list As New ArrayList     
            Dim i As Integer    
            For i = 0 To directories.Length - 1     
                Dim info As DirectoryInfo = directories(i)     
                If Me.IsValid(info) Then    
                    list.Add(GetDirectory(info, (VirtualPathUtility.AppendTrailingSlash(parentPath) & info.Name)))     
                End If    
            Next i     
            Return DirectCast(list.ToArray(GetType(DirectoryItem)), DirectoryItem())     
        End Function    
        
        Public Function GetDirectory(ByVal dir As DirectoryInfo, ByVal fullPath As StringAs DirectoryItem     
            Dim virtualName As String = dir.Name     
            If CanUpload(fullPath) Then virtualName += " (upload)"    
            If fullPath.ToLower.Contains("secure/documents"Then virtualName += " (secure)"    
            Return GetDirectory(dir, virtualName, String.Empty, fullPath, fullPath)     
        End Function    
        
        Public Function GetDirectory(ByVal dir As DirectoryInfo, ByVal virtualName As StringByVal location As StringByVal fullPath As StringByVal tag As StringAs DirectoryItem     
            Dim permissions As PathPermissions = Me.GetPermissions(fullPath)     
            Dim flag As Boolean = IIf(IsListMode, TrueMe.IsParentOf(fullPath, Me.SelectedUrl))     
            Dim flag2 As Boolean = Me.IsParentOf(fullPath, Me.SelectedUrl)     
            Dim directories As DirectoryItem() = IIf(flag, GetDirectories(dir, fullPath), New DirectoryItem(0 - 1) {})     
            Return New DirectoryItem(virtualName, location, fullPath, tag, permissions, IIf(flag2, GetFiles(dir, permissions, (fullPath & "/")), New FileItem(0 - 1) {}), directories)     
        End Function    
        
        Protected Function GetFiles(ByVal directory As DirectoryInfo, ByVal permissions As PathPermissions, ByVal location As StringAs FileItem()     
            Dim list As New ArrayList     
            Dim hashtable As New Hashtable     
            Dim str As String    
            For Each str In Me.SearchPatterns     
                Dim info As FileInfo     
                For Each info In directory.GetFiles(str)     
                    If (Not hashtable.ContainsKey(info.FullName) AndAlso Me.IsValid(info)) Then    
                        hashtable.Add(info.FullName, String.Empty)     
                        Dim tag As String = IIf(Me.IsListMode, (location & info.Name), String.Empty)     
                        list.Add(New FileItem(info.Name, info.Extension, info.Length, String.Empty, String.Empty, tag, permissions))     
                    End If    
                Next    
            Next    
            Return DirectCast(list.ToArray(GetType(FileItem)), FileItem())     
        End Function    
        
        Public Overrides Function CreateDirectory(ByVal path As StringByVal name As StringAs String    
            If (name.IndexOfAny(IO.Path.GetInvalidPathChars) >= 0) Then    
                Return "InvalidCharactersInPath"    
            End If    
            Dim str As String = MyBase.Context.Server.MapPath((VirtualPathUtility.AppendTrailingSlash(path) & name))     
            Try    
                Directory.CreateDirectory(str)     
            Catch exception1 As UnauthorizedAccessException     
                Return "NoPermissionsToCreateFolder"    
            End Try    
            Return String.Empty     
        End Function    
        
        Public Overrides Function DeleteDirectory(ByVal path As StringAs String    
            path = path.Replace(" (upload)""").Replace(" (secure)""")     
            Dim str As String = MyBase.Context.Server.MapPath(path)     
            Try    
                If Directory.Exists(str) Then    
                    Directory.Delete(str, True)     
                End If    
            Catch exception1 As UnauthorizedAccessException     
                Return "NoPermissionsToDeleteFolder"    
            End Try    
            Return String.Empty     
        End Function    
        
        Public Overrides Function DeleteFile(ByVal path As StringAs String    
            path = path.Replace(" (upload)""").Replace(" (secure)""")     
            Dim str As String = MyBase.Context.Server.MapPath(path)     
            Try    
                If File.Exists(str) Then    
                    If ((File.GetAttributes(str) And FileAttributes.ReadOnly) = FileAttributes.ReadOnlyThen    
                        Return "FileReadOnly"    
                    End If    
                    File.Delete(str)     
                End If    
            Catch exception1 As UnauthorizedAccessException     
                Return "NoPermissionsToDeleteFile"    
            End Try    
            Return String.Empty     
        End Function    
        
        Public Function IsListMode() As Boolean    
            If Me.DisplayMode = FileBrowserDisplayMode.List Then Return True Else Return False    
        End Function    
        
    End Class    
     


    Shaun.
  5. Shaun Peet
    Shaun Peet avatar
    571 posts
    Member since:
    Aug 2004

    Posted 19 Aug 2008 Link to this post

    I've also learned that injecting *anything* into the virtualName of the DirectoryItem causes a whole slew of other problems - the biggest one being that the virtual name is part of the path returned to the editor when a file is selected (oops).  It also causes the image previewer to not work in the Image Manager, and I'm sure it throws off the file type settings for the other dialogs as well.

    Add 5 more votes for separating the tag from the virtualName.

    I would also like to propose another option.  Namely, adding another property to the DirectoryItem called "ImageUrl".  The default wold be the folder icon that is currently in use, but it would allow us to specify another icon instead if we want to give the end-user a visual clue as to the permissions of the folder.  In my case, a folder can be read-only or "uploadable", and may or may not be in a password-protected section of the site.  So I'll want to have four icons that represent the different possibilities.  That is essentially what I was trying to do by injecting html into the virtualName, but like I said, that breaks alot of other things with the dialog.

    Anybody else think that might be a good idea?  Telerik, would that even be possible with all the javascript serialization that is going on?

    Shaun.
Back to Top