获取 IIS 7 站点属性

发布于 2024-10-13 13:11:20 字数 454 浏览 1 评论 0原文

我有一个 C++ 应用程序,需要检索 IIS 7 站点的属性(例如类似于 IIS6 中的元数据库属性 - PathAppFriendlyName 等)。

在 IIS 7 中,我的代码执行以下操作:

  1. 获取 AppHostWritableAdminManager 并提交路径 MACHINE/WEBROOT/APPHOST/Default Web Site/
  2. 使用部分名称 appSettings 调用 GetAdminSection
  3. 然后查看返回的集合并查找属性(例如 Path)。

这适用于 IIS 6,但不适用于 IIS7/7.5。

为了使这项工作顺利进行,我需要做出哪些改变?

I have a C++ application that needs to retrieve an IIS 7 site's properties (such as metabase properties similar to those in IIS6 - Path, AppFriendlyName etc).

With IIS 7, my code does this:

  1. Get the AppHostWritableAdminManager and commit the path MACHINE/WEBROOT/APPHOST/Default Web Site/.
  2. Call GetAdminSection with the section name appSettings.
  3. Then look at the returned collection and look for the property (Path for example).

This works in IIS 6 but not on IIS7/7.5.

What changes do I need to make in order to make this work?

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

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

发布评论

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

评论(1

笔芯 2024-10-20 13:11:21

在 IIS7 中,配置数据并不存储在“元数据库”中,而且我们在 IIS6 中习惯的元数据库属性也不同。 IIS7 将其大部分配置数据存储在以下文件中:

%systemroot%\System32\InetSrv\Config\applicationHost.config

还有其他文件,但为了回答这个问题,这是我们感兴趣的文件。

的文档applicationHost.config 可以在这里找到:

- IIS.NET
配置元素 [IIS 7设置架构]
system.applicationHost 部分组[IIS 7 设置架构]

您可以找到 IIS6 元数据库列表 -> IIS7 XML 配置映射如下:

将元数据库属性转换为配置设置 [IIS 7 ]

例如,在 IIS6 中,站点 /root 的路径存储在 IIsWebVirtualDirPath 属性中。即:

<IIsWebServer Location="/LM/W3SVC/67793744" AuthFlags="0" ServerAutoStart="TRUE" 
              ServerBindings="217.69.47.170:80:app2.dev" ServerComment="app2" /> 
<IIsWebVirtualDir Location="/LM/W3SVC/67793744/root" 
    AccessFlags="AccessRead | AccessScript" 
    AppFriendlyName="Default Application" 
    AppIsolated="2" 
    AppRoot="/LM/W3SVC/67793744/Root" 
    AuthFlags="AuthAnonymous | AuthNTLM" 
    DirBrowseFlags="DirBrowseShowDate | DirBrowseShowTime | DirBrowseShowSize |
            DirBrowseShowExtension | DirBrowseShowLongDate | EnableDefaultDoc" 
    Path="D:\websites\ssl-test\www\kerboom" 
    ScriptMaps="...">

但在 IIS7 中,它的存储方式有所不同:

<sites>
    <site name="Default Web Site" id="1" serverAutoStart="true">
        <!-- this is the functional equivalent of the /root app in IIS6 -->
        <application path="/">
            <virtualDirectory path="/" 
                              physicalPath="%SystemDrive%\inetpub\wwwroot" />
        </application>
    </site>
<sites>

但是,如果您的代码必须同时适用于 IIS6 和 IIS7,那么您可以安装 IIS6 管理兼容性组件。这将允许您使用传统的 IIS6 元数据库 API(例如 ADSI、System.DirectoryServices 等)访问 IIS7 站点属性。兼容性层将为您将这些属性映射到新的 IIS7 架构。

本文的第一部分解释了如何在 Vista/Windows7/Windows 2008 上安装它:

如何在 Vista 和 Windows 2008 上使用 IIS7 安装 ASP.NET 1.1 - 请参阅步骤 #1

更新:

不幸的是,C++ 不是我的强项。不过,我使用 COM Interop 在 C# 中组合了一个示例,以演示如何使用 AppHostWritableAdminManager

IAppHostWritableAdminManager wam = new AppHostWritableAdminManager();
IAppHostElement sites = 
   wam.GetAdminSection("system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST");
IAppHostElementCollection sitesCollection = sites.Collection;

long index = FindSiteIndex(sitesCollection, "MySite");
if(index == -1) throw new Exception("Site not found");

IAppHostElement site = sitesCollection[index];
IAppHostElementCollection bindings = site.ChildElements["bindings"].Collection;

for (int i = 0; i < bindings.Count; i++)
{
  IAppHostElement binding = bindings[i];
  IAppHostProperty protocolProp = binding.GetPropertyByName("protocol");
  IAppHostProperty bindingInformationProp = 
      binding.GetPropertyByName("bindingInformation");

  string protocol = protocolProp.Value;
  string bindingInformation = bindingInformationProp.Value;

  Debug.WriteLine("{0} - {1}", protocol, bindingInformation);

}

static long FindSiteIndex(IAppHostElementCollection sites, string siteName)
{
  for (int i = 0; i < sites.Count; i++)
  {
    IAppHostElement site = sites[i];
    Debug.WriteLine(site.Name);
    IAppHostProperty prop = site.GetPropertyByName("name");
    if(prop.Value == siteName)
    {
      return i;
    }
  }
  return -1;
}

上面的代码在 集合中定位名为“MySite”的站点。然后,它检索站点的 集合并打印每个绑定的 protocolbindingInformation 属性。

您应该能够相当轻松地将其转换为 C++。

回答您评论中的问题 -

例如,路径
system.applicationHost/Sites 将得到
我到网站列表。有没有一个
访问我的服务器的绝对方法
像这样的绑定(例如通过
正在做
system.applicationHost/站点/默认
网站/绑定

使用 AppHostWritableAdminManager 时,没有直接访问您想要检查/修改的网站或其属性的快捷方式。在上面的示例中,您将看到我需要循环访问网站集以找到我感兴趣的网站。原因是 AppHostWritableAdminManager 将所有内容视为元素和元素集合。这是一个相当基本的 API。即使使用托管 Microsoft.Web.Administration API,您也会发现虽然有一些不错的属性,例如 Site.Bindings,但它们只是对 AppHostWritableAdminManager 进行了轻微伪装的包装器

事实上,如果我想找到一个站点,我仍然需要在 for 循环中搜索 Sites 集合,或者如果我使用 C#3.5 或更高版本,则需要添加一些 LINQ 糖:

using(ServerManager serverManager = new ServerManager())
{
    Site x = serverManager.Sites.FirstOrDefault(s => s.Name == "MySite");
}

Site 的基类是 ConfigurationElement,它在引擎盖下封装了对 IAppHostElement 的访问。

一旦您了解了一些基本的快捷方式包装器属性,我们在托管代码中配置 IIS(例如 IIS FTP)的大部分工作就是元素、属性和元素集合。

更新 2:

请记住,我一生中从未写过一行 C++ 代码。没有清理字符串或对象:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <ahadmin.h>
#include <crtdbg.h>

static IAppHostElement* 
   FindSite(IAppHostElementCollection *pCollection, BSTR bstrSiteName);

int _tmain(int argc, _TCHAR* argv[])
{
  CoInitialize(NULL);

  IAppHostWritableAdminManager *pMgr = NULL;
  IAppHostElement *pElem = NULL;
  IAppHostElementCollection *pSitesCollection = NULL;
  IAppHostElement *pSite = NULL;
  IAppHostElement *pBindings = NULL;
  IAppHostElement *pBinding = NULL;
  IAppHostElementCollection *pBindingsCollection = NULL;
  IAppHostChildElementCollection *pChildElements = NULL;
  IAppHostProperty *pProtocol = NULL;
  IAppHostProperty *pBindingInformation = NULL;

  BSTR bstrSectionName = SysAllocString( L"system.applicationHost/sites" );
  BSTR bstrConfigCommitPath = SysAllocString( L"MACHINE/WEBROOT/APPHOST" );
  BSTR bstrSiteName = SysAllocString( L"MySite" );
  BSTR bstrBindingsConst = SysAllocString( L"bindings" );
  BSTR bstrBindingProtocol = SysAllocString( L"protocol" );
  BSTR bstrBindingInformation = SysAllocString( L"bindingInformation" );

  VARIANT vtPropertyName;
  VARIANT vtIndex;

  HRESULT hr = S_OK;

  hr = CoCreateInstance( __uuidof(AppHostWritableAdminManager), NULL, 
      CLSCTX_INPROC_SERVER, __uuidof(IAppHostWritableAdminManager), (void**) &pMgr);

  hr = pMgr->GetAdminSection(bstrSectionName, bstrConfigCommitPath, &pElem);
  hr = pElem->get_Collection(&pSitesCollection);

  pSite = FindSite(pSitesCollection, bstrSiteName);

  hr = pSite->get_ChildElements(&pChildElements);

  vtPropertyName.vt = VT_BSTR;
  vtPropertyName.bstrVal = bstrBindingsConst;

  hr = pChildElements->get_Item(vtPropertyName, &pBindings);
  hr = pBindings->get_Collection(&pBindingsCollection);

  DWORD bindingsCount;
  hr = pBindingsCollection->get_Count(&bindingsCount);

  for(int i = 0; i < bindingsCount; i++)
  {
    vtIndex.lVal = i;
    vtIndex.vt = VT_I4;
    hr = pBindingsCollection->get_Item(vtIndex, &pBinding);

    hr = pBinding->GetPropertyByName(bstrBindingProtocol, &pProtocol);
    hr = pBinding->GetPropertyByName(bstrBindingInformation, &pBindingInformation);

    BSTR bstrProtocol;
    BSTR bstrBindingInformation;

    hr = pProtocol->get_StringValue(&bstrProtocol);
    hr = pBindingInformation->get_StringValue(&bstrBindingInformation);

    _tprintf(_T("Protocol: %s, BindingInfo: %s\n"), bstrProtocol, bstrBindingInformation);
  }

  CoUninitialize();
  return 0;
}

IAppHostElement* FindSite(IAppHostElementCollection *pCollection, BSTR bstrSiteName)
{
  DWORD count = -1;
  pCollection->get_Count(&count);

  BSTR bstrPropName = SysAllocString( L"name");

  for(DWORD i = 0; i < count; i++)
  {
    IAppHostElement *site = NULL;
    IAppHostProperty *prop = NULL;
    BSTR bstrPropValue;

    HRESULT hr = S_OK;

    VARIANT vtCount;
    VariantInit(&vtCount);
    vtCount.lVal = i;
    vtCount.vt = VT_I4;

    hr = pCollection->get_Item(vtCount, &site);
    hr = site->GetPropertyByName(bstrPropName, &prop);
    hr = prop->get_StringValue(&bstrPropValue);

    if(wcscmp(bstrPropValue, bstrSiteName) == 0)
    {
      return site;
    }
  }

  return NULL;
}

In IIS7 the configuration data is not stored in a "metabase" and also the metabase properties that we're accustomed to in IIS6 aren't the same. IIS7 stores the bulk of its configuration data in the following file:

%systemroot%\System32\InetSrv\Config\applicationHost.config

There are other files, but for the purposes of answering this question, this is the file we're interested in.

The documentation for applicationHost.config can be found here:

<system.applicationHost> - IIS.NET
configuration Element [IIS 7 Settings Schema]
system.applicationHost Section Group [IIS 7 Settings Schema]

You can find a list of IIS6 metabase -> IIS7 XML configuration mappings here:

Converting Metabase Properties to Configuration Settings [IIS 7]

For example in IIS6 the path to a site's /root is stored in the Path attribute of IIsWebVirtualDir. i.e.:

<IIsWebServer Location="/LM/W3SVC/67793744" AuthFlags="0" ServerAutoStart="TRUE" 
              ServerBindings="217.69.47.170:80:app2.dev" ServerComment="app2" /> 
<IIsWebVirtualDir Location="/LM/W3SVC/67793744/root" 
    AccessFlags="AccessRead | AccessScript" 
    AppFriendlyName="Default Application" 
    AppIsolated="2" 
    AppRoot="/LM/W3SVC/67793744/Root" 
    AuthFlags="AuthAnonymous | AuthNTLM" 
    DirBrowseFlags="DirBrowseShowDate | DirBrowseShowTime | DirBrowseShowSize |
            DirBrowseShowExtension | DirBrowseShowLongDate | EnableDefaultDoc" 
    Path="D:\websites\ssl-test\www\kerboom" 
    ScriptMaps="...">

But in IIS7 it's stored differently:

<sites>
    <site name="Default Web Site" id="1" serverAutoStart="true">
        <!-- this is the functional equivalent of the /root app in IIS6 -->
        <application path="/">
            <virtualDirectory path="/" 
                              physicalPath="%SystemDrive%\inetpub\wwwroot" />
        </application>
    </site>
<sites>

However, if your code must work with both IIS6 and IIS7 then you can install the IIS6 Management Compatibility components. This will allow you to access IIS7 site properties using traditional IIS6 metabase API's such as ADSI, System.DirectoryServices etc. The compatibility layer will map these properties to the new IIS7 schema for you.

The first part of this article explains how to install this on Vista/Windows7/Windows 2008:

How to install ASP.NET 1.1 with IIS7 on Vista and Windows 2008 - see step #1

Update:

Unfortunately C++ isn't my strong point. However I put together an example in C# using COM Interop to demonstrate using the AppHostWritableAdminManager:

IAppHostWritableAdminManager wam = new AppHostWritableAdminManager();
IAppHostElement sites = 
   wam.GetAdminSection("system.applicationHost/sites", "MACHINE/WEBROOT/APPHOST");
IAppHostElementCollection sitesCollection = sites.Collection;

long index = FindSiteIndex(sitesCollection, "MySite");
if(index == -1) throw new Exception("Site not found");

IAppHostElement site = sitesCollection[index];
IAppHostElementCollection bindings = site.ChildElements["bindings"].Collection;

for (int i = 0; i < bindings.Count; i++)
{
  IAppHostElement binding = bindings[i];
  IAppHostProperty protocolProp = binding.GetPropertyByName("protocol");
  IAppHostProperty bindingInformationProp = 
      binding.GetPropertyByName("bindingInformation");

  string protocol = protocolProp.Value;
  string bindingInformation = bindingInformationProp.Value;

  Debug.WriteLine("{0} - {1}", protocol, bindingInformation);

}

static long FindSiteIndex(IAppHostElementCollection sites, string siteName)
{
  for (int i = 0; i < sites.Count; i++)
  {
    IAppHostElement site = sites[i];
    Debug.WriteLine(site.Name);
    IAppHostProperty prop = site.GetPropertyByName("name");
    if(prop.Value == siteName)
    {
      return i;
    }
  }
  return -1;
}

The code above locates a site named "MySite" in the <sites> collection. It then retrieves the site's <bindings> collection and print's each bindings protocol and bindingInformation attributes.

Your should be able to convert this to C++ fairly easily.

To answer the question in your comment -

For example, the path
system.applicationHost/Sites will get
me to the list of sites. Is there an
absolute way to get to my server
bindings like this (for example by
doing
system.applicationHost/Sites/Default
Web Site/Bindings

When using the AppHostWritableAdminManager there isn't a shortcut to getting directly to the site you want to inspect/modify or it's properties. In the example above, you'll see that I need to loop through the sites collection to find the site I'm interested in. The reason for this is that AppHostWritableAdminManager sees everything as elements and collections of elements. It's a fairly basic API. Even when using the managed Microsoft.Web.Administration API you find that whilst there are some nice properties such as Site.Bindings, these are thinly disguised wrappers around AppHostWritableAdminManager.

In fact if I want to find a site I still have to search the Sites collection either in a for loop or by adding some LINQ sugar if I'm using C#3.5 or later:

using(ServerManager serverManager = new ServerManager())
{
    Site x = serverManager.Sites.FirstOrDefault(s => s.Name == "MySite");
}

Site's base class is ConfigurationElement which under the bonnet wraps access to IAppHostElement.

Once you're past some basic shortcut wrapper properties much of what we do in managed code to configure IIS (for example IIS FTP) is elements, attributes and collections of elements.

Update 2:

Please bear in mind I've never written a line of C++ in my life. There's no cleanup of strings or objects:

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>
#include <ahadmin.h>
#include <crtdbg.h>

static IAppHostElement* 
   FindSite(IAppHostElementCollection *pCollection, BSTR bstrSiteName);

int _tmain(int argc, _TCHAR* argv[])
{
  CoInitialize(NULL);

  IAppHostWritableAdminManager *pMgr = NULL;
  IAppHostElement *pElem = NULL;
  IAppHostElementCollection *pSitesCollection = NULL;
  IAppHostElement *pSite = NULL;
  IAppHostElement *pBindings = NULL;
  IAppHostElement *pBinding = NULL;
  IAppHostElementCollection *pBindingsCollection = NULL;
  IAppHostChildElementCollection *pChildElements = NULL;
  IAppHostProperty *pProtocol = NULL;
  IAppHostProperty *pBindingInformation = NULL;

  BSTR bstrSectionName = SysAllocString( L"system.applicationHost/sites" );
  BSTR bstrConfigCommitPath = SysAllocString( L"MACHINE/WEBROOT/APPHOST" );
  BSTR bstrSiteName = SysAllocString( L"MySite" );
  BSTR bstrBindingsConst = SysAllocString( L"bindings" );
  BSTR bstrBindingProtocol = SysAllocString( L"protocol" );
  BSTR bstrBindingInformation = SysAllocString( L"bindingInformation" );

  VARIANT vtPropertyName;
  VARIANT vtIndex;

  HRESULT hr = S_OK;

  hr = CoCreateInstance( __uuidof(AppHostWritableAdminManager), NULL, 
      CLSCTX_INPROC_SERVER, __uuidof(IAppHostWritableAdminManager), (void**) &pMgr);

  hr = pMgr->GetAdminSection(bstrSectionName, bstrConfigCommitPath, &pElem);
  hr = pElem->get_Collection(&pSitesCollection);

  pSite = FindSite(pSitesCollection, bstrSiteName);

  hr = pSite->get_ChildElements(&pChildElements);

  vtPropertyName.vt = VT_BSTR;
  vtPropertyName.bstrVal = bstrBindingsConst;

  hr = pChildElements->get_Item(vtPropertyName, &pBindings);
  hr = pBindings->get_Collection(&pBindingsCollection);

  DWORD bindingsCount;
  hr = pBindingsCollection->get_Count(&bindingsCount);

  for(int i = 0; i < bindingsCount; i++)
  {
    vtIndex.lVal = i;
    vtIndex.vt = VT_I4;
    hr = pBindingsCollection->get_Item(vtIndex, &pBinding);

    hr = pBinding->GetPropertyByName(bstrBindingProtocol, &pProtocol);
    hr = pBinding->GetPropertyByName(bstrBindingInformation, &pBindingInformation);

    BSTR bstrProtocol;
    BSTR bstrBindingInformation;

    hr = pProtocol->get_StringValue(&bstrProtocol);
    hr = pBindingInformation->get_StringValue(&bstrBindingInformation);

    _tprintf(_T("Protocol: %s, BindingInfo: %s\n"), bstrProtocol, bstrBindingInformation);
  }

  CoUninitialize();
  return 0;
}

IAppHostElement* FindSite(IAppHostElementCollection *pCollection, BSTR bstrSiteName)
{
  DWORD count = -1;
  pCollection->get_Count(&count);

  BSTR bstrPropName = SysAllocString( L"name");

  for(DWORD i = 0; i < count; i++)
  {
    IAppHostElement *site = NULL;
    IAppHostProperty *prop = NULL;
    BSTR bstrPropValue;

    HRESULT hr = S_OK;

    VARIANT vtCount;
    VariantInit(&vtCount);
    vtCount.lVal = i;
    vtCount.vt = VT_I4;

    hr = pCollection->get_Item(vtCount, &site);
    hr = site->GetPropertyByName(bstrPropName, &prop);
    hr = prop->get_StringValue(&bstrPropValue);

    if(wcscmp(bstrPropValue, bstrSiteName) == 0)
    {
      return site;
    }
  }

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