Cara Memanfaatkan Alur Terintegrasi IIS 7.0

oleh Mike Volodarsky

IIS 6.0 dan versi sebelumnya memungkinkan pengembangan komponen aplikasi .NET melalui platform ASP.NET. ASP.NET terintegrasi dengan IIS melalui ekstensi ISAPI, dan mengekspos aplikasi dan model pemrosesan permintaannya sendiri. Ini secara efektif mengekspos dua alur server terpisah, satu untuk filter ISAPI asli dan komponen ekstensi, dan satu lagi untuk komponen aplikasi terkelola. ASP.NET komponen akan dijalankan sepenuhnya di dalam gelembung ekstensi ISAPI ASP.NET dan hanya untuk permintaan yang dipetakan ke ASP.NET dalam konfigurasi peta skrip IIS.

IIS 7.0 ke atas mengintegrasikan runtime ASP.NET dengan server web inti, menyediakan alur pemrosesan permintaan terpadu yang terekspos ke komponen asli dan terkelola yang dikenal sebagai modul. Banyak manfaat integrasi meliputi:

  • Mengizinkan layanan yang disediakan oleh modul asli dan terkelola untuk diterapkan ke semua permintaan, terlepas dari handler. Misalnya, Autentikasi Formulir terkelola dapat digunakan untuk semua konten, termasuk halaman ASP, CGI, dan file statis.
  • Memberdayakan komponen ASP.NET untuk menyediakan fungsionalitas yang sebelumnya tidak tersedia untuk komponen tersebut karena penempatannya di alur server. Misalnya, modul terkelola yang menyediakan fungsionalitas penulisan ulang permintaan dapat menulis ulang permintaan sebelum pemrosesan server apa pun, termasuk autentikasi.
  • Satu tempat untuk mengimplementasikan, mengonfigurasi, memantau, dan mendukung fitur server seperti modul tunggal dan konfigurasi pemetaan handler, konfigurasi kesalahan kustom tunggal, konfigurasi otorisasi url tunggal.

Artikel ini memeriksa bagaimana aplikasi ASP.NET dapat memanfaatkan mode terintegrasi di IIS 7.0 ke atas, dan mengilustrasikan tugas-tugas berikut:

  • Mengaktifkan/menonaktifkan modul pada tingkat per aplikasi.
  • Menambahkan modul aplikasi terkelola ke server, dan memungkinkannya untuk diterapkan ke semua jenis permintaan.
  • Menambahkan handler terkelola.

Pelajari selengkapnya tentang membangun modul IIS 7.0 ke atas dalam Mengembangkan Modul dan Handler IIS 7.0 dan Di Atas dengan .NET Framework.

Lihat juga blog, http://www.mvolo.com/, untuk tips selengkapnya tentang memanfaatkan mode Terintegrasi dan mengembangkan modul IIS yang memanfaatkan integrasi ASP.NET di IIS 7.0 ke atas. Di sana, unduh sejumlah modul tersebut termasuk Mengalihkan permintaan ke aplikasi Anda dengan modul HttpRedirection, Daftar direktori yang bagus untuk situs web IIS Anda dengan DirectoryListingModule, dan Menampilkan ikon file cantik di aplikasi ASP.NET Anda dengan IconHandler.

Prasyarat

Untuk mengikuti langkah-langkah dalam dokumen ini, fitur IIS 7.0 ke atas berikut harus diinstal.

ASP.NET

Instal ASP.NET melalui Panel Kontrol Windows Vista. Pilih "Program dan Fitur" - "Aktifkan atau nonaktifkan fitur Windows". Kemudian buka "Layanan Informasi Internet" - "World Wide Web Services" - "Fitur Pengembangan Aplikasi" dan periksa "ASP.NET".

Jika Anda memiliki build Windows ServerĀ® 2008, buka "Manajer Server" - "Peran" dan pilih "Server Web (IIS)". Klik "Tambahkan layanan peran". Di bagian "Pengembangan Aplikasi", periksa "ASP.NET".

ASP Klasik

Kami ingin menunjukkan bagaimana modul ASP.NET sekarang bekerja dengan semua konten dan bukan hanya ASP.NET halaman, jadi instal ASP klasik melalui Panel Kontrol Windows Vista. Pilih "Program" - "Aktifkan atau nonaktifkan fitur Windows". Kemudian buka "Layanan Informasi Internet" - "World Wide Web Services" - "Fitur Pengembangan Aplikasi" dan periksa "ASP".

Jika Anda memiliki build Windows Server 2008, buka "Manajer Server" - "Peran" dan pilih "Server Web (IIS)". Klik "Tambahkan layanan peran". Di bagian "Pengembangan Aplikasi", periksa "ASP".

Menambahkan Autentikasi Formulir ke Aplikasi Anda

Sebagai bagian dari tugas ini, kami mengaktifkan Autentikasi berbasis Formulir ASP.NET untuk aplikasi. Dalam tugas berikutnya, kami mengaktifkan modul Autentikasi Formulir untuk dijalankan untuk semua permintaan ke aplikasi Anda, terlepas dari jenis kontennya.

Pertama, konfigurasikan autentikasi formulir seperti yang Anda lakukan untuk aplikasi ASP.NET normal.

Membuat Halaman Sampel

Untuk mengilustrasikan fitur ini, kami menambahkan halaman default.aspx ke direktori akar web. Buka notepad (untuk memastikan Anda memiliki akses ke direktori wwwroot di bawah ini, Anda harus menjalankan sebagai administrator--klik kanan pada ikon Programs\Accessories\Notepad, dan klik "Jalankan sebagai administrator"), dan buat file berikut: %systemdrive%\inetpub\wwwroot\default.aspx. Tempelkan baris berikut ke dalamnya:

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

Semua default.aspx menampilkan waktu saat ini dan nama pengguna yang masuk. Kami menggunakan halaman ini nanti untuk menampilkan autentikasi formulir dalam tindakan.

Mengonfigurasi Autentikasi Formulir dan Aturan Access Control

Sekarang, untuk melindungi default.aspx dengan autentikasi formulir. Buat file web.config di %systemdrive%\inetpub\wwwroot direktori dan tambahkan konfigurasi yang ditunjukkan di bawah ini:

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

Konfigurasi ini mengatur mode autentikasi ASP.NET untuk menggunakan autentikasi berbasis formulir, dan menambahkan pengaturan otorisasi untuk mengontrol akses ke aplikasi. Pengaturan ini menolak akses ke pengguna anonim (?) dan hanya mengizinkan pengguna terautentikasi (*).

Membuat Penyedia Keanggotaan

Langkah 1: Kita harus menyediakan penyimpanan autentikasi tempat kredensial pengguna akan diverifikasi. Untuk mengilustrasikan integrasi mendalam antara ASP.NET dan IIS 7.0 ke atas, kami menggunakan penyedia Keanggotaan berbasis XML kami sendiri (Anda juga dapat menggunakan Penyedia Keanggotaan SQL Server default jika SQL Server diinstal).

Tambahkan entri berikut tepat setelah elemen konfigurasi konfigurasi> awal</<system.web> dalam file web.config:

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

Langkah 2: Setelah entri konfigurasi ditambahkan, Anda harus menyimpan kode penyedia Keanggotaan yang disediakan dalam Lampiran sebagai XmlMembershipProvider.cs di direktori Anda%systemdrive%\inetpub\wwwroot\App_Code. Jika direktori ini tidak ada, Anda harus membuatnya.

Catatan

Jika menggunakan Notepad, pastikan untuk mengatur Simpan Sebagai: Semua File untuk mencegah file disimpan sebagai XmlMembershipProvider.cs.txt.

Langkah 3: Yang tersisa hanyalah penyimpanan kredensial aktual. Simpan cuplikan xml di bawah ini sebagai file MembershipUsers.xml di %systemdrive%\inetpub\wwwroot\App_Data direktori.

Catatan

Jika menggunakan Notepad, pastikan untuk mengatur Simpan Sebagai: Semua File untuk mencegah file disimpan sebagai MembershipUsers.xml.txt.

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

Jika direktori App_Data tidak ada, Anda harus membuatnya.

Catatan

Karena perubahan keamanan di Windows Server 2003 dan Windows Vista SP1, Anda tidak dapat lagi menggunakan alat Administrasi IIS untuk membuat akun pengguna Keanggotaan untuk penyedia Keanggotaan non-GACed.

Setelah menyelesaikan tugas ini, buka alat Administrasi IIS dan tambahkan atau hapus pengguna untuk aplikasi Anda. Mulai "INETMGR" dari "Jalankan..." Menu. Buka tanda "+" di tampilan pohon di sebelah kiri hingga "Situs Web Default" ditampilkan. Pilih "Situs Web Default" lalu pindah ke kanan dan klik kategori "Keamanan". Fitur yang tersisa menampilkan ".NET Users". Klik ".NET Users" dan tambahkan satu atau beberapa akun pengguna pilihan Anda.

Lihat di MembershipUsers.xml untuk menemukan pengguna yang baru dibuat.

Membuat Halaman Masuk

Untuk menggunakan autentikasi formulir, kita harus membuat halaman masuk. Buka notepad (Untuk memastikan Anda memiliki akses ke direktori wwwroot di bawah ini, Anda perlu menjalankan sebagai administrator dengan mengklik kanan ikon Programs\Accessories\Notepad, dan mengklik "Jalankan sebagai administrator"), dan buat file login.aspx di %systemdrive%\inetpub\wwwroot direktori. Catatan - pastikan untuk mengatur Simpan Sebagai: Semua File untuk mencegah file disimpan sebagai login.aspx.txt. Tempelkan baris berikut ke dalamnya:

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

Ini adalah halaman masuk tempat Anda dialihkan ketika aturan otorisasi Anda menolak akses ke sumber daya tertentu.

Pengujian

Buka Jendela Internet Explorer dan minta http://localhost/default.aspx. Anda melihat bahwa Anda dialihkan ke login.aspx, karena awalnya Anda tidak diautentikasi, dan kami menahan akses ke pengguna yang tidak diautentikasi sebelumnya. Jika Anda berhasil masuk dengan salah satu pasangan nama pengguna/kata sandi yang ditentukan dalam MembershipUsers.xml, Anda akan diarahkan kembali ke halaman default.aspx yang awalnya diminta. Halaman ini kemudian memperlihatkan waktu saat ini dan identitas pengguna yang Anda autentikasi.

Pada titik ini, kami telah berhasil menyebarkan solusi autentikasi kustom menggunakan Autentikasi Formulir, Kontrol masuk, dan Keanggotaan. Fungsionalitas ini bukan yang baru di IIS 7.0 atau lebih tinggi - fungsi ini telah tersedia sejak ASP.NET 2.0 pada rilis IIS sebelumnya.

Namun, masalahnya adalah bahwa hanya konten yang ditangani oleh ASP.NET yang dilindungi.

Jika Anda menutup dan membuka kembali jendela browser, dan meminta http://localhost/iisstart.htm, Anda tidak dimintai kredensial. ASP.NET tidak berpartisipasi dalam permintaan file statis seperti iisstart.htm. Oleh karena itu, ia tidak dapat melindunginya dengan autentikasi formulir. Anda melihat perilaku yang sama dengan halaman ASP klasik, program CGI, PHP atau skrip Perl. Autentikasi formulir adalah fitur ASP.NET, dan tidak tersedia selama permintaan ke sumber daya tersebut.

Mengaktifkan Autentikasi Formulir untuk Seluruh Aplikasi

Dalam tugas ini, kami menghilangkan batasan ASP.NET pada rilis sebelumnya, dan mengaktifkan fungsionalitas Autentikasi dan Otorisasi Url Formulir ASP.NET untuk seluruh aplikasi.

Untuk memanfaatkan integrasi ASP.NET, aplikasi kami harus dikonfigurasi untuk berjalan dalam mode Terintegrasi. Mode integrasi ASP.NET dapat dikonfigurasi per kumpulan aplikasi, memungkinkan aplikasi ASP.NET dalam mode yang berbeda untuk dihosting berdampingan di server yang sama. Kumpulan aplikasi default tempat aplikasi kita tinggal sudah menggunakan mode Terintegrasi secara default, jadi kita tidak perlu melakukan apa pun di sini.

Jadi, mengapa kita gagal mengalami manfaat mode Terintegrasi ketika kita mencoba mengakses halaman statis sebelumnya? Jawabannya terletak pada pengaturan default untuk semua modul ASP.NET yang dikirim dengan IIS 7.0 ke atas.

Memanfaatkan Alur Terintegrasi

Konfigurasi default untuk semua modul terkelola yang dikirim dengan IIS 7.0 ke atas, termasuk modul Autentikasi Formulir dan Otorisasi URL, menggunakan prasyarat sehingga modul ini hanya berlaku untuk konten yang dikelola penangan (ASP.NET). Ini dilakukan untuk alasan kompatibilitas mundur.

Dengan menghapus prasyarat, kami membuat modul terkelola yang diinginkan dijalankan untuk semua permintaan ke aplikasi, terlepas dari kontennya. Ini diperlukan untuk melindungi file statis kami, dan konten aplikasi lainnya dengan autentikasi berbasis Formulir.

Untuk melakukan ini, buka file web.config aplikasi yang terletak di %systemdrive%\inetpub\wwwroot direktori, dan tempelkan baris berikut tepat di bawah elemen konfigurasi> pertama<:

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

Konfigurasi ini menambahkan kembali elemen modul tanpa prasyarat, memungkinkannya untuk mengeksekusi semua permintaan ke aplikasi.

Pengujian

Tutup semua instans Internet Explorer agar kredensial yang dimasukkan sebelumnya tidak lagi di-cache. Buka Internet Explorer, dan buat permintaan ke aplikasi di URL berikut:

http://localhost/iisstart.htm

Anda diarahkan ke halaman login.aspx untuk masuk.

Masuk dengan pasangan nama pengguna/kata sandi yang digunakan sebelumnya. Ketika Anda berhasil masuk, Anda dialihkan kembali ke sumber daya asli, yang menampilkan halaman selamat datang IIS.

Catatan

Meskipun Anda meminta file statis, modul autentikasi formulir terkelola dan modul otorisasi URL menyediakan layanan mereka untuk melindungi sumber daya Anda.

Untuk mengilustrasikan ini lebih lanjut, kami menambahkan halaman ASP klasik dan melindunginya dengan Autentikasi Formulir.

Buka notepad (untuk memastikan Anda memiliki akses ke direktori wwwroot di bawah ini, Anda harus menjalankan sebagai administrator--klik kanan ikon Programs\Accessories\Notepad, dan klik "Jalankan sebagai administrator"), dan buat file page.asp di direktori Anda %systemdrive%\inetpub\wwwroot .

Catatan

Jika menggunakan Notepad, pastikan untuk mengatur Simpan Sebagai: Semua File untuk mencegah file disimpan sebagai page.asp.txt. Tempelkan baris di bawah ini ke dalamnya:

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

Tutup semua instans Internet Explorer lagi-- jika tidak, kredensial Anda masih di-cache dan meminta http://localhost/page.asp. Anda kembali diarahkan ke halaman masuk, dan setelah autentikasi berhasil, tampilkan halaman ASP.

Selamat - Anda telah berhasil menambahkan layanan terkelola ke server, memungkinkan mereka untuk semua permintaan ke server terlepas dari handler!

Ringkasan

Panduan ini menunjukkan bagaimana mode ASP.NET Terintegrasi dapat dimanfaatkan untuk membuat fitur ASP.NET yang kuat tersedia untuk tidak hanya ASP.NET halaman, tetapi untuk seluruh aplikasi.

Lebih penting lagi, Anda sekarang dapat membangun modul terkelola baru menggunakan API ASP.NET 2.0 yang akrab yang memiliki kemampuan untuk mengeksekusi untuk semua konten aplikasi, dan menyediakan serangkaian layanan pemrosesan permintaan yang ditingkatkan ke aplikasi Anda.

Jangan ragu untuk memeriksa blog, https://www.mvolo.com/, untuk tips lebih lanjut tentang memanfaatkan mode Terintegrasi dan mengembangkan modul IIS yang memanfaatkan integrasi ASP.NET di IIS 7 ke atas. Di sana, Anda juga dapat mengunduh sejumlah modul tersebut termasuk Mengalihkan permintaan ke aplikasi Anda dengan modul HttpRedirection, Daftar direktori yang terlihat bagus untuk situs web IIS Anda dengan DirectoryListingModule, dan Menampilkan ikon file cantik di aplikasi ASP.NET Anda dengan IconHandler.

Lampiran

Penyedia Keanggotaan ini didasarkan pada sampel penyedia keanggotaan XML yang ditemukan di Penyedia Keanggotaan ini.

Untuk menggunakan penyedia Keanggotaan ini, simpan kode sebagai XmlMembershipProvider.cs di direktori Anda %systemdrive%\inetpub\wwwroot\App\_Code . Jika direktori ini tidak ada, Anda harus membuatnya. Catatan - pastikan untuk mengatur Simpan Sebagai: Semua File jika menggunakan Notepad untuk mencegah file disimpan sebagai XmlMembershipProvider.cs.txt.

Catatan

Sampel penyedia keanggotaan ini hanya untuk tujuan demo ini. Ini tidak sesuai dengan praktik terbaik dan persyaratan keamanan untuk penyedia Keanggotaan produksi, termasuk menyimpan kata sandi dengan aman dan mengaudit tindakan pengguna. Jangan gunakan penyedia keanggotaan ini di aplikasi Anda!

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

                } 
            } 
        } 
    } 
}