5

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

我能够确定我应该处理的两种类型是“IIsWebDirectory”和“IIsWebVirtualDir”。

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

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

更新

@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...
            }
        }
    }
}
4

1 回答 1

8

您可以通过三种方式解决此问题:

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

普通的旧 System.DirectoryServices

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

例如,当您创建“应用程序”时,通常会在元数据库管理对象IIsWebDirectoryIIsWebVirtualDir元数据库管理对象上设置三个属性 -

AppFriendlyName
AppIsolated
AppRoot

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

<!-- 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>

现在你会认为它就像检查这三个属性的存在一样简单,特别是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

...并说我们有一个实例DirectoryEntry

DirectoryEntry de = new DirectoryEntry("IIS://Localhost/w3svc/1/root/MyApp");

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

解析 IIS metabase.xml 文件

我过去使用另一种方法作为死服务器重建工作的一部分,我们有元数据库文件,一个包含 vdirs 和我们知道我们创建的应用程序的数据库表,没有太多其他方法 - 服务器有 1200 个网站以及弹出之前的大量虚拟目录和应用程序。基本上我将整个metabase.xml文件加载到XMLDocument. 然后,我使用 XPath 来查找与我感兴趣的路径匹配的AppIsolated属性是否存在。Location

这是一段代码,应该可以为您提供大致的思路:

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
            }
        }
    }
}

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 类型库”( %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;
    }

}

还有第四种使用 WMI 的方法,但我只是为了一些相当简单的 IIS/应用程序池管理任务而涉足其中。

于 2009-03-13T03:05:40.687 回答