Introduction
This article is the Part II of a previous work of mine titled "Managing virtual directories on multiple IIS sites and servers". The Virtual Directory Viewer tool described there has been improved with some new features. This article focuses on those new features (and only on them - so, taking a look at the Part I is strongly recommended). The main new feature makes the Viewer capable of accessing virtual directory data hosted in the IIS metabase in a read/write fashion (no more in a limited, read-only way). So, the Viewer actually became an Editor, but we still simply call it Virtual Directory Viewer (v2).
New features in the Virtual Directory Viewer v2
The new features introduced in this version of the Virtual Directory Viewer (v2) are:
- the ability to search a particular physical path (or path part) inside the set of data shown in the matrix, in order to find which virtual directory of which web site on which web server is currently pointing to it;
- the ability to edit a cell in the matrix, actually inducing a modification to the virtual directory configuration on the correct web server and web site the cell itself refers;
- the ability to inject (that is, simultaneously add) a new virtual directory definition to multiple web sites and web servers;
- the ability to modify a virtual directory definition simultaneously on multiple web sites and web servers;
- the ability to remove a virtual directory definition simultaneously from multiple web sites and web servers.
Buttons on the main form
The following table lists the buttons on the main form of the tool, and the corresponding features. For features already present in version 1, please refer to the Part I of this article.
Shape |
Function |
Description |
New in v2 |
|
Load data |
Retrieve data from specified web servers and web sites |
No |
|
Save |
Save current matrix on file |
No |
|
Load |
Load matrix from file |
No |
|
Edit |
Edit selected virtual directory cell |
Yes |
|
Inject |
Inject, modify, or remove a virtual directory |
Yes |
|
Find |
Find a string and highlight all the cells containing it |
Yes |
|
Select All |
Select all cells in the current matrix (to prepare a copy & paste operation) |
No |
|
Transpose |
Transpose the current matrix, by swapping row with columns |
No |
|
Apply filter |
Apply the filter condition |
No |
|
Web sites... |
Open the "Web Site Chooser" dialog box |
No |
How the editing feature has been implemented
As stated in the Introduction, the main difference between this version of the Virtual Directory Viewer tool and the previous one is the ability to edit the virtual directory configurations shown in the matrix. The editing feature is simply accomplished by code like this (see the btnOk_Click
event handler in VDirEdit.vb), that makes use of the System.DirectoryServices.DirectoryEntry
class:
Dim de As New DirectoryEntry(VDirMetabasePath)
Dim OldPhysPath As String = de.Properties("Path").Value()
Dim NewPhysPath As String = txtPhysPath.Text
de.Properties("Path")(0) = NewPhysPath
de.CommitChanges()
de.Dispose()
Of course, the need arises to store somewhere some information about the IIS metabase entry the user is going to edit. I decided to store these information as additional data directly related to each cell of the matrix. To achieve this goal, I created a simple class named VirtualDir
, hosting all the info I needed about the virtual directory the user is going to edit (let me call them "metadata", needed for manipulating each single DirectoryEntry
instance: the web server, the web site, the metabase path, the virtual directory logical name, and so on) and defined as follows:
Public Class VirtualDir
Public VDName As String = ""
Public VDPhysicalPath As String = ""
Public VDWebSiteAndServer As String = ""
Public VDMetabasePath As String = ""
Public Overrides Function ToString() As String
Return VDPhysicalPath
End Function
End Class
This class is then directly instantiated when creating the DataSet
and DataTable
that support the matrix visualization: some columns of the DataTable
are actually of type VirtualDir
(see the btnLoadData_Click
event handler in VDirViewer.vb):
VDirMatrix = New DataTable("VDirMatrix")
Dim col As New DataColumn("VDirName", Type.GetType("System.String"))
VDirMatrix.Columns.Add(col)
...
col = New DataColumn(dr("WebSiteName"), Type.GetType("VDirViewer.VirtualDir"))
col.DefaultValue = New VirtualDir
VDirMatrix.Columns.Add(col)
...
The ToString()
method's override I did in the VirtualDir
class guarantees some control about what the DataGrid
will display in the corresponding cell, when the DataGrid
itself is bound to the underlying DataTable
.
The "metadata" I added behind each cell this way, need (of course!) to be persisted and retrieved when the user clicks on the Save and Load buttons. To accomplish this task, I created a class named VDirDataSet
to be used instead of the standard DataSet
class. VDirDataSet
is a class derived from System.Data.DataSet
to overload the WriteXml
and ReadXml
methods in order to achieve a sort of custom serialization/deserialization of customized DataSet
columns (see the code in VDirDataSet.vb). The deserialization process (ReadXml
methods) is obviously capable of recreating a DataTable
containing some columns of type VirtualDir
(compare the btnLoadData_Click
procedure in VDirViewer.vb with the ReadXml
procedure in VDirDataSet.vb).
How the search functionality has been implemented
The search functionality's goal is to provide a quick way to highlight those cells in the matrix that contain a virtual directory physical path matching with the given search string. To implement this kind of highlighting, I decided to create a specialized version of the DataGridTextBoxColumn
class, capable of rendering itself using a different backcolor when the search string is found inside its content. So, the class I created contains the logic of searching and highlighting (see DataGridColoredTextBoxColumn.vb), and the execution of a Find operation actually becomes just a matter of creating a proper DataGridTableStyle
and applying it to the shown DataGrid
:
Private Sub cmdFind_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles cmdFind.Click
If dgMatrix.DataSource Is Nothing Then Exit Sub
SearchString = InputBox("Enter the string you want to find:", _
"Find", SearchString)
Try
dgMatrix.TableStyles.RemoveAt(0)
Catch ex As Exception
End Try
dgMatrix.TableStyles.Add(CreateGridStyle((SearchString <> "")))
End Sub
Private Function CreateGridStyle(Optional ByVal Search _
As Boolean = True) As DataGridTableStyle
Dim ColWidth As New NameValueCollection
If Not CurrentTableStyle Is Nothing Then
Dim gcs As DataGridColumnStyle
For Each gcs In CurrentTableStyle.GridColumnStyles
ColWidth(gcs.MappingName) = gcs.Width
Next
End If
Dim dt As DataTable = CType(dgMatrix.DataSource, DataView).Table
Dim GridStyle = New DataGridTableStyle
GridStyle.MappingName = dt.TableName
Dim nameColumnStyle As DataGridTextBoxColumn
Dim dc As DataColumn
For Each dc In dt.Columns
If Search Then
nameColumnStyle = New DataGridColoredTextBoxColumn
Else
nameColumnStyle = New DataGridTextBoxColumn
End If
nameColumnStyle.MappingName = dc.ColumnName
nameColumnStyle.HeaderText = dc.ColumnName
If Not ColWidth(dc.ColumnName) Is Nothing Then
nameColumnStyle.Width = ColWidth(dc.ColumnName)
End If
GridStyle.GridColumnStyles.Add(nameColumnStyle)
Next
CurrentTableStyle = GridStyle
Return GridStyle
End Function
Points of interest
I think the major points of interest in this implementation are:
- the use of
DataTable
s with columns based on custom types;
- modified serialization/deserialization of
DataSet
s to support those custom types in columns;
- the use of
DataGridTableStyle
s and custom DataGridTextBoxColumn
s to provide a personalized rendering of data in the DataGrid
.