しばやん雑記

Azure とメイドさんが大好きなフリーランスのプログラマーのブログ

IIS の ネイティブ HTTP モジュールで Web.config から設定を読み込む方法を調べた

IIS ネイティブ HTTP モジュールは設定を Web.config から読み込むのが一般的ですが、どうやって読み込むのか分からなかったので調べました。ネイティブ HTTP モジュールの作り方は以前に書いた通りです。

Web.config の読み込みは IHttpServer から IAppHostAdminManager を取得し、さらに GetAdminSection メソッドを呼び出すと、該当する Web.config のセクションを読み込めます。

IAppHostAdminManager::GetAdminSection Method

言葉だと説明にしくいので、実際に動くコードを使って紹介します。

設定を読み込む

IHttpContext から MetaPath を取得し、GetAdminSection メソッドを呼び出す流れです。IAppHostElement を取得出来れば楽ですが、COM なので BSTR を使ったり、Release を忘れないようにするなど面倒です。

HRESULT CModuleConfiguration::Initialize(IN IHttpContext *pHttpContext, IN IHttpServer *pHttpServer)
{
    // samplecfg 要素を読み込む
    IAppHostElement *section;

    BSTR path = SysAllocString(pHttpContext->GetMetadata()->GetMetaPath());
    BSTR sectionPath = SysAllocString(L"system.webServer/samplecfg");

    pHttpServer->GetAdminManager()->GetAdminSection(sectionPath, path, &section);

    SysFreeString(sectionPath);
    SysFreeString(path);

    if (section == NULL)
    {
        return S_OK;
    }

    // samplecfg.config 属性を読み込む
    IAppHostProperty property;

    BSTR propertyName = SysAllocString(L"config");

    section->GetPropertyByName(propertyName, &property);

    SysFreeString(propertyName);

    // プロパティの値を読み込む
    BSTR propertyValue;

    property->get_StringValue(&propertyValue);

    SysFreeString(propertyValue);

    // リソースを解放
    property->Release();
    section->Release();

    return S_OK;
}

IAppHostAdminManager の取得に必要な IHttpServer は RegisterModule 関数でしか取れないので、そのタイミングでグローバルな領域にでも保存しておく必要があります。

あとは IHttpContext も必要になるので、呼び出されるタイミングには気を使う必要があります。

COM スマートポインタを使う

Visual C++ の COM スマートポインタを使うと、リソースの解放を考えずに書けるので便利です。

COM スマートポインタを使うには comdef.h をインクルードして、_COM_SMARTPTR_TYPEDEF を使って該当する COM インターフェースを定義しておく必要があります

#include <comdef.h>

_COM_SMARTPTR_TYPEDEF(IAppHostElement, __uuidof(IAppHostElement));
_COM_SMARTPTR_TYPEDEF(IAppHostProperty, __uuidof(IAppHostProperty));

static const _bstr_t sectionPath = L"system.webServer/samplecfg";
static const _bstr_t propertyName = L"config";

HRESULT CModuleConfiguration::Initialize(IN IHttpContext *pHttpContext, IN IHttpServer *pHttpServer)
{
    // samplecfg 要素を読み込む
    IAppHostElementPtr section;

    _bstr_t path = pHttpContext->GetMetadata()->GetMetaPath();

    pHttpServer->GetAdminManager()->GetAdminSection(sectionPath, path, &section);

    if (section == NULL)
    {
        return S_OK;
    }

    // samplecfg.config 属性の値を読み込む
    IAppHostPropertyPtr property;

    section->GetPropertyByName(propertyName, &property);

    _bstr_t propertyValue;

    property->get_StringValue(&propertyValue.GetBSTR());

    return S_OK;
}

_com_ptr_t と _bstr_t を使うと解放する必要が無いので、とてもシンプルに書けました。_bstr は comutil.h だけで使えますが、_COM_SMARTPTR_TYPEDEF は comdef.h が必要なので注意です。

COM リソースの解放を忘れると IIS のワーカープロセスが終了しなくなるようでした。