IIS 7 統合パイプラインの利点の活用方法

公開日: 2007 年 12 月 5 日 (作業者: IIS チーム (英語))

更新日: 2008 年 2 月 29 日 (作業者: IIS チーム (英語))

はじめに

IIS 6 以前のバージョンでは、ASP.NET プラットフォームで .NET アプリケーション コンポーネントを開発できます。ASP.NET は ISAPI 拡張によって IIS と統合され、独自のアプリケーションおよび要求処理モデルを利用できます。例として 2 つのサーバー パイプラインがあります。1 つはネイティブ ISAPI フィルターおよび拡張機能コンポーネント用、もう 1 つはマネージ アプリケーション コンポーネント用のパイプラインです。ASP.NET コンポーネントは、完全に ASP.NET ISAPI 拡張機能バブル内で実行され、IIS スクリプト マップ構成内の ASP.NET にマップされた要求に対してのみ実行されます。

IIS 7 では、コア サーバーに ASP.NET ランタイムが統合され、モジュールとして認識されるネイティブ コンポーネントとマネージ コンポーネントから利用できる統合要求処理パイプラインを利用できます。この統合には、以下をはじめとする多くの利点があります。

  • ネイティブおよびマネージの両方のモジュールから提供されるサービスを、ハンドラーに関係なく、すべての要求に適用できます。たとえば、マネージ フォーム認証を、ASP ページ、CGI、静的ファイルなどのすべてのコンテンツに使用できます。
  • サーバー パイプラインでの実行位置の制限によって以前は ASP.NET コンポーネントで提供できなかった機能を使用できます。たとえば、要求を書き換える機能を提供するマネージ モジュールを使用して、認証などのサーバー処理に渡される前に要求を書き換えることができます。
  • モジュールとハンドラー マッピングの単一の構成、カスタム エラーの単一の構成、URL 認証の単一の構成など、サーバー機能の実装、構成、監視、サポートを 1 か所で管理できます。

この記事では、ASP.NET アプリケーションで IIS 7 の統合モードの利点を活用する方法を検討し、以下の作業について解説します。

  • アプリケーションごとにモジュールの有効化と無効化を行う。
  • サーバーにマネージ アプリケーション モジュールを追加し、すべての要求の種類に適用されるようにする。
  • マネージ ハンドラーを追加する。

IIS 7 モジュールの構築の詳細については、「.NET Framework による IIS 7 のモジュールおよびハンドラーの開発」を参照してください。

また、統合モードの利点の活用、および IIS 7 での ASP.NET 統合を活用する IIS 7 モジュールの開発のヒントについては、ブログ (http://www.mvolo.com/、英語) も参照してください。このブログでは、「HttpRedirection モジュールを使用して要求をアプリケーションにリダイレクトする (英語)」、「DirectoryListingModule を使用して IIS Web サイトの見やすいディレクトリ一覧を表示する (英語)」、「IconHandler を使用して ASP.NET アプリケーションで見栄えのよいファイル アイコンを表示する (英語)」、および「IIS と ASP.NET によるホット リンクの阻止 (英語)」などのページからさまざまな IIS 7 モジュールをダウンロードできます。

必要条件

このドキュメントのステップを実行するには、以下の IIS 7 の機能をインストールする必要があります。

ASP.NET

Windows Vista のコントロール パネルから ASP.NETをインストールします。[プログラムと機能] の [Windowsの機能の有効化または無効化] をクリックします。次に、[インターネット インフォメーション サービス]、[World Wide Web サービス]、[アプリケーション開発機能] の順に展開し、[ASP.NET] をオンにします。

Windows Server® 2008 ビルドの場合は、[サーバー マネージャ]、[役割] の順に展開し、[Web サーバー (IIS)] をオンにします。[役割サービスの追加] をクリックします。[アプリケーション開発] の [ASP.NET] をオンにします。

クラシック ASP

ASP.NET ページだけではなく、すべてのコンテンツに対して ASP.NET モジュールが動作することを示す必要があるので、Windows Vista のコントロール パネルからクラシック ASP をインストールします。[プログラム] をクリックし、[Windowsの機能の有効化または無効化] をクリックします。次に、[インターネット インフォメーション サービス]、[World Wide Web サービス]、[アプリケーション開発機能] の順に展開し、[ASP] をオンにします。

Windows Server 2008 ビルドの場合は、[サーバー マネージャ]、[役割] の順に展開し、[Web サーバー (IIS)] をオンにします。[役割サービスの追加] をクリックします。[アプリケーション開発] の [ASP] をオンにします。

アプリケーションへのフォーム認証の追加

この作業の一環として、アプリケーションで ASP.NET のフォームに基づく認証を有効にします。次の作業では、コンテンツ タイプに関係なく、フォーム認証モジュールがアプリケーションへのすべての要求に対して実行されるようにします。

最初に、普通の ASP.NET アプリケーション向けの場合と同様にフォーム認証を構成します。

サンプル ページの作成

この機能を例示するために、default.aspx ページを Web のルート ディレクトリに追加します。メモ帳を開きます。wwwroot ディレクトリに確実にアクセスするには、管理者として実行する必要があります ([すべてのプログラム]、[アクセサリ] の順にクリックし、[メモ帳] アイコンを右クリックして [管理者として実行] をクリックします)。%systemdrive%\inetpub\wwwroot\default.aspx というファイルを作成し、以下のコードを追加します。

<%=Datetime.Now%> 
<BR> 
Login Name: <asp:LoginName runat="server"/> 

default.aspx は、現在時刻およびログインしたユーザーの名前を表示するだけのものです。このページを後で使用して、動作中のフォーム認証を示します。

フォーム認証およびアクセス制御規則の構成

ここで、default.aspx をフォーム認証で保護します。%systemdrive%\inetpub\wwwroot ディレクトリに web.config ファイルを作成し、次の構成を追加します。

<configuration> 
  <system.web> 
    <!--membership provider entry goes here--> 
    <authorization> 
      <deny users="?"/> 
      <allow users="*"/> 
    </authorization> 
    <authentication mode="Forms"/> 
  </system.web> 
</configuration> 

この構成によって、ASP.NET 認証モードでフォームに基づく認証が使用されるようになり、アプリケーションへのアクセスを制御するための承認設定が追加されます。これらの設定では、匿名ユーザー (?) のアクセスは拒否され、認証されたユーザー (*) のみが許可されます。

メンバーシップ プロバイダーの作成

ステップ 1: ユーザー資格情報を照合するための認証ストアを提供する必要があります。ASP.NET と IIS 7 の密接な統合を例示するために、独自の XML に基づくメンバーシップ プロバイダーを使用します (SQL Server がインストールされている場合は、既定の SQL Server メンバーシップ プロバイダーも使用できます)。

Web.config ファイル内の最初の <configuration>/<system.web> 構成要素の直後に、次のエントリを追加します。

<membership defaultProvider="AspNetReadOnlyXmlMembershipProvider"> 
  <providers> 
    <add name="AspNetReadOnlyXmlMembershipProvider" type="AspNetReadOnlyXmlMembershipProvider" description="Read-only XML membership provider" xmlFileName="~/App_Data/MembershipUsers.xml"/> 
  </providers> 
</membership> 

ステップ 2: 構成エントリを追加した後で、「付録」に記載のメンバーシップ プロバイダー コードを、%systemdrive%\inetpub\wwwroot\App_Code ディレクトリに XmlMembershipProvider.cs として保存する必要があります。このディレクトリが存在していない場合は、作成する必要があります。

メモ: メモ帳を使用する場合は、XmlMembershipProvider.cs.txt として保存されないようにするために、[名前を付けて保存] をクリックし、[ファイルの種類] の一覧の [すべてのファイル] を選択してください。

ステップ 3: 最後は、実際の資格情報ストアです。次の xml スニペットを、%systemdrive%\inetpub\wwwroot\App_Data ディレクトリに MembershipUsers.xml として保存します。

メモ: メモ帳を使用する場合は、MembershipUsers.xml.txt として保存されないようにするために、[名前を付けて保存] をクリックし、[ファイルの種類] の一覧の [すべてのファイル] を選択してください。

<Users>    
    <User>        
        <UserName>Bob</UserName>        
        <Email>bob@contoso.com</Email>        
    </User>    
    <User>        
        <UserName>Alice</UserName>        
        <Password>contoso!</Password>        
        <Email>alice@contoso.com</Email>        
    </User>    
</Users> 

App_Data ディレクトリが存在していない場合は、作成する必要があります。

メモ: Windows Server 2003 および Windows Vista SP1 ではセキュリティ関係の変更があったので、GAC にキャッシュされていないメンバーシップ プロバイダー用のメンバーシップ ユーザー アカウントは、IIS 7 管理ツールで作成できなくなりました。

上記の作業を完了したら、IIS 7 管理ツールを使用してアプリケーション用のユーザーの追加または削除を行います。[ファイル名を指定して実行] メニューから「INETMGR」と入力して開始します。[Default Web Site] が表示されるまで、左側のツリー ビューの [+] 記号を展開します。[Default Web Site] を選択してから、その右のウィンドウの [セキュリティ] カテゴリをクリックします。そこに [.NET ユーザー] 機能が表示されています。[.NET ユーザー] をクリックし、任意のユーザー アカウントを 1 つ以上追加します。

MembershipUsers.xml の中身を確認し、この新しく作成したユーザーを探します。

ログイン ページの作成

フォーム認証を使用するには、ログイン ページを作成する必要があります。メモ帳を開きます。wwwroot ディレクトリに確実にアクセスするには、管理者として実行する必要があります ([すべてのプログラム]、[アクセサリ] の順にクリックし、[メモ帳] アイコンを右クリックして [管理者として実行] をクリックします)。%systemdrive%\inetpub\wwwroot ディレクトリに login.aspx ファイルを作成します。メモ - login.aspx.txt として保存されないようにするために、[名前を付けて保存] をクリックし、[ファイルの種類] の一覧の [すべてのファイル] を選択してください。このファイル内に、次のコードを貼り付けます。

<%@ Page language="c#" %>    
<form id="Form1" runat="server">    
        <asp:LoginStatus runat="server" />        
        <asp:Login runat="server" />    
</form> 

これはログイン ページであり、承認規則によって特定のリソースへのアクセスが拒否されたときにこのページにリダイレクトされます。

テスト

Internet Explorer ウィンドウを開いて https://localhost/default.aspx を要求すると login.aspx にリダイレクトされます。これは、最初は認証されておらず、また前に未認証のユーザーのアクセスを保留するようにしたからです。MembershipUsers.xml に指定されているユーザー名とパスワードの組み合わせの 1 つを使用して正しくログインすると、リダイレクトされ、最初に要求した default.aspx に戻されます。このページには、現在時刻および認証に使用したユーザー ID が表示されます。

この時点で、フォーム認証、ログイン コントロール、メンバーシップを使用したカスタム認証ソリューションが正しく展開されています。これは IIS 7 で初めて登場した機能ではありません。以前のリリースの IIS の ASP.NET 2.0 から提供されています。

しかし、問題は ASP.NET で処理されるコンテンツのみが保護されるということです。

ブラウザー ウィンドウを閉じ、開き直して https://localhost/iisstart.htm を要求すると、資格情報を求めるプロンプトは表示されません。ASP.NET は、iisstart.htm のような静的ファイルに対する要求に関与しないので、フォーム認証でこのページを保護できません。クラシック ASP ページ、CGI プログラム、PHP、Perl スクリプトの場合も同じ動作になります。フォーム認証は ASP.NET 機能なので、単純にこれらのリソースに対する要求の最中は利用できません。

アプリケーション全体に対するフォーム認証の有効化

この作業では、過去のリリース上の ASP.NET の制限をなくし、アプリケーション全体に対して ASP.NET のフォーム認証および URL 認証機能を有効化します。

ASP.NET 統合の利点を活用するには、統合モードで実行されるようにアプリケーションを構成する必要があります。ASP.NET 統合モードは、アプリケーション プールごとに構成可能なので、異なるモードの ASP.NET アプリケーションを同一サーバー上で一緒にホストできます。アプリケーションを格納する既定のアプリケーション プールは既定で統合モードを使用するようになっているので、ここでの作業は必要ありません。

前に静的ページにアクセスしようとしたときに、統合モードの利点を体験できなかった理由をここで検討します。原因は、IIS 7 に付属のすべての ASP.NET モジュールに対する既定の設定にあります。

統合パイプラインの利点の活用

IIS 7 に付属のすべてのマネージ モジュール (フォーム認証、URL 認証モジュールなど) の既定の設定では、(ASP.NET) ハンドラーが管理するコンテンツのみにこれらのモジュールを適用するという前提条件が使用されます。これは、後方互換性のためです。

この前提条件を削除すると、コンテンツに関係なく、アプリケーションに対するすべての要求に対して目的のマネージ モジュールを実行できるようになります。静的ファイルをはじめとするすべてのアプリケーション コンテンツを、フォームに基づく認証を使用して保護するには、この作業が必要です。

そのためには、%systemdrive%\inetpub\wwwroot ディレクトリに存在するアプリケーションの web.config ファイルを開き、最初の <configuration> 要素の直後に次のコードを貼り付ける必要があります。

<system.webServer> 
<modules> 
    <remove name="FormsAuthenticationModule" />    
   <add name="FormsAuthenticationModule" type="System.Web.Security.FormsAuthenticationModule" />    
    <remove name="UrlAuthorization" />    
    <add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />    
    <remove name="DefaultAuthentication" />    
    <add name="DefaultAuthentication" type="System.Web.Security.DefaultAuthenticationModule" />    
</modules> 
</system.webServer> 

この構成によって、モジュール要素は前提条件なしで再度追加され、アプリケーションへのすべての要求に対してこれらのモジュールが実行されるようになります。

テスト

以前に入力した資格情報のキャッシュを消去するために、Internet Explorer のすべてのインスタンスを閉じます。Internet Explorer を開き、次の URL にあるアプリケーションに要求を送信します。

https://localhost/iisstart.htm

ログインするための login.aspx ページにリダイレクトされます。

前に使用したユーザー名とパスワードの組み合わせでログインします。正しくログインすると、リダイレクトされて元のリソースに戻され、IIS 7 の [ようこそ] ページが表示されます。

メモ: 要求したのは静的ファイルですが、リソースの保護のために、マネージ フォーム認証モジュールおよび URL 認証モジュールによってサービスが提供されます。

さらに例証するために、クラシック ASP ページを追加し、フォーム認証でそのページを保護します。

メモ帳を開きます。wwwroot ディレクトリに確実にアクセスするには、管理者として実行する必要があります ([すべてのプログラム]、[アクセサリ] の順にポイントし、[メモ帳] アイコンを右クリックして [管理者として実行] をクリックします)。%systemdrive%\inetpub\wwwroot ディレクトリに page.asp ファイルを作成します。

メモ: メモ帳を使用する場合は、page.asp.txt として保存されないようにするために、[名前を付けて保存] をクリックし、[ファイルの種類] の一覧の [すべてのファイル] を選択してください。このファイル内に次のコードを貼り付けます。

<% 
for each s in Request.ServerVariables
   Response.Write s & ": "&Request.ServerVariables(s) & VbCrLf
next
%> 

再度、すべての Internet Explorer インスタンスを閉じます (この操作を行わないと、資格情報がキャッシュされたままになります)。https://localhost/page.asp を要求すると、今度もログイン ページにリダイレクトされます。正しく認証された後で、この ASP ページが表示されます。

以上で完了です。マネージ サービスをサーバーに正しく追加し、ハンドラーに関係なくマネージ サービスがサーバーへのすべての要求に対して実行されるようになりました。

まとめ

このチュートリアルでは、ASP.NET 統合モードを活用し、強力な ASP.NET 機能を ASP.NET ページだけでなくアプリケーション全体で利用できることを実証しました。

重要な点は、使い慣れた ASP.NET 2.0 API を使用して、アプリケーションのすべてのコンテンツに対して実行できる新しいマネージ モジュールを構築できるようになり、強化された要求処理サービスのセットをアプリケーションで使用できるようにしたことです。

また、統合モードの利点の活用、および IIS 7 での ASP.NET 統合を活用する IIS 7 モジュールの開発のヒントについては、ブログ (http://www.mvolo.com/、英語) も参考になります。このブログでは、「HttpRedirection モジュールを使用して要求をアプリケーションにリダイレクトする (英語)」、「DirectoryListingModule を使用して IIS Web サイトの見やすいディレクトリ一覧を表示する (英語)」、「IconHandler を使用して ASP.NET アプリケーションで見栄えのよいファイル アイコンを表示する (英語)」、および「IIS と ASP.NET によるホット リンクの阻止 (英語)」などのページから、さまざまな IIS 7 モジュールをダウンロードできます。

        

付録

このメンバーシップ プロバイダーは、このMSDN の記事(英語)にあるサンプル XML メンバーシップ プロバイダーに基づいています。

このメンバーシップ プロバイダーを使用するには、コードを %systemdrive%\inetpub\wwwroot\App_Code ディレクトリ内に XmlMembershipProvider.cs として保存します。このディレクトリが存在していない場合は、作成する必要があります。メモ - メモ帳を使用する場合は、XmlMembershipProvider.cs.txt として保存されないようにするために、[名前を付けて保存] をクリックし、[ファイルの種類] の一覧の [すべてのファイル] を選択してください。

メモ: このメンバーシップ プロバイダーのサンプルは、例示のみを目的としています。これは実稼働用のメンバーシップ プロバイダーとしてのベスト プラクティスではなく、パスワードの安全な格納、ユーザー操作の監査などのセキュリティ要件を満たしていません。実際のアプリケーションには、このメンバーシップ プロバイダーを使用しないでください。

using System; 
using System.Xml; 
using System.Collections.Generic; 
using System.Collections.Specialized; 
using System.Configuration.Provider; 
using System.Web.Security; 
using System.Web.Hosting; 
using System.Web.Management; 
using System.Security.Permissions; 
using System.Web; 

public class AspNetReadOnlyXmlMembershipProvider : MembershipProvider 
{ 
    private Dictionary<string, MembershipUser> _Users; 
    private string _XmlFileName; 
                  // MembershipProvider Properties 

    public override string ApplicationName 
    { 
        get { throw new NotSupportedException(); } 
        set { throw new NotSupportedException(); } 
    } 

    public override bool EnablePasswordRetrieval 
    { 
        get { return false; } 
    } 

    public override bool EnablePasswordReset 
    { 
        get { return false; } 
    } 

    public override int MaxInvalidPasswordAttempts 
    { 
        get { throw new NotSupportedException(); } 
    } 

    public override int MinRequiredNonAlphanumericCharacters 
    { 
        get { throw new NotSupportedException(); } 
    } 

    public override int MinRequiredPasswordLength 
    { 
        get { throw new NotSupportedException(); } 
    } 
   
    public override int PasswordAttemptWindow 
    { 
        get { throw new NotSupportedException(); } 
    } 

    public override MembershipPasswordFormat PasswordFormat 
    { 
        get { throw new NotSupportedException(); } 
    } 

    public override string PasswordStrengthRegularExpression 
    { 
        get { throw new NotSupportedException(); } 
    } 
   
    public override bool RequiresQuestionAndAnswer 
    { 
        get { return false; } 
    } 

    public override bool RequiresUniqueEmail 
    { 
        get { throw new NotSupportedException(); } 
    } 
  
   // MembershipProvider Methods 

    public override void Initialize(string name, 
        NameValueCollection config) 
    { 
        // Verify that config isn't null 
        if (config == null) 
            throw new ArgumentNullException("config"); 

        // Assign the provider a default name if it doesn't have one 
        if (String.IsNullOrEmpty(name)) 
            name = "ReadOnlyXmlMembershipProvider"; 
  
        // Add a default "description" attribute to config if the 
        // attribute doesn't exist or is empty 
        if (string.IsNullOrEmpty(config["description"])) 
        { 
            config.Remove("description"); 
            config.Add("description", 
                "Read-only XML membership provider"); 
        } 
  
        // Call the base class's Initialize method 
        base.Initialize(name, config); 
  
        // Initialize _XmlFileName and make sure the path 
        // is app-relative 
        string path = config["xmlFileName"]; 

        if (String.IsNullOrEmpty(path)) 
            path = "~/App_Data/MembershipUsers.xml"; 

        if (!VirtualPathUtility.IsAppRelative(path)) 
            throw new ArgumentException 
                ("xmlFileName must be app-relative"); 

        string fullyQualifiedPath = VirtualPathUtility.Combine 
            (VirtualPathUtility.AppendTrailingSlash 
            (HttpRuntime.AppDomainAppVirtualPath), path); 

        _XmlFileName = HostingEnvironment.MapPath(fullyQualifiedPath); 
        config.Remove("xmlFileName"); 
  
        // Make sure we have permission to read the XML data source and 
        // throw an exception if we don't 
        FileIOPermission permission = 
            new FileIOPermission(FileIOPermissionAccess.Read, 
            _XmlFileName); 
        permission.Demand(); 
  
        // Throw an exception if unrecognized attributes remain 
        if (config.Count > 0) 
        { 
            string attr = config.GetKey(0); 
            if (!String.IsNullOrEmpty(attr)) 
                throw new ProviderException 
                    ("Unrecognized attribute: " + attr); 
        } 
    } 

    public override bool ValidateUser(string username, string password) 
    { 
        // Validate input parameters 
        if (String.IsNullOrEmpty(username) || 
            String.IsNullOrEmpty(password)) 
            return false; 
  
        // Make sure the data source has been loaded 
        ReadMembershipDataStore(); 
  
        // Validate the user name and password 
        MembershipUser user; 

        if (_Users.TryGetValue(username, out user)) 
        { 
            if (user.Comment == password) // Case-sensitive 
            { 
                return true; 
            } 
        } 

        return false; 
    } 
   
    public override MembershipUser GetUser(string username, 
        bool userIsOnline) 
    { 
  
        // Note: This implementation ignores userIsOnline 
        // Validate input parameters 

        if (String.IsNullOrEmpty(username)) 
            return null; 
  
        // Make sure the data source has been loaded 
        ReadMembershipDataStore(); 
  
        // Retrieve the user from the data source 
        MembershipUser user; 

        if (_Users.TryGetValue(username, out user)) 
            return user; 

        return null; 
    } 
   
    public override MembershipUserCollection GetAllUsers(int pageIndex, 
        int pageSize, out int totalRecords) 
    { 
        // Note: This implementation ignores pageIndex and pageSize, 
        // and it doesn't sort the MembershipUser objects returned 
        // Make sure the data source has been loaded 

        ReadMembershipDataStore(); 

        MembershipUserCollection users = 
            new MembershipUserCollection(); 

        foreach (KeyValuePair<string, MembershipUser> pair in _Users) 
            users.Add(pair.Value); 

        totalRecords = users.Count; 

        return users; 
    } 

    public override int GetNumberOfUsersOnline() 
    { 
        throw new NotSupportedException(); 
    } 

    public override bool ChangePassword(string username, 
        string oldPassword, string newPassword) 
    { 
        throw new NotSupportedException(); 
    } 

    public override bool 
        ChangePasswordQuestionAndAnswer(string username, 
        string password, string newPasswordQuestion, 
        string newPasswordAnswer) 
    { 
        throw new NotSupportedException(); 
    } 

    public override MembershipUser CreateUser(string username, 
        string password, string email, string passwordQuestion, 
        string passwordAnswer, bool isApproved, object providerUserKey, 
        out MembershipCreateStatus status) 
    { 
        throw new NotSupportedException(); 
    } 

    public override bool DeleteUser(string username, 
        bool deleteAllRelatedData) 
    { 
        throw new NotSupportedException(); 
    } 

    public override MembershipUserCollection 
        FindUsersByEmail(string emailToMatch, int pageIndex, 
        int pageSize, out int totalRecords) 
    { 
        throw new NotSupportedException(); 
    } 

    public override MembershipUserCollection 
        FindUsersByName(string usernameToMatch, int pageIndex, 
        int pageSize, out int totalRecords) 
    { 
        throw new NotSupportedException(); 
    } 

    public override string GetPassword(string username, string answer) 
    { 
        throw new NotSupportedException(); 
    } 
   
    public override MembershipUser GetUser(object providerUserKey, 
        bool userIsOnline) 
    { 
        throw new NotSupportedException(); 
    } 

    public override string GetUserNameByEmail(string email) 
    { 
        throw new NotSupportedException(); 
    } 
   
    public override string ResetPassword(string username, 
        string answer) 

    { 
        throw new NotSupportedException(); 
    } 
   
    public override bool UnlockUser(string userName) 
    { 
        throw new NotSupportedException(); 
    } 
   
    public override void UpdateUser(MembershipUser user) 
    { 
        throw new NotSupportedException(); 

    } 
   
    // Helper method 

    private void ReadMembershipDataStore() 
    { 
        lock (this) 
        { 
            if (_Users == null) 
            { 
                _Users = new Dictionary<string, MembershipUser> 
                   (16, StringComparer.InvariantCultureIgnoreCase); 
                XmlDocument doc = new XmlDocument(); 
                doc.Load(_XmlFileName); 
                XmlNodeList nodes = doc.GetElementsByTagName("User"); 
  
                foreach (XmlNode node in nodes) 
                { 
                    MembershipUser user = new MembershipUser( 
                        Name,                       // Provider name 
                        node["UserName"].InnerText, // Username 
                        null,                       // providerUserKey 
                        node["Email"].InnerText,    // Email 
                        String.Empty,               // passwordQuestion 
                        node["Password"].InnerText, // Comment 
                        true,                       // isApproved 
                        false,                      // isLockedOut 
                        DateTime.Now,               // creationDate 
                        DateTime.Now,               // lastLoginDate 
                        DateTime.Now,               // lastActivityDate 
                        DateTime.Now,               // lastPasswordChangedDate 
                        new DateTime(1980, 1, 1)    // lastLockoutDate 
                 ); 

                 _Users.Add(user.UserName, user); 

                } 
            } 
        } 
    } 
} 

関連コンテンツ

記事