A "Make Virtual Directory 2.0 Here"
Windows Explorer Context Menu Utility

by Peter A. Bromberg, Ph.D.

Peter Bromberg

A couple of years ago I put together an ASP.NET 1.1 "Make Virtual Directory Here" Windows Explorer utility which has been pretty well received. (Actually I gave the code to Dr. Dotnetsky and he went ahead and submitted it, but I'll forgive him). You can find the original here.



Now that I am using ASP.NET 2.0 more and more, it's been in the back of my mind to update this to ASP.NET 2.0. Since it's a Windows Explorer Context Menu Folder Shell Extension, a new version only needs to have:

1) a new Registry entry with a different menu item name and
2) Additional code that runs ASPNET_REGIIS.EXE -sn on the new Vroot from the .NET Framework 2.0 Folder so that it gets converted to 2.0.

Today I "bit the bullet" and wrote the code. Fortunately, it didn't take long because 90% of it was already written for the ASP.NET 1.1 version. So instead of boring you with old code, I'll just show the "new code".

For starters, let me share something I've discovered now that I've been developing seriously with the .NET Framework since before 2001: As a developer, if you truly take an object-oriented approach to your programming career, programming gets easier and easier as time goes on.

Let me rephrase that: If you have learned to program effectively, programming should get easier all the time as you become more valuable to your employer (which could be you and your own business). This is because you have learned to wrap functionality that you expect to use again into well-designed class libraries with a well-thought-out namespace scheme.

Stuff that I write for myself for re-use starts out with the PAB namepace (my initials), then .Data, or .Utils, or.Whatever is the descriptive name for the next level down in the hierarchy. So the IIS VDir class was already written and tested, and can be used in other ways. For example, it could be added to a Windows MSI Installer project as a post-install step. The calling class for this particular implementation is the console app that calls the pre-written utility class and then adds the additional functionality to make the Process class call to ASPNET_REGIIS.EXE. A couple of months from now, I may use it for something else. If I do, it likely won't need to be changed, because I originally wrote it withe the OOP / re-usability idea in mind.

Here's the new code that calls the revised original "CreateVDir" method in my class:

using System;

using System.DirectoryServices;

namespace PAB.Utils

{   

    public class MkVdir

    {

        public MkVdir()

        {           

        }

        public static string CreateVDir20(string  WebSite, string VDirName, string Path, bool  RootDir, bool chkRead,bool chkWrite, bool chkExecute, bool chkScript, bool chkAuth,int webSiteNum, string serverName)

        {

            string sRet=String.Empty;

            System.DirectoryServices.DirectoryEntry IISSchema;

            System.DirectoryServices.DirectoryEntry IISAdmin;

            System.DirectoryServices.DirectoryEntry VDir;

            bool IISUnderNT;

            IISSchema = new  System.DirectoryServices.DirectoryEntry("IIS://" +serverName +"/Schema/AppIsolated");

            if  (IISSchema.Properties["Syntax"].Value.ToString().ToUpper() == "BOOLEAN")

                IISUnderNT = true;

            else

                IISUnderNT = false;       

            IISAdmin = new  System.DirectoryServices.DirectoryEntry("IIS://localhost/W3SVC/" + webSiteNum + "/Root");

            if (!RootDir)

            {

                foreach(System.DirectoryServices.DirectoryEntry v in IISAdmin.Children)

                {

                    if (v.Name == VDirName)

                    {

                        // Delete the specified virtual directory if it already exists

                        try

                        {

                            IISAdmin.Invoke("Delete", new string [] { v.SchemaClassName, VDirName });

                            IISAdmin.CommitChanges();

                        }

                        catch(Exception ex)

                        {

                            sRet+=ex.Message;

                        }

                    }

                }

            }   

 

            //

            // Create the virtual directory

            //

            if (!RootDir)

            {

                VDir = IISAdmin.Children.Add(VDirName, "IIsWebVirtualDir");

            }

            else

            {

                VDir = IISAdmin;

            }

 

            //

            // Setup the VDir

            //

            VDir.Properties["AccessRead"][0] = chkRead;

            VDir.Properties["AccessExecute"][0] = chkExecute;

            VDir.Properties["AccessWrite"][0] = chkWrite;

            VDir.Properties["AccessScript"][0] = chkScript;

            VDir.Properties["AuthNTLM"][0] = chkAuth;

            VDir.Properties["EnableDefaultDoc"][0] = true;

            VDir.Properties["EnableDirBrowsing"][0] = false;

            VDir.Properties["DefaultDoc"][0] = true;

            VDir.Properties["Path"][0] = Path;

            VDir.Properties["AppFriendlyName"][0]=VDirName;

            //

            // NT doesn't support this property

            //

            if (!IISUnderNT)

            {

                VDir.Properties["AspEnableParentPaths"][0] = true;

            }

            VDir.CommitChanges();

            if (IISUnderNT)

            {

                VDir.Invoke("AppCreate", false);

            }

            else

            {

                VDir.Invoke("AppCreate", 1);

            }

            // Register as ASP.NET 2.0 vdir

 

            string frameworkVersion = System.Configuration.ConfigurationManager.AppSettings["frameworkVersion"];

            string winPath = Environment.GetEnvironmentVariable("windir");

 

            string fullPath = winPath + @"\Microsoft.NET\Framework\" + frameworkVersion + @"\aspnet_regiis ";

 

            string args = " -sn " + "W3SVC/" + webSiteNum + "/root/" + VDirName  ;

            System.Diagnostics.Process _p = new System.Diagnostics.Process();

            _p.StartInfo.FileName = fullPath;

            _p.StartInfo.Arguments = args;

            _p.StartInfo.UseShellExecute = false;

            _p.StartInfo.RedirectStandardOutput = true;

            _p.Start();

            sRet+= "VRoot " +VDirName + " created!";

            return sRet;

        }

    }

}

You can easily see the only code I really had to add near the end, right after the "// Register as ASP.NET 2.0 vdir" comment line.

Here is the "Front end" code for the Console Exe app that sets the Registry entry, gets the current folder you want to make into an IIS Vroot, and calls the code:

using System;

using System.DirectoryServices ;

using System.IO;

using Microsoft.Win32;

using System.Windows.Forms;

 

namespace PAB.Utils

{

 /// <summary>

 /// Summary description for Class1.

 /// </summary>

 class MakeVdir

 {

/// <summary>

/// The main entry point for the application.

/// </summary>

[STAThread]

static void Main(string[] args)

{

string appLoc=String.Empty;

try

{

appLoc=Environment.CurrentDirectory +"\\" + System.Reflection .Assembly.GetExecutingAssembly().GetName().Name.ToString()+".Exe";

RegistryKey tstKey=Registry.ClassesRoot.OpenSubKey(@"Folder\shell\MakeVRoot20Here");

if(tstKey!=null)tstKey.Close();

if (tstKey==null)

{

RegistryKey theKey = Registry.ClassesRoot;

RegistryKey otherKey = theKey.CreateSubKey(@"Folder\shell\MakeVRoot20Here");

RegistryKey newKey = otherKey.CreateSubKey("command");

newKey.SetValue("", "\""+ appLoc + "\" \"%1\"");

newKey.Close();

}

}

catch(Exception ex)

{

MessageBox.Show(ex.Message);

return;

}

 

DirectoryInfo d=null;

if(args.Length >0)

{

d =new DirectoryInfo(args[0]);

}

else

{

d = new DirectoryInfo(Environment.CurrentDirectory);

}

string result=String.Empty;

 

try

{

result= MkVdir.CreateVDir20("localhost",d.Name,d.FullName,false,true,false,false,true,true, 1, "localhost");

}

catch(Exception ex)

 

{

result=ex.Message;

}

MessageBox.Show(result);

 

 

}

 }

}

 

Now what does this little utility buy you? Well, a lot of convenience, really. Let's say you are writing a class library. And you've decided you need an IIS web project in the solution (NOT a "fileSystem" based web site). All you need to do is open windows explorer, make a new folder under your Solution root, right click the folder and choose "Make Vroot20 Here" (or alt-M, if you are really lazy!). Presto! Without ever leaving Visual Studio.NET, you can add a new IIS (the real thing) web site to your solution, because the Virtual Directory is already created and its already configured for ASP.NET 2.0!. Enjoy the code.

When you run the program for the first time, it will enter the Registry entries for the context menu. So, be sure you've got a release build exactly where you want to keep it before you run it.

And, don't forget: Reusability of code may not be specified as one of the three pillars of OOP, but its one of the most important ones. Didn't Yogi Berra say that?

Download the Visual Studio 2005 Solution that accompanies this article


Peter Bromberg is a C# MVP, MCP, and .NET consultant who has worked in the banking and financial industry for 20 years. He has architected and developed web - based corporate distributed application solutions since 1995, and focuses exclusively on the .NET Platform.
Article Discussion: