如何确定"IIsWebDirectory"或"IIsWebVirtualDir"是否为ASP.NET应用程序?

Mic*_*ern 5 c# asp.net iis directoryservices

我目前正在编写一个C#asp.net应用程序来连接到IIS服务器并查询虚拟目录/ web目录信息.

我能够确定我应该处理的两种类型是"IIsWebDirectory"和"IIsWebVirtualDir".

如何确定它们是否已配置为C#中的"应用程序"?

您还可以在此处此处查看我在C#和IIS中的冒险经历

UPDATE

@Kev - 我在你的答案中提取了信息并开发了以下简单的解决方案,以检查AppFriendlyName是否未设置为"默认应用程序"

private void CheckIfApp(DirectoryEntry de)
{
    if(de.SchemaClassName.Equals("IIsWebDirectory") || de.SchemaClassName.Equals("IIsWebVirtualDir"))
    {
        if (de.Properties["AppFriendlyName"].Value != null)
        {
            string friendlyName = de.Properties["AppFriendlyName"].Value.ToString();

            if (!friendlyName.Equals("Default Application"))
            {
                //do something...
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Kev*_*Kev 8

有三种方法可以解决这个问题:

  • 普通的旧System.DirectoryServices
  • 解析IIS metabase.xml文件
  • System.DirectoryServices和一些COM互操作

普通的旧System.DirectoryServices

确定一个IIsWebDirectory或一个IIsWebVirtualDir IIS管理对象是否配置为System.DirectoryServices单独使用的应用程序有时可能是一个非显而易见的业务,因为配置数据库属性继承.

例如,当您创建"应用程序"时,通常会在IIsWebDirectory或配置IIsWebVirtualDir数据库管理对象上设置三个属性-

AppFriendlyName
AppIsolated
AppRoot
Run Code Online (Sandbox Code Playgroud)

在元数据库中,您会看到如下内容:

<!-- This is an application -->
<IIsWebVirtualDir   Location ="/LM/W3SVC/1/ROOT/MyApp"
    AccessFlags="AccessRead | AccessScript"
    AppFriendlyName="MyAppKev"
    AppIsolated="2"
    AppRoot="/LM/W3SVC/1/Root/MyApp"    
    >
</IIsWebVirtualDir>
Run Code Online (Sandbox Code Playgroud)

现在您会认为它就像检查这三个属性的存在一样简单,特别是AppIsolated属性,因为这是用于指示应用程序隔离类型的属性(进程内[0],进程外[ 1]或汇集[2]) - 每个应用程序都需要此属性.作为旁注,在运行IIS6的服务器上,您只能看到AppIsolated=0|1IIS是否在IIS5兼容模式下运行.创建自己的应用程序时,应始终设置AppIsolated=2哪个站点或应用程序将在其中一个应用程序池(w3wp.exe)中运行.

无论如何......由于配置数据库属性继承,检查上面列出的三个属性中的任何一个都不能保证您正在检查的对象实际上是一个应用程序 - 无论是使用ADSI,WMI还是DirectoryServicesAPI.即使您正在检查的对象只是一个虚拟目录(而不是应用程序),您仍将获得返回的值,因为它们将从父应用程序继承.

例如,如果/MyVdir是位于默认网站中的虚拟目录(不是应用程序),您仍会看到一个值AppIsolated,这是因为它是从中继承的IIS://Localhost/w3svc/1/root).这同样适用于AppFriendlyNameAppRoot属性.

我在这里采用的方法是将DirectoryEntry.Path属性与AppRoot目标管理对象上的属性进行比较.AppRoot是一个属性,指示特定应用程序的根目录.如果您正在检查站点的元数据库层次结构中的IIS管理对象,并且您需要知道其应用程序的根源,这可能很方便.

所以,我说有一个应用程序位于:

IIS://Localhost/w3svc/1/root/MyApp
Run Code Online (Sandbox Code Playgroud)

...并说我们有一个例子DirectoryEntry:

DirectoryEntry de = new DirectoryEntry("IIS://Localhost/w3svc/1/root/MyApp");
Run Code Online (Sandbox Code Playgroud)

de.Path属性将被设置为IIS://Localhost/w3svc/1/root/MyApp,在AppRoot管理对象属性de.Properties["AppRoot"].Value,将被设置为/LM/W3SVC/1/Root/MyApp.您需要做的就是去除前导IIS://Localhost/LM字符串,并进行不区分大小写的字符串比较.如果匹配则该路径上的对象是应用程序.

解析IIS metabase.xml文件

还有另一种方法我过去曾用过死服务器重建工作,我们有配置数据库文件,我们知道我们创建的vdirs和应用程序的数据库表,而不是其他 - 服务器有1200个网站弹出之前的众多虚拟目录和应用程序.基本上我把整个metabase.xml文件加载到了XMLDocument.然后我使用XPath来查找AppIsolated属性的存在,其中Locationattibute匹配我感兴趣的路径.

这是代码的摘录,应该为您提供该想法的一般要点:

private XmlNamespaceManager _nsm = 
        new XmlNamespaceManager(new NameTable());
private XmlDocument _doc = new XmlDocument();
_doc.Load(@"c:\windows\system32\inetsrv\metabase.xml");
_nsm.AddNamespace("iis", "urn:microsoft-catalog:XML_Metabase_V64_0");

// lmPath could be build from the DirectoryEntry.Path property
string lmPath = "/lm/w3svc/1/root/myapp";

// Try as an IIsWebDirectory object
string iisWebDirectoryXPath = 
    String.Format(@"//iis:IIsWebDirectory[translate(@Location, 
            'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
            'abcdefghijklmnopqrstuvwxyz') = '{0}']",
            lmPath);

mbNode = _doc.DocumentElement.SelectSingleNode(iisWebDirectoryXPath, _nsm);

if(mbNode != null)
{
    // We found an IIsWebDirectory - is it an application though?
    if (mbNode.Attributes["AppIsolated"] != null)
    {
        // IIsWebDirectory is an Application
    }
}
else
{
    // Is our object an IIsWebVirtualDir?
    string iisWebVirtualDirectoryXPath = 
        String.Format(@"//iis:IIsWebVirtualDir[translate(@Location, 
                'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 
                'abcdefghijklmnopqrstuvwxyz') = '{0}']",
                lmPath);

    mbNode = _doc.DocumentElement
            .SelectSingleNode(iisWebVirtualDirectoryXPath, _nsm);

    if (mbNode != null)
    {
        // Yes it's an IIsWebVirtualDir
        if (mbNode.Attributes["Path"] != null)
        {
            if(mbNode.Attributes["AppIsolated"] != null)
            {
                // And it's an application
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

metabase.xml只要应用程序/虚拟目录没有很高的转换率,解析原始文件就可以正常工作.这是因为内存中的元数据库更新不会metabase.xml立即刷新到文件中.我不建议这样做,我只是出于系统恢复的目的这样才解决问题.

System.DirectoryServices和一些COM互操作

最后还有第三种方式(可能是最简单的方法),如果您的开发PC没有运行IIS6/Windows 2003,您可能无法正常测试(我没有可用的XP机器来验证它是否适用于IIS 5.1 ).您所做的是添加对名为"Active DS IIS Extension Dll"(%systemroot%\system32\inetsrv\iisext.dll)的COM库的引用,它在Visual Studio的"添加引用"对话框的COM选项卡上列出.添加此引用时,Visual Studio还将自动解析并引用依赖项"Active DS Type Library"(%systemroot%\system32\activeds.tlb).在您的解决方案参考文件夹中,您会看到它们被列为"ActiveDS"和"IISExt".

使用"Active DS IIS Extension"库,我们可以通过执行以下操作来测试特定路径上的IIS管理对象是否实际上是IIS应用程序:

using (DirectoryEntry de = 
        new DirectoryEntry("IIS://Localhost/w3svc/1/root/MyApp"))
{
    // Cast our native underlying object to the correct interface
    IISExt.IISApp2 app = (IISExt.IISApp2)de.NativeObject;
    int status = app.AppGetStatus2();

    switch(status)
    {
        case 0:
            Console.WriteLine("It's an app but it's stopped.");
            break;

        case 1:
            Console.WriteLine("It's an app and it's running.");
            break;

        case 2:
            Console.WriteLine("No application found here.");
            break;
    }

}
Run Code Online (Sandbox Code Playgroud)

使用WMI还有第四种方法,但我只是在水中蘸了一些相当简单的IIS/App Pool管理任务.