Mengembangkan Modul C\C++ Asli untuk IIS 7.0

oleh Mike Volodarsky

Pendahuluan

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 > Registrasi Visual Studio > Registrasi 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 fabrikan modul, dan mendaftarkan modul untuk satu atau beberapa event server.
  • Implementasi kelas modul yang mewarisi dari kelas dasar CHttpModule . Kelas ini menyediakan fungsionalitas utama modul Anda.
  • Implementasi kelas pabrik modul yang mengimplementasikan antarmuka IHttpModuleFactory . Kelas bertanggung jawab untuk membuat instance dari modul Anda.

Nota

Dalam beberapa kasus, Anda juga dapat menerapkan 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, server akan memuat DLL yang berisi modul Anda, dan akan 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 dari kelas modul Anda menggunakan fungsi pembuat 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. Signature dan seluruh 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 cara 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 dalam panduan ini. Pabrik ini bertanggung jawab atas produksi instance 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 instans modul yang akan digunakan untuk permintaan ini. Implementasi hanya mengembalikan instans baru kelas modul kami, CMyHttpModule, yang kami terapkan berikutnya. Seperti yang akan kita lihat segera, ini memungkinkan kita untuk dengan mudah menyimpan status permintaan tanpa khawatir terhadap keamanan utas, karena server selalu menggunakan instans modul baru 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 dijalankan oleh server ketika proses kerja dimatikan untuk membersihkan modul secara menyeluruh pada akhir proses. Jika Anda menginisialisasi status global apa pun di RegisterModule, terapkan pembersihannya dalam metode ini.

Mengimplementasikan 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 tersebut 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 membebaskan thread yang menangani permintaan agar dapat digunakan kembali untuk permintaan lain. Eksekusi asinkron tidak dibahas dalam artikel ini.

Kelas modul kami mengambil alih metode penanganan aktivitas OnAcquireRequestState. Untuk menyediakan fungsionalitas dalam salah satu tahap alur, kelas modul harus mengambil alih 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 sintaks metode dari metode overriding sama persis dengan metode kelas dasar dari kelas CHttpModule yang Anda override.

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, harus 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 > Program > Aksesoris, Klik kanan pada Command Prompt, 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 menambahkan modul dengan menggunakan GUI. Buka Menu Start>Run, 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> dalam 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 lebih lanjut 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.