65.9K
CodeProject is changing. Read more.
Home

WebOpenFileDialog

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.75/5 (3 votes)

Jun 22, 2017

CPOL

6 min read

viewsIcon

6553

downloadIcon

272

This article presents an OpenFileDialog for the Web

1. Abstract Table of Contents

This short article presents a class that provides a user with the ability to choose a file from a list of files found at a web URL. It also allows the traversal of the directory structure of a web site.

 

2. Background Table of Contents

During a recent project, I found that I needed the functionality of OpenFileDialog [^], but for web directories. In searching the web, I found some tools that would perform this function, but none that I could drop into an application, especially an application developed with the .Net Framework Version 3.5.

Because it appeared that the resuling tool might have usefulness outside my original project, I present it here.

A note on typography

In the following discussions, properties that are specified by the developer are displayed in

  • bold black
  • bold red are required
  • red are required under some circumstances

Variables, used internally by the software are displayed in italicized text.

3. WebOpenFileDialog Table of Contents

WebOpenFileDialog is a tool that is derived from the .NET Form [^] class and provides the ability to select a file from files on a web site. It incororates its own GUI that, once successfully initialized, allows a user to select a node from a TreeView [^], and indicate (through the OK button) that the selected node is the file of choice.

3.1. Properties Table of Contents

The following properties may be specified.

PropertyGet/SetDefaultDescription
Anonymous_FTPSetfalseIf true, causes an attempt to establish an anonymous FTP connection; otherwise, a User_Name and Password must be supplied
File_NameGetNoneIf, upon return, the return value is DialogResult.OK, contains the fully qualified file name of the file chosen by the user; otherwise, if, upon return, the return value is DialogResult.Cancel, contains an empty string.
FTP_URLSetNoneURL of the FTP web site from which the initial directory source will be retrieved (i.e., the topmost directory whose listing is to be retrieved). Akin to "InitialDirectory" in OpenFileDialog. The supplied value must adhere to the FTP schema (i.e., it must begin with either 'ftp://' or 'ftps://').
Pass_WordSetNoneThe FTP password for the site specified in FTP_URL. If Anonymous_FTP is true, this property may be the empty string or the anonymous FTP password for the site. If Anonymous_FTP is false, the FTP password for the site must be supplied.
Perform_PingSettrueIf true, causes an attempt to establish a connection with the web site using Ping; otherwise, no Ping is executed.
Show_HiddenSetfalseIf true, the directory entries that begin with a period will be displayed; otherwise, directory entries that begin with a period will be ignored.
User_NameSetNoneThe FTP username for the site specified in FTP_URL. If Anonymous_FTP is true, this property may be the empty string or the anonymous FTP username for the site. If Anonymous_FTP is false, the FTP username for the site must be supplied.
Window_TitleSetNoneA title to appear in the title area of the dialog. If not supplied, the title "Web Open File Dialog" will be used.

3.2. Invocation Table of Contents

using System;
using System.Text;
using System.Windows.Forms;

using WOFD = WebOpenFileDialog.WebOpenFileDialog;
:
:
    WOFD wofd = new WOFD 
        {
        Anonymous_FTP = <(true|false)>,
        FTP_URL = <URL of the FTP web site topmost node>,
        User_Name = <username for the FTP web site>,
        Pass_Word = <password for the FTP web site>,
        Perform_Ping = <(true|false)>,
        Show_Hidden = <(true|false)>,
        Window_Title = <title for the WebOpenFileDialog form>
        };

    if ( wofd.ShowDialog ( ) == DialogResult.OK )
        {
        filename_TextBox.Text = wofd.File_Name;
        }

4. Implementation Table of Contents

4.1. directories_and_files_to_treeview Table of Contents

The method that actually retrieves and expands FTP directory listings is called directories_and_files_to_treeview. Its signature is

bool directories_and_files_to_treeview (     
                            string             ftp_url, 
                            NetworkCredential  credential,
                        ref TreeView           tree_view, 
                        ref string             error_message )

Prior to processing ftp_url, the method determines if ftp_url is the root node of an existing TreeView. If it is, a new TreeNode [^] is created; otherwise a search is made for the node with the name ftp_url. Either case establishes the root note for the current invocation of directories_and_files_to_treeview.

    ftp_url = ftp_url.Replace ( @"\", "/" );

    if ( tree_view.Nodes.Count == 0 )
        {
        tree_node = new TreeNode ( ftp_url )
            {
            Tag = "DIR"
            };
        tree_view.Nodes.Add ( tree_node );
        root_node = tree_view.Nodes [ 0 ];
        }
    else 
        {
        root_node = find_tree_node ( tree_view.Nodes [ 0 ], 
                                     ftp_url ) ;
        if ( root_node == null )
            {
            error_message = String.Format (
                "Unable to locate {0}\n" +
                "in existing directory tree",
                ftp_url );
            successful = false;
            return ( successful );
            }
        }

Note that at each invocation of directories_and_files_to_treeview, only the current directory (specified in ftp_url) will be processed. Multiple invocations are required to traverse the directory tree below ftp_url. This restriction is imposed so that a large amount of network traffic is avoided based on the assumption that only a limited number of subdirectories need to be visited.

Retrieving a web site directory is accomplished by using the FtpWebRequest [^] class returned by WebRequest.Create [^] cast to a FtpWebRequest. To obtain a directory of files at a web site, the request Method is set to WebRequestMethods.Ftp.ListDirectoryDetails [^]. This protocol retrieves a detailed listing of the files on an FTP server. The initializing code may take on the following appearance:

    FtpWebRequest   request;

    ftp_uri = new Uri ( ftp_url );
                            // retrieve directory details
    request = 
        ( FtpWebRequest ) WebRequest.Create ( ftp_uri );
    request.Credentials = credential;
                            // use FTP LIST to retrieve 
                            // all directory entries 
    request.Method = WebRequestMethods.
                     Ftp.ListDirectoryDetails;
    using ( WebResponse response = request.
                                   GetResponse ( ) )
        {
        using ( StreamReader stream_reader = 
                             new StreamReader ( 
                                 response.
                                 GetResponseStream ( ) ) )
            {
                            // process each line in the 
                            // directory list
            while ( stream_reader.Peek ( ) > 0 )
                {
                string  line = stream_reader.ReadLine ( );
                :
                :

The directory list is composed of lines whose first character distinguishes one entry type from another. Unix file types [^] describes the types of files found in the Unix operating system. An example of a directory listing is:

drwx--x--x 24 amvetspost amvetspost  4096 May  1 09:31 ..
drwx------  2 amvetspost amvetspost  4096 Jul 14  2016 .HttpRequest
drwx------  4 amvetspost amvetspost  4096 Jul 14  2016 .MirrorSearch
-rw-r--r--  1 amvetspost amvetspost   100 May 22  2016 .bash_logout
-rw-r--r--  1 amvetspost amvetspost   230 May 22  2016 .bash_profile
-rw-r--r--  1 amvetspost amvetspost   176 Jul 27  2015 .bash_profile.rpmnew
-rw-r--r--  1 amvetspost amvetspost   124 Sep 22  2015 .bashrc
drwxrwx--x  5 amvetspost amvetspost  4096 Jul 14  2016 .cagefs
drwxr-xr-x  2 amvetspost amvetspost  4096 Apr 26 15:17 .cl.selector
-rw-------  1 amvetspost amvetspost     0 Jul 10  2016 .contactemail
drwxr-xr-x  3 amvetspost amvetspost  4096 Jul 14  2016 .cpan
drwx------  5 amvetspost amvetspost  4096 Apr 29 08:36 .cpanel
drwx------  3 amvetspost amvetspost  4096 Jul 14  2016 .cpcpan
drwx------  4 amvetspost amvetspost  4096 Aug 17  2016 .cphorde
drwx------  4 amvetspost amvetspost  4096 Jul 14  2016 .cpobjcache
-rw-r--r--  1 amvetspost amvetspost   145 Jul 10  2016 .gemrc
drwxr-x---  2 amvetspost 99          4096 Jul 10  2016 .htpasswds
-rw-------  1 amvetspost amvetspost   650 Apr 29 08:36 .lastlogin
-rw-r--r--  1 amvetspost amvetspost    33 May 22  2016 .md5sum
drwxr-xr-x  2 0          0           4096 Jun 19 12:03 .mysql_backup
drwx------  2 amvetspost amvetspost  4096 Apr 26 15:58 .subaccounts
drwx------  2 amvetspost amvetspost  4096 Jul 15  2016 .trash
-rw-r--r--  1 amvetspost amvetspost   658 Mar 25  2016 .zshrc
drwxr-xr-x  2 amvetspost amvetspost  4096 Jun 13 08:51 AmVetsData
lrwxrwxrwx  1 amvetspost amvetspost    39 Jul 10  2016 access-logs -> /usr/local/apache/domlogs/amvetspost292
drwxr-xr-x  2 amvetspost amvetspost  4096 Aug 17  2016 cache
drwxr-x---  2 amvetspost 12          4096 Jul 10  2016 etc
drwx------  2 amvetspost amvetspost  4096 Jun 14 05:20 logs
drwxr-x---  8 amvetspost amvetspost  4096 Jul 14  2016 mail

The first character of each line determines if it will be processed. For our purposes, only files, whose first character is the hyphen (-), and directories, whose first character is the lowercase letter 'd', will be retained. All others will be ignored.

If the directory entry name (last column in the directory listing) starts with a period, the entry is considered to be a "hidden" entry. Unless the Show_Hidden property is set true, hidden entries will be ignored. If the first character of a directory listing line is 'd' and the directory entry name ends with a period, then the entry will be ignored. This latter case eliminates the directories '.' (current directory) and '..' (parent directory).

With these first character definitions, the code takes on the following form:

                char    first_ch = ( char ) 0;
                int     index = 0;
                string  name = String.Empty;
                string  type = String.Empty;

                first_ch = line [ 0 ];
                if ( first_ch == 'd' )
                    {
                    if ( line.EndsWith ( "." ) )
                        {
                        continue;   // ignore . and ..
                        }
                    type = "DIR";
                    }
                else if ( first_ch == '-' ) 
                    {
                    type = "FILE";
                    }
                else 
                    {
                    continue;       // ignore all others
                    }

                index = line.LastIndexOf ( ' ' );
                if ( index < 0 )
                    {
                    continue;
                    }

                name = line.Substring ( index ).Trim ( );
                if ( name.StartsWith ( "." ) )
                    {
                    if ( !Show_Hidden )
                        {
                        continue;
                        }
                    }

                tree_node = new TreeNode ( name )
                    {
                    Tag = type
                    };
                if ( type.Equals ( "DIR" ) )
                    {
                    tree_node.Nodes.Add ( 
                        new TreeNode ( "EMPTY" )
                            {
                            Tag = "EMPTY"
                            } );
                    }

                root_node.Nodes.Add ( tree_node );
                }

Each non-ignored directory entry name in the directory listing is assigned to a TreeNode with a type of either "DIR" or "FILE" stored in its Tag. If a new directory node (DIR) is being added, it is given a child node of type "EMPTY" before being added to the TreeView. This empty node causes the TreeView control to place a plus sign (+) before the node, thereby implying that a subtree exists. Note that the expansion of a TreeNode only occurs when that TreeNode is processed as a root (i.e., passed as ftp_url during an invocation of directories_and_files_to_treeview).

4.2. find_tree_node Table of Contents

Of interest may be the TreeNode search method. Its contents are:

TreeNode find_tree_node ( TreeNode root, 
                          string   name_to_find ) 
    {
    Stack < TreeNode >  stack = new Stack < TreeNode > ( );
    bool                no_strip = false;

    stack.Push ( root );
    name_to_find = name_to_find.Replace ( @"\", "/" );
    no_strip = name_to_find.EndsWith ( "/" );
    while ( stack.Count > 0 )
        {
        StringBuilder   name = new StringBuilder ( );
        TreeNode        node = ( TreeNode ) stack.Pop ( );
        
        name.AppendFormat ( "{0}/{1}",
                            node.FullPath,
                            node.Name );
        name.Replace ( @"\", "/" );
        if ( !no_strip )
            {
            while ( name.ToString ( ).EndsWith ( "/" ) )
                {
                name.Length--;
                }
            }

        if ( name.ToString ( ).Equals ( name_to_find ) )
            {
            return ( node );
            }

        foreach ( TreeNode child in node.Nodes )
            {
            if ( child != null )
                {
                stack.Push( child );
                }
            }
        }

    return ( null );
    }

Given a root node from which to search and the name of a node for which to search, find_tree_node finds a node in the subtree of root that has the name of name_to_find. If the search is successful, returns the TreeNode that contains the name; otherwise, returns null.

I considered using a recursive search but the iterative approach appears to be simple. As a result, the simple beat out the elegant!

5. Using WebOpenFileDialog Table of Contents

As constructed, WebOpenFileDialog is a project containing the WebOpenFileDialog class derived from the Form class. It has the namespace WebOpenFileDialog. To utilize this class in Microsoft Visual Studio [^], simply copy the WebOpenFileDialog project into a containg solution.

6. Demonstration Table of Contents

A demonstration project has been included in the downloads. Upon execution it displayes:

When a file has been chosen, as in the first figure, and the OK button has been clicked, the fully qualified path of the chosen filename appears in the Filename TextBox.

7. References Table of Contents

8. Development Environment Table of Contents

The WebOpenFileDialog was developed in the following environment:

Microsoft Windows 7 Professional Service Pack 1
Microsoft Visual Studio 2008 Professional
Microsoft .Net Framework Version 3.5 SP1
Microsoft Visual C# 2008

9. History Table of Contents

06/27/2017     Original article
WebOpenFileDialog - CodeProject