您可以通过三种方式解决此问题:
- 普通的旧 System.DirectoryServices
- 解析 IIS metabase.xml 文件
- System.DirectoryServices 和一些 COM 互操作
普通的旧 System.DirectoryServices
由于元数据库属性继承,确定一个IIsWebDirectory
或一个IIsWebVirtualDir
IIS 管理对象是否配置为单独使用的应用程序System.DirectoryServices
有时可能不是显而易见的事情。
例如,当您创建“应用程序”时,通常会在元数据库管理对象IIsWebDirectory
或IIsWebVirtualDir
元数据库管理对象上设置三个属性 -
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|1
IIS 是否在 IIS5 兼容模式下运行。当您创建自己的应用程序时,您应该始终设置AppIsolated=2
这意味着站点或应用程序将在您的应用程序池之一 (w3wp.exe) 中运行。
无论如何...由于元数据库属性继承,检查上面列出的三个属性中的任何一个都不能保证您正在检查的对象实际上是一个应用程序 - 无论是使用 ADSI、WMI 还是DirectoryServices
API。即使您正在检查的对象只是一个虚拟目录(不是应用程序),您仍然会得到返回的值,因为它们将从父应用程序继承。
例如,如果/MyVdir
是位于默认网站中的虚拟目录(不是应用程序),您仍然会看到 的值AppIsolated
,这是因为它继承自IIS://Localhost/w3svc/1/root
)。AppFriendlyName
和AppRoot
属性也是如此。
我在这里采用的方法是将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/MyApp
,AppRoot
管理对象属性 ,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/应用程序池管理任务而涉足其中。