如何确定“IIsWebDirectory”是否已存在 或“IIsWebVirtualDir” 是 ASP.NET 应用程序吗?

发布于 2024-07-15 21:50:29 字数 1026 浏览 7 评论 0原文

我目前正在编写一个 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...
            }
        }
    }
}

I am currently writing an C# asp.net application to connect to an IIS server and query the virtual directory/web directory information.

I am able to determine that there are that two types I should be dealing with is an "IIsWebDirectory" and "IIsWebVirtualDir".

How to I determine if they have been configured to be an "application" in C#?

You can also view my adventures in C# and IIS here and here

UPDATE

@Kev - I took the information in your answer and developed the following simple solution to check to see if the AppFriendlyName is not set to "Default Application"

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

顾北清歌寒 2024-07-22 21:50:29

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

  • 普通旧式 System.DirectoryServices
  • 解析 IIS metabase.xml 文件
  • System.DirectoryServices 和一些 COM
    interop

普通旧式 System.DirectoryServices

确定 IIsWebDirectoryIIsWebVirtualDir 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 的服务器上,如果 IIS 在 IIS5 兼容模式下运行,您只会看到 AppIsolated=0|1。 当您创建自己的应用程序时,应始终设置 AppIsolated=2,这意味着站点或应用程序将在您的应用程序池之一 (w3wp.exe) 中运行。

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

例如,如果 /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 文件

我过去在死服务器重建作业中使用过另一种方法,其中我们有元数据库文件、我们知道的 vdir 和应用程序的数据库表我们已经创建了它,但没有其他任何东西 - 服务器在弹出之前有 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”的 COM 库的引用 (%systemroot%\system32\inetsrv\iisext.dll),它列在 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/应用程序池管理任务。

There are three ways you can approach this problem:

  • Plain old System.DirectoryServices
  • Parse the IIS metabase.xml file
  • System.DirectoryServices and some COM
    interop

Plain old System.DirectoryServices

Determining whether an IIsWebDirectory or an IIsWebVirtualDir IIS admin object is configured to be an application using System.DirectoryServices alone can sometimes be a non-obvious business because of metabase property inheritance.

For example, when you create an 'application' there are normally three properties set on the IIsWebDirectory or IIsWebVirtualDir metabase admin objects -

AppFriendlyName
AppIsolated
AppRoot

In the metabase you would see something like:

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

Now you would think that it would be as simple as checking for the presence of these three properties, and in particular the AppIsolated property because that's the property used to indicate the Application Isolation type (in-process [0], out-of-process [1] or pooled [2]) - and every application requires this property. As a sidenote, on a server running IIS6 you would only see AppIsolated=0|1 if IIS was running in IIS5 compatibility mode. When you create your own applications you should always set AppIsolated=2 which means the site or application will run in one of your application pools (w3wp.exe).

Anyway... because of metabase property inheritance, checking for any of the three properties listed above doesn't guarantee the object you're examining is actually an application - whether it be by using the ADSI, WMI or DirectoryServices API's. Even if the object you are checking is just a virtual directory (not application) you'll still get values returned because they would be inherited from the parent application.

For example, if /MyVdir is a virtual directory (not application) located in the Default Website, you would still see a value for AppIsolated, this is because it is inherited from IIS://Localhost/w3svc/1/root). The same applies with the AppFriendlyName and AppRoot properties.

The approach I took here was to compare the DirectoryEntry.Path property with the AppRoot property on the target admin object. AppRoot is a property that indicates where a particular application is rooted. This can be handy if you are examining an IIS admin object deep down in the site's metabase hierarchy and you need to know where its application is rooted at.

So, say I had an application located at:

IIS://Localhost/w3svc/1/root/MyApp

...and say we have an instance of DirectoryEntry:

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

The de.Path property would be set to IIS://Localhost/w3svc/1/root/MyApp, the AppRoot admin object property, de.Properties["AppRoot"].Value, would be set to /LM/W3SVC/1/Root/MyApp. All you need to do is strip off the leading IIS://Localhost and /LM strings and do a case-insensitive string compare. If there's a match then the object at that path is an application.

Parse the IIS metabase.xml file

There is another way that I've used in the past as part of a dead server rebuild job where we had the metabase file, a database table of vdirs and apps we knew we'd created and not much else - the server had 1200 websites and a multitude of virtual directories and applications before it popped. Basically I loaded the whole metabase.xml file into an XMLDocument. I then used XPath to look for the presence of the AppIsolated attribute where the Location attibute matched the path I was interested in.

This is a extract of code that should give you the general jist of the idea:

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

Parsing the raw metabase.xml file works ok as long as there isn't a high turn over of applications/virtual directories. This is because in-memory metabase updates are not flushed to the metabase.xml file immediately. I wouldn't recommend doing this, I only approached the problem this way purely for the purposes of system recovery.

System.DirectoryServices and some COM interop

Finally there is a third way (and probably the simplest) which you may not be able to test properly if your development PC is not running IIS6/Windows 2003 (I don't have an XP machine available to verify if this works with IIS 5.1). What you do is add a reference to a COM library called 'Active DS IIS Extension Dll' (%systemroot%\system32\inetsrv\iisext.dll), it's listed on the COM tab in Visual Studio's Add Reference dialogue. When you add this reference, Visual Studio will also automatically resolve and reference a dependency, 'Active DS Type Library' (%systemroot%\system32\activeds.tlb). In your solution references folder you'll see them listed as 'ActiveDS' and 'IISExt'.

Using the 'Active DS IIS Extension' library we can test if an IIS admin object at a particular path is in fact an IIS Application by doing the following:

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

}

There is a fourth way using WMI but I've only dipped my toes in the water for some fairly simple IIS/App Pool management tasks.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文