获取IIS 7站点属性

Ron*_*Ron 3 c++ configuration iis-7 metabase

我有一个C++应用程序需要检索IIS 7网站的属性(诸如数据库属性类似于在IIS6 - Path,AppFriendlyName等).

使用IIS 7,我的代码执行此操作:

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

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

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

Kev*_*Kev 8

在IIS7中,配置数据不存储在"元数据库"中,而且我们在IIS6中习惯使用的元数据库属性也不相同.IIS7将大部分配置数据存储在以下文件中:

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

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

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

<system.applicationHost>- IIS.NET
configuration Element [IIS 7 Settings Schema]
system.applicationHost节组[IIS 7设置架构]

您可以在此处找到IIS6配置数据库 - > IIS7 XML配置映射的列表:

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

例如,在IIS6中,站点的路径/root存储在Path属性中IIsWebVirtualDir.即:

<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="...">
Run Code Online (Sandbox Code Playgroud)

但在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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

更新:

不幸的是,C++不是我的强项.但是我在C#中使用COM Interop组合了一个示例来演示使用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;
}
Run Code Online (Sandbox Code Playgroud)

上面的代码在<sites>集合中找到名为"MySite"的站点.然后它检索网站的<bindings>集合并打印每个绑定protocolbindingInformation属性.

你应该能够很容易地将它转换为C++.

要在评论中回答这个问题 -

例如,路径system.applicationHost/Sites将使我进入站点列表.是否有绝对的方式来访问我的服务器绑定(例如通过做system.applicationHost/Sites/Default Web Site/Bindings)

使用时,AppHostWritableAdminManager没有直接进入要检查/修改的站点或其属性的快捷方式.在上面的示例中,您将看到我需要遍历网站集以找到我感兴趣的网站.原因是AppHostWritableAdminManager将所有内容视为元素和元素集合.这是一个相当基本的API.即使使用托管Microsoft.Web.AdministrationAPI,您也会发现虽然有一些很好的属性,例如Site.Bindings,这些是伪装的包装器AppHostWritableAdminManager.

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

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

Site的基础类是ConfigurationElement在bonnet包裹下进入的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;
}
Run Code Online (Sandbox Code Playgroud)