Mengembangkan Modul C\C++ Asli untuk IIS 7.0

oleh Mike Volodarsky

Pengantar

IIS 7.0 ke atas memungkinkan untuk memperluas server berdasarkan modul yang dikembangkan dengan dua cara:

  • Menggunakan kode terkelola, dan API ekstensibilitas server ASP.NET
  • Menggunakan kode asli, dan API ekstensibilitas server asli IIS

Tidak seperti versi IIS sebelumnya, sebagian besar skenario ekstensibilitas server tidak memerlukan pengembangan kode asli (C++), dan dapat diakomodasi menggunakan kode terkelola dan API ASP.NET. Menggunakan ASP.NET untuk memperluas server memungkinkan Anda mengurangi waktu pengembangan secara dramatis, dan memanfaatkan fungsionalitas ASP.NET dan .NET Framework yang kaya. Untuk mempelajari selengkapnya tentang memperluas IIS dengan ASP.NET, lihat Mengembangkan Modul IIS dengan .NET.

IIS juga menyediakan API server inti asli (C++), yang menggantikan API filter dan ekstensi ISAPI dari rilis IIS sebelumnya. Jika Anda memiliki persyaratan khusus yang menuntut pengembangan kode asli, atau ingin mengonversi komponen ISAPI asli yang ada, manfaatkan API ini untuk membangun komponen server. API server asli baru menampilkan pengembangan berorientasi objek dengan model objek intuitif, memberikan kontrol lebih besar atas pemrosesan permintaan, dan menggunakan pola desain yang lebih sederhana untuk membantu Anda menulis kode yang kuat.

Panduan ini memeriksa tugas-tugas berikut:

  • Mengembangkan modul asli menggunakan API server asli (C++)
  • Menyebarkan modul asli di server

Untuk mengkompilasi modul, Anda harus menginstal Platform SDK yang berisi file header IIS. Windows Vista Platform SDK terbaru tersedia di sini.

Untuk menggunakan Platform SDK dengan Visual Studio 2005, Anda harus mendaftarkan SDK. Setelah Anda menginstal SDK, lakukan ini melalui Mulai > Program > Microsoft Windows SDK > Visual Studio Registration > Daftarkan Direktori Windows SDK dengan Visual Studio.

Kode sumber untuk modul ini tersedia di Sampel Modul Asli Visual Studio IIS7.

Mengembangkan Modul Asli

Dalam tugas ini, kami memeriksa pengembangan modul asli menggunakan API server asli (C++) baru. Modul asli adalah DLL Windows yang berisi hal berikut:

  • Fungsi yang diekspor RegisterModule. Fungsi ini bertanggung jawab untuk membuat pabrik modul, dan mendaftarkan modul untuk satu atau beberapa peristiwa server.
  • Implementasi kelas modul yang mewarisi dari kelas dasar CHttpModule . Kelas ini menyediakan fungsi utama modul Anda.
  • Implementasi kelas pabrik modul yang mengimplementasikan antarmuka IHttpModuleFactory . Kelas bertanggung jawab untuk membuat instans modul Anda.

Catatan

Dalam beberapa kasus, Anda juga dapat mengimplementasikan antarmuka IGlobalModule , untuk memperluas beberapa fungsionalitas server yang tidak terkait dengan pemrosesan permintaan. Ini adalah topik lanjutan dan tidak tercakup dalam panduan ini.

Modul asli Anda memiliki siklus hidup berikut:

  1. Ketika proses pekerja server dimulai, itu akan memuat DLL yang berisi modul Anda, dan memanggil fungsi RegisterModule yang diekspor. Dalam fungsi ini, Anda:

    a. Buat pabrik modul.
    b. Daftarkan pabrik modul untuk peristiwa alur permintaan yang diterapkan modul Anda.

  2. Ketika permintaan tiba, server:

    a. Membuat instans kelas modul Anda menggunakan pabrik yang Anda sediakan.
    b. Memanggil metode penanganan aktivitas yang sesuai pada instans modul untuk setiap peristiwa permintaan yang Anda daftarkan.
    c. Membuang instans modul di akhir pemrosesan permintaan.

Sekarang, untuk membangunnya.

Kode sumber lengkap untuk modul tersedia di Sampel Modul Asli Visual Studio IIS7. Langkah-langkah di bawah ini adalah yang paling penting untuk mengembangkan modul, dan tidak termasuk kode pendukung dan penanganan kesalahan.

Terapkan fungsi RegisterModule yang dipanggil server saat DLL modul dimuat. Tanda tangannya dan sisa API asli didefinisikan dalam file header httpserv.h , yang merupakan bagian dari Platform SDK (jika Anda tidak memiliki Platform SDK, silakan lihat Pengantar untuk informasi tentang mendapatkannya):

main.cpp:

HRESULT        
__stdcall        
RegisterModule(        
    DWORD                           dwServerVersion,    
    IHttpModuleRegistrationInfo *   pModuleInfo,
    IHttpServer *                   pHttpServer            
)
{
   // step 1: save the IHttpServer and the module context id for future use 
    g_pModuleContext = pModuleInfo->GetId();
    g_pHttpServer = pHttpServer;

    // step 2: create the module factory 
    pFactory = new CMyHttpModuleFactory();

    // step 3: register for server events 
    hr = pModuleInfo->SetRequestNotifications( pFactory, 
                                              RQ_ACQUIRE_REQUEST_STATE,
                                               0 );            
}

The RegisterModule

Ada tiga tugas dasar yang perlu kita selesaikan di dalam RegisterModule:

Simpan Status Global

Kami akan menyimpan instans server global, dan id konteks modul untuk digunakan nanti dalam variabel global. Meskipun contoh ini tidak menggunakan informasi ini, banyak modul merasa berguna untuk menyimpan dan menggunakannya nanti selama pemrosesan permintaan. Antarmuka IHttpServer menyediakan akses ke banyak fungsi server, seperti membuka file, dan mengakses cache. Id konteks modul digunakan untuk mengaitkan status modul kustom dengan beberapa objek server, seperti permintaan dan aplikasi.

Membuat Pabrik Modul

Kami akan menerapkan kelas pabrik kami, CMyHttpModuleFactory, nanti di panduan ini. Pabrik ini bertanggung jawab untuk memproduksi instans modul kami untuk setiap permintaan.

Daftarkan Module Factory untuk Peristiwa Pemrosesan Permintaan yang Diinginkan

Pendaftaran dilakukan melalui metode SetRequestNotificatons , yang menginstruksikan server: untuk membuat instans modul kami untuk setiap permintaan menggunakan pabrik yang ditentukan; dan, untuk memanggil penanganan aktivitas yang sesuai di atasnya untuk setiap tahap pemrosesan permintaan yang ditentukan.

Dalam hal ini, kami hanya tertarik pada tahap RQ_ACQUIRE_REQUEST_STATE. Daftar lengkap tahapan yang terdiri dari alur pemrosesan permintaan ditentukan dalam httpserv.h:

#define RQ_BEGIN_REQUEST               0x00000001 // request is beginning 
#define RQ_AUTHENTICATE_REQUEST        0x00000002 // request is being authenticated             
#define RQ_AUTHORIZE_REQUEST           0x00000004 // request is being authorized 
#define RQ_RESOLVE_REQUEST_CACHE       0x00000008 // satisfy request from cache 
#define RQ_MAP_REQUEST_HANDLER         0x00000010 // map handler for request 
#define RQ_ACQUIRE_REQUEST_STATE       0x00000020 // acquire request state 
#define RQ_PRE_EXECUTE_REQUEST_HANDLER 0x00000040 // pre-execute handler 
#define RQ_EXECUTE_REQUEST_HANDLER     0x00000080 // execute handler 
#define RQ_RELEASE_REQUEST_STATE       0x00000100 // release request state 
#define RQ_UPDATE_REQUEST_CACHE        0x00000200 // update cache 
#define RQ_LOG_REQUEST                 0x00000400 // log request 
#define RQ_END_REQUEST                 0x00000800 // end request

Selain itu, Anda dapat berlangganan beberapa peristiwa non-deterministik yang mungkin terjadi selama pemrosesan permintaan karena tindakan yang diambil modul lain, seperti membersihkan respons terhadap klien:

#define RQ_CUSTOM_NOTIFICATION         0x10000000 // custom notification 
#define RQ_SEND_RESPONSE               0x20000000 // send response 
#define RQ_READ_ENTITY                 0x40000000 // read entity 
#define RQ_MAP_PATH                    0x80000000 // map a url to a physical path

Agar implementasi RegisterModule kami dapat diakses oleh server, kita harus mengekspornya. Gunakan . File DEF yang berisi kata kunci EXPORTS untuk mengekspor fungsi RegisterModule kami.

Selanjutnya, terapkan kelas pabrik modul:

mymodulefactory.h:

class CMyHttpModuleFactory : public IHttpModuleFactory
{
public:
    virtual HRESULT GetHttpModule(
        OUT CHttpModule            **ppModule, 
        IN IModuleAllocator        *
    )
            
    {
    }

   virtual void Terminate()
    {
    }

};

Pabrik modul mengimplementasikan antarmuka IHttpModuleFactory , dan berfungsi untuk membuat instans modul pada setiap permintaan.

Server memanggil metode GetHttpModule di awal setiap permintaan untuk mendapatkan contoh modul yang akan digunakan untuk permintaan ini. Implementasinya hanya mengembalikan instans baru kelas modul kami, CMyHttpModule, yang kami terapkan berikutnya. Seperti yang kita lihat segera, ini memungkinkan kita untuk menyimpan status permintaan dengan mudah tanpa khawatir tentang keamanan utas, karena server selalu membuat dan menggunakan instans baru modul untuk setiap permintaan.

Implementasi pabrik yang lebih canggih dapat memutuskan untuk menggunakan pola singleton alih-alih membuat instans baru setiap kali, atau menggunakan antarmuka IModuleAllocator yang disediakan untuk mengalokasikan memori modul di kumpulan permintaan. Pola lanjutan ini tidak dibahas dalam panduan ini.

Metode Hentikan dipanggil oleh server ketika proses pekerja dimatikan untuk melakukan pembersihan akhir modul. Jika Anda menginisialisasi status global apa pun di RegisterModule, terapkan pembersihannya dalam metode ini.

Menerapkan Kelas Modul

Kelas ini bertanggung jawab untuk menyediakan fungsionalitas utama modul selama satu atau beberapa peristiwa server:

myhttpmodule.h:

class CMyHttpModule : public CHttpModule
{
public:
    REQUEST_NOTIFICATION_STATUS
    OnAcquireRequestState(
        IN IHttpContext *                       pHttpContext,
        IN OUT IHttpEventProvider *             pProvider
    );
};

Kelas modul mewarisi dari kelas dasar CHttpModule , yang menentukan metode penanganan aktivitas untuk setiap peristiwa server yang dibahas sebelumnya. Ketika alur pemrosesan permintaan menjalankan setiap peristiwa, alur ini memanggil metode penanganan aktivitas terkait pada setiap instans modul yang telah mendaftar untuk peristiwa tersebut.

Setiap metode penanganan aktivitas memiliki tanda tangan berikut:

REQUEST_NOTIFICATION_STATUS
    OnEvent(
        IN IHttpContext *                       pHttpContext,
        IN OUT IHttpEventProvider *             pProvider
    );

Antarmuka IHttpContext menyediakan akses ke objek konteks permintaan, yang dapat digunakan untuk melakukan tugas pemrosesan permintaan seperti memeriksa permintaan, dan memanipulasi respons.

Antarmuka IHttpEventProvider diganti dengan antarmuka yang lebih spesifik untuk setiap peristiwa yang menyediakan fungsionalitas khusus untuk modul. Misalnya, penanganan aktivitas OnAuthenticateRequest menerima antarmuka IAuthenticationProvider yang memungkinkan modul untuk mengatur pengguna yang diautentikasi.

Pengembalian setiap metode penanganan aktivitas adalah salah satu nilai enumerasi REQUEST_NOTIFICATION_STATUS. Anda harus mengembalikan RQ_NOTIFICATION_CONTINUE jika modul berhasil melakukan tugas; alur harus melanjutkan eksekusi.

Jika terjadi kegagalan dan Anda ingin membatalkan pemrosesan permintaan dengan kesalahan, Anda harus mengatur status kesalahan dan mengembalikan RQ_NOTIFICATION_FINISH_REQUEST. Pengembalian RQ_NOTIFICATION_PENDING memungkinkan Anda untuk melakukan pekerjaan secara asinkron, dan melepaskan utas yang memproses permintaan sehingga dapat digunakan kembali untuk permintaan lain. Eksekusi asinkron tidak dibahas dalam artikel ini.

Kelas modul kami mengambil alih metode penanganan aktivitas OnAcquireRequestate. Untuk menyediakan fungsionalitas dalam salah satu tahap alur, kelas modul harus mengganti metode penanganan aktivitas masing-masing. Jika Anda mendaftar untuk peristiwa di RegisterModule, tetapi tidak mengambil alih metode penanganan aktivitas yang sesuai pada kelas modul Anda, modul Anda akan gagal pada runtime (dan memicu pernyataan waktu debug jika dikompilasi dalam mode debug). Berhati-hatilah dan pastikan bahwa tanda tangan metode dari metode penimpaan sama persis dengan metode kelas dasar kelas CHttpModule yang Anda timpa.

Mengkompilasi Modul

Ingat, Anda memerlukan Platform SDK untuk mengkompilasi. Lihat Pengantar untuk informasi selengkapnya tentang mendapatkannya dan mengaktifkan Visual Studio untuk mereferensikannya.

Menyebarkan Modul Asli

Setelah mengkompilasi modul, Anda harus menyebarkannya di server. Kompilasi modul, lalu salin IIS7NativeModule.dll (dan file simbol debugging IIS7NativeModule.pdb jika diinginkan) ke lokasi mana pun di komputer yang menjalankan IIS.

Modul asli, tidak seperti modul terkelola yang dapat ditambahkan langsung ke aplikasi, perlu terlebih dahulu diinstal di server. Ini memerlukan hak istimewa Administratif.

Untuk menginstal modul asli, Anda memiliki beberapa opsi:

  • Menggunakan alat baris perintah APPCMD.EXE
    APPCMD membuat penginstalan modul menjadi sederhana. Buka Mulai>Aksesori Program>, Klik kanan pada Prompt Baris Perintah, dan pilih Jalankan Sebagai Administrator. Di jendela baris perintah, jalankan hal berikut:
    %systemroot%\system32\inetsrv\appcmd.exe install module /name:MyModule /image:[FULL\_PATH\_TO\_DLL]
    Di mana [FULL_PATH_TO_DLL] adalah jalur lengkap ke DLL yang dikompilasi yang berisi modul yang baru saja Anda buat.
  • Menggunakan Alat Administrasi IIS
    Ini memungkinkan Anda untuk menambahkan modul dengan menggunakan GUI. Buka Mulai>Jalankan, ketik inetmgr, dan tekan Enter. Sambungkan ke localhost, temukan tugas Modul, dan klik dua kali untuk membukanya. Lalu, klik tugas Tambahkan Modul Asli di panel kanan.
  • Menginstal modul secara manual
    Instal modul secara manual dengan menambahkannya ke <bagian konfigurasi system.webServer>/<globalModules> di file konfigurasi applicationHost.config, dan tambahkan referensi ke dalamnya di <bagian konfigurasi system.webServer>/<modules> dalam file yang sama untuk mengaktifkannya. Kami menyarankan agar Anda menggunakan salah satu dari dua opsi sebelumnya untuk menginstal modul alih-alih mengedit konfigurasi secara langsung.

Tugas selesai--kami telah selesai mengonfigurasi modul asli baru.

Ringkasan

Dalam panduan ini, Anda mempelajari cara mengembangkan dan menyebarkan modul asli kustom menggunakan API ekstensibilitas asli (C++) baru. Silakan lihat Ringkasan Pengembangan Native-Code untuk mempelajari selengkapnya tentang API server asli (C++).

Untuk mempelajari tentang memperluas IIS menggunakan kode terkelola dan kerangka kerja .NET, lihat Mengembangkan modul IIS Dengan .NET. Untuk mempelajari selengkapnya tentang mengelola modul IIS, lihat laporan resmi gambaran umum modul.