1. サーバー スクリプトの基本的な概要
まず、Web サーバー ページの基本的な実行方法を確認しましょう。
1. クライアントはブラウザのアドレス バーにアドレスを入力して、サーバーにリクエストを送信します
。 2. サーバーがリクエストを受信した後、対応するサーバー側のページ (つまり、スクリプト) が実行されます。 スクリプトは、クライアントからの応答を生成し、クライアントに送り返します。
3. クライアントのブラウザーは、サーバーからの応答を受信し、その応答を解析します。 HTML を使用して、グラフィカルな Web ページをユーザーに表示します。
サーバーとクライアント間の対話には、通常、次の主な方法が使用されます。
1. フォーム: これは、ユーザー入力を取得するために使用される最も重要な方法です。フォームを送信すると、処理のためにデータがサーバーに送信されます。
2. QueryString: URL の後にパラメーターを追加することで、パラメーターがサーバーに送信されます。3. Cookie: これは、
実際には Get メソッドと同じです。
2. ASP.Net の概要
ASP、JSP などの従来のサーバー スクリプト言語は、すべて同じ方法でサーバー スクリプトを記述し、解釈またはコンパイルされて実行されるコードを埋め込みます
。
HTML で記述され、サーバー プラットフォームはこれらのコードを実行して HTML を生成します。サーブレットのライフ サイクルは実際には非常に単純です。つまり、サーブレットで記述されたすべてのコードが最初から最後まで実行されます。 Java はより複雑なコードを作成できますが、構造の観点からは JSP と変わりません。
ASP.Net の出現は、この伝統を打ち破りました。ASP.Net は、CodeBehind テクノロジとサーバー側コントロールを採用し、サーバー側イベントの概念を追加し、スクリプト言語の記述モデルを変更し、Windows プログラミングに近づけて、Web プログラミングを容易にしました。直感的ですが、ASP.Net 自体は Web プログラミングの基本モデルを変更するものではなく、一部の詳細をカプセル化し、使いやすい機能を提供するだけで、コードの作成と保守が容易になることを理解する必要があります。これが、今日説明する主なトピックである ASP.Net Web ページのライフ サイクルです。
3. ASP.Net リクエスト処理モード
ASP.Net の Web ページは Web プログラミング モードから離脱していないため、リクエスト -> リクエストの受信 -> リクエストの処理 -> レスポンスの送信という各対話モードで動作します。クライアントとの通信により新しいリクエストがトリガーされるため、Web ページのライフサイクルは 1 つのリクエストに基づいています。
IIS はクライアントから要求を受け取ると、処理のためにその要求を aspnet_wp プロセスに渡します。このプロセスは、要求されたアプリケーション ドメインが存在するかどうかを確認し、存在しない場合は、HTTP ランタイムを作成します。 HttpRuntime ) ) リクエストを処理するため、このランタイムは「現在のアプリケーションに一連の ASP.NET ランタイム サービスを提供します」(MSDN より)。
HttpRuntime がリクエストを処理するとき、一連のアプリケーション インスタンス、つまりアプリケーションのグローバル クラス (global.asax) のインスタンスが維持されます。これらのインスタンスは、リクエストがないときはアプリケーション プールに保存されます (実際には、アプリケーション プールは維持されます)。別のクラスによる場合、HttpRuntime は単なる呼び出しです)。HttpRuntime は、リクエストを受信するたびに、リクエストを処理するためにアイドル インスタンスを取得します。このインスタンスは、リクエストが完了するまで他のリクエストを処理しません。プールに戻ると、「インスタンスは存続期間中に複数のリクエストを処理するために使用されますが、一度に処理できるのは 1 つのリクエストのみです。」 (MSDN からの抜粋)
アプリケーション インスタンスがリクエストを処理するとき、インスタンスを作成します。リクエスト ページ クラスを取得し、その ProcessRequest メソッドを実行してリクエストを処理します。このメソッドは Web ページのライフ サイクルの始まりです。
4. Aspx ページと CodeBehind
ページのライフ サイクルを詳しく調べる前に、まず Aspx と CodeBehind の関係についていくつか説明します。
<%@ Page language="c#" Codebehind="WebForm.aspx.cs" Inherits="MyNamespace.WebForm" %>
CodeBehind テクノロジを使用したことのある友人なら、ASPX の先頭にあるこの文をよく知っているはずです。これを 1 つずつ分析します。
Page language="c#" 言うまでもなく、
Codebehind="WebForm.aspx.cs" この文は、バインドされたコード ファイルを示します
。 Inherits="MyNamespace.WebForm" この文は、クラス名を表します。 CodeBehind のコード ファイル内のクラスであるページによって継承されます。このクラスは System.Web.WebControls.Page から派生する必要があります。
上記のことから、実際には CodeBehind のクラスがページの基礎であることがわかります。 (ASPX) ここで、ASPX を作成するとき、いわゆる「クラス」の影が見えないのか、と尋ねる人もいるかもしれません。 ?
この問題は実際には複雑ではありません。ASP.Net プログラミングを使用している友人は、システム ディスク WINDOWSMicrosoft.NETFramework<バージョン番号>Temporary ASP.NET Files に移動し、それを ASP のすべての一時ファイルの下に置くことができます。このマシン上に存在する .Net アプリケーションの名前は、アプリケーションの名前から 2 レベル下にあります (一意性を確保するために、ASP.Net は自動的に 2 レベルのサブディレクトリを生成し、サブディレクトリの名前は次のようになります)。ランダム)、「yfy1gjhc.dll」、「xeunj5u3.dll」、「komee-bp.0.cs」、「9falckav.0.cs」ファイルなどのソースに類似したリンク ライブラリが多数あることがわかります。実際、これは ASP.Net によって動的にコンパイルされた ASPX の結果です。これらのソース ファイルを開くと、次のことがわかります。
これは、前のステートメントを裏付けています
。
, ASPX これは、ASPX ファイル名に「_aspx」接尾辞を加えた名前です。これらのコードを調べると、実際には、aspx で定義されているすべてのサーバー コントロールがこれらのコードで生成されることがわかります。これらのコードが動的に生成されると、もともと ASPX に埋め込まれていたコードが対応する場所に書き込まれます。
初めてページにアクセスすると、HTTP ランタイムはコード ジェネレーターを使用して ASPX ファイルを解析し、ソース コードを生成してコンパイルします。これが、ASPX がアクセスする理由です。とても遅いです。
この問題を説明したので、別の問題を見てみましょう。コード バインディングを使用する場合、デザイン ページ上でコントロールをドラッグし、コード ビューに切り替えると、そのコントロールを Page_Load で直接使用できます。コントロールはサブクラスで生成されるのに、なぜ親クラスで使用できるのでしょうか。直接使ってみてはどうでしょうか?
実際、VS.Net を使用してコントロールをページにドラッグすると、常に次のようなステートメントがコード バインディング ファイルに追加されることがわかり
ます
。
フィールドが保護されていると宣言し、名前が ASPX のコントロールの ID と一致していることをよく考えれば、この問題は解決されます。 ASPX のソース コードはジェネレーターによって動的に生成され、コンパイルされると前述しました。ジェネレーターは、各サーバー コントロールを動的に生成するためのコードを生成します。そうであれば、親クラスがこのコントロールを宣言しているかどうかを確認します。次のようなコードが追加されます:
this.DataGrid1 = __ctrl;
この __ctrl は、コントロールの参照を親クラスの対応する変数に割り当てます。親クラス サブクラスが宣言を呼び出せるようにする必要があるため、宣言は保護する必要があります (実際には public にすることもできます)。
次に、Page_Load が実行されると、サブクラスの初期化コードによって親クラスの宣言に値が割り当てられるため、このフィールドを使用して対応するコントロールにアクセスできるため、コントロールを使用してコード バインディングをコミットする必要はありません。指定されたファイルのコンストラクターで null 参照例外エラーが発生します。コンストラクターが最初に実行されるため、サブクラスの初期化がまだ開始されていないため、親クラスのフィールドは null 値になります。サブクラスについては後で説明します。クラスが初期化されるとき。
5. ページのライフ サイクル
3 番目のタイトルで述べた内容に戻り、HttpApplication のインスタンスがリクエストを受信してページ クラスのインスタンスを作成することについて説明しました。実際、このインスタンスは動的にコンパイルされた ASPX クラスのインスタンスです。前回のタイトルでは、ASPX は実際にはコード バインディング内のクラスのサブクラスであるため、すべての保護されたメソッドを継承することを学びました。
ここで、VS.Net によって自動的に生成された CodeBehind クラスのコードを見て、ページのライフ サイクルの説明を開始しましょう。
#region Web フォーム デザイナーが生成したコード
オーバーライド protected void OnInit(EventArgs e)
{
//
// CODEGEN: この呼び出しは、ASP.NET Web フォーム デザイナーに必要です。
//
InitializeComponent();
Base.OnInit(e);
}
/// <概要>
/// デザイナーは必要なメソッドをサポートしています - 変更にはコード エディターを使用しないでください
/// このメソッドの内容。
/// </summary>
private void InitializeComponent()
{
this.DataGrid1.ItemDataBound += 新しい System.Web.UI.WebControls.DataGridItemEventHandler(this.DataGrid1_ItemDataBound);
this.Load += 新しい System.EventHandler(this.Page_Load);
これ
は
VS.Net を使用して生成されたページのコードです。このコードには 2 つのメソッドがあり、1 つは OnInit、もう 1 つは InitializeComponent です。ページ初期化の始まり InitializeComponent には、コントロールのイベント宣言とページの Load 宣言が表示されます。
以下は MSDN から抜粋した説明と、ページ ライフ サイクル メソッドとイベント トリガーのシーケンス テーブルです。
「ASP.NET ページが要求されるたびに、サーバーは ASP.NET ページをロードし、要求が完了するとページをアンロードします。ページとそれに含まれるサーバー コントロールは、リクエストを実行し、HTML をクライアントにレンダリングする役割を果たします。クライアントとサーバー間の通信はステートレスで断続的ですが、クライアントによっては継続的なプロセスとして認識される必要があります。
「この連続性の錯覚は、ASP.NET ページ フレームワーク、ページ、およびそのコントロールによって実装されます。ポストバック後、コントロールの動作は、最後の Web リクエストが終了した場所から開始するように見える必要があります。フレームワークは実行状態の管理を相対的に行うことができます」これは簡単ですが、継続性の効果を実現するには、コントロールの開発者はコントロールの実行順序を理解し、コントロールのライフ サイクルの各段階でどのような情報が使用され、どのようなデータが保持されるかを理解する必要があります。たとえば、コントロールは、ページ上のコントロール ツリーにデータが設定されるまで、その親を呼び出すことができません。次の表は、コントロールのライフサイクルの段階の概要を示しています。表内をクリックします。リンク。"
受信 Web リクエストのライフ サイクル内で必要な設定を | 初期化する | ために、||
初期 | 化メソッドまたはイベントをオーバーライドする | アクションを実行する必要があります | |
「継承されたイベントの処理」を参照してください。 | Init イベント (OnInit メソッド) は | ||
ビュー ステートを読み込みます。 | このフェーズの終了時に、コントロールの ViewState プロパティが自動的に設定されます。詳細については、「コントロールの状態を維持する」の説明を参照してください。コントロールは、LoadViewState メソッドのデフォルト実装をオーバーライドして、カスタム状態に復元できます。 | LoadViewState メソッドは、 | |
ポストバック データを処理し | 、受信フォーム データを処理し、それに応じてプロパティを更新します。 「ポストバック データの処理」を参照してください。 注:ポストバック データを処理するコントロールのみがこのフェーズに参加します。 | LoadPostData メソッド (IPostBackDataHandler が実装されている場合) は、 | |
データベース クエリの設定など、すべてのリクエストに共通する操作を | ロードして | 実行します。この時点で、ツリー内のサーバー コントロールが作成および初期化され、状態が復元され、フォーム コントロールにクライアントのデータが反映されます。 「継承されたイベントの処理」を参照してください。 | Load イベント (OnLoad メソッド) |
ポストバック変更通知を送信する | 現在のポストバックと以前のポストバックの間の状態変化に応じて、変更イベントを発生させます。 「ポストバック データの処理」を参照してください。 注:ポストバック変更イベントを発生させるコントロールのみがこのフェーズに参加します。 | RaisePostDataChangedEvent メソッド (IPostBackDataHandler が実装されている場合) は | |
ポストバック イベントを処理し、 | ポストバックを引き起こすクライアント イベントを処理し、サーバー上で適切なイベントを発生させます。 「ポストバック イベントのキャプチャ」を参照してください。 注:ポストバック イベントを処理するコントロールのみがこのフェーズに参加します。 | RaisePostBackEvent メソッド (IPostBackEventHandler が実装されている場合) | |
プリレンダリングは、 | 出力をレンダリングする前に更新を実行します。プリレンダリング段階でのコントロールの状態への変更は保存できますが、レンダリング段階で加えられた変更は失われます。 「継承されたイベントの処理」を参照してください。 | PreRender イベント (OnPreRender メソッド) は、 | |
状態を保存し | 、コントロールの ViewState プロパティを文字列オブジェクトに自動的に永続化します。この文字列オブジェクトはクライアントに送信され、隠し変数として返されます。効率を向上させるために、コントロールは SaveViewState メソッドをオーバーライドして ViewState プロパティを変更できます。 「コントロールでの状態の維持」を参照してください。 | SaveViewState メソッドは、 | |
クライアントに提示される出力 | をレンダリングします | 。「ASP.NET サーバー コントロールのレンダリング」を参照してください。 | Render メソッドは、 |
コントロールを破棄する前に、すべての最終クリーンアップ操作を | 処理します | 。データベース リンクなどの高価なリソースへの参照は、この段階で解放する必要があります。 ASP.NET サーバー コントロールのメソッドを参照してください。 | Dispose メソッドは、 |
コントロールを破棄する前に、すべての最終クリーンアップ操作を | オフロードします | 。コントロール作成者は通常、このイベントを処理せずに Dispose でクリーンアップを実行します。 | UnLoad イベント (UnLoad メソッド時) |
この表から、呼び出されるメソッドとページのロードからアンロードまでのトリガー時間が明確にわかります。 次に、それを詳しく分析します。
上の表を見た後、注意深い友人は尋ねるかもしれません。OnInit はページのライフサイクルの始まりであり、前の講義でサブクラスに作成されるコントロールについて話しましたが、ここでは実際に InitializeComponent メソッドを使用します。 親クラスで宣言されたフィールドはすでに使用できるので、その前にサブクラスが初期化されるという意味ですか?
3 番目のタイトルで、ページ クラスの ProcessRequest が本当の意味でのページ宣言サイクルの始まりであると述べました。このメソッドは HttpApplication によって呼び出されます (呼び出しメソッドはより複雑なので、後で書く機会があります)。これについては別の記事で説明します)。ページ リクエストの処理は、このメソッドから始まります。.Net クラス ライブラリを逆コンパイルしてソース コードを表示すると、System.Web.WebControls.Page の基本クラスが見つかりました。 WebControls.TemplateControl (ページおよびユーザー コントロールです。「FrameworkInitialize」仮想メソッドが基本クラスで定義されています)、このメソッドは最初にページの ProcessRequest で呼び出されます。ASPX ソース コードでこのメソッドの痕跡が見つかりました。すべてのコントロールはジェネレーターによって生成されます。このメソッドで初期化され、このときにページのコントロール ツリーが生成されます。
次は簡単です。ページのライフ サイクルの各項目を徐々に分析してみましょう。
1. 初期化
初期化は、ページの Init イベントと OnInit メソッドに対応します。
書き換える場合、MSDN では、Init イベントのプロキシを追加する代わりに OnInti メソッドをオーバーロードすることをお勧めします。前者は親クラスの OnInit メソッドが呼び出される順序を制御できます。後者は、OnInit の後に実行されます (実際には OnInit で呼び出されます)。
2. ビュー ステートのロード
これは、2 つのリクエストの間の状態を保証するために、実際には各リクエストが ViewState を使用することがわかっています。
LoadViewState メソッドは ViewState から最後の状態を取得し、再帰を使用してページ上のコントロール ツリーの構造に従ってツリー全体を走査し、対応する状態を各コントロールに復元します。
3. ポストバックデータの処理
クライアントから返信された制御データの状態が変化したかどうかを確認する方法です。メソッドのプロトタイプ:
public virtual bool LoadPostData(string postDataKey, NameValueCollection postCollection)
postDataKey はコントロールを識別するキーワードです (つまり、postCollection の Key はポストバック データを含むコレクションです)。このメソッドをオーバーライドして確認できます。戻り値 送信されたデータが変更されたかどうか、変更されている場合は True を返します。「LoadPostData は、ポストバックによってコントロールの状態が変更された場合は true を返します。それ以外の場合は false を返します。ページ フレームワークは、true を返すすべてのコントロールを追跡し、これらのコントロールで RaisePostDataChangedEvent を呼び出します」 . "(MSDN からの抜粋)
このメソッドは System.Web.WebControls.Control で定義されており、イベントを処理する必要があるすべてのカスタム コントロールが処理する必要があるメソッドでもあります。今日説明しているページについては、そのままにしておいても問題ありません。一人で。
4. Loading は、
Load イベントと OnLoad メソッドに対応します。このイベントは、VS.Net によって生成される Page_Load メソッドによく知られていると思います。これは、すべてのリクエストに対して Load イベントに応答するメソッドです。イベントがトリガーされると、Page_Load メソッドも実行されます。これは、ほとんどの人にとって ASP.Net を理解するための最初のステップでもあると思います。
Page_Load メソッドは、System.Web.WebControl.Control クラス (このクラスは Page およびすべてのサーバー コントロールの祖先です) で定義され、OnLoad メソッドでトリガーされる Load イベントに応答します。
PageBase クラスを作成し、Page_Load でユーザー情報を検証したところ、検証が成功したかどうかに関係なく、サブクラス ページの Page_Load が常に最初に実行されることが判明したことがあります。今回は、セキュリティ上のリスクとして、ユーザーが認証されずにサブクラス内の Page_Load メソッドを実行する可能性があります。
この問題の理由は非常に単純です。Page_Load メソッドが OnInit の Load イベントに追加され、サブクラスの OnInit メソッドが最初に Load イベントを追加してから、base.OnInit を呼び出すためです。これにより、サブクラスの Page_Load が最初に追加されます。 、最初に実行されます。
この問題を解決する方法も非常に簡単です。1
) PageBase で OnLoad メソッドをオーバーロードし、次に OnLoad でユーザーを認証してから、base.OnLoad を呼び出します。これは、Load イベントが OnLoad でトリガーされるためです。 Load イベントを起動する前にユーザーを認証してください。
2) まず、サブクラスの OnInit メソッドで Base.OnInit を呼び出し、親クラスが最初に Page_Load を実行するようにします。
5. ポストバック変更通知を送信します。
このメソッドは、ステップ 3 のポストバック データの処理に対応します。 , True が返されます。ページ フレームワークはこのメソッドを呼び出してデータ変更イベントをトリガーするため、カスタム コントロールのポストバック データ変更イベントをこのメソッドでトリガーする必要があります。
同様に、この方法は Page にはあまり役に立ちません。もちろん、Page に基づいてデータ変更イベントを定義することも可能です。
6. ポストバック イベントを処理する
このメソッドは、リクエストにコントロール イベント トリガー (サーバー コントロールのイベントについては別のトピックです。近い将来説明する別の記事を書きます) に関する情報が含まれている場合に、ほとんどのサーバー コントロール イベントがトリガーされる場所です。対応するコントロールの RaisePostBackEvent メソッドが呼び出され、サーバー側イベントがトリガーされます。
ここで、もう 1 つのよくある質問があります。
ネットユーザーは、送信されたデータが変更後に変更されない理由をよく尋ねます。
ほとんどの場合、サーバー イベントがページのロード後にトリガーされることがわかります。つまり、ページは最初に Page_Load を実行し、次にボタンのクリック イベントを実行します (ここでは例としてボタンを示します)。その後、ボタン イベントの変更を処理します。これには問題があります。Page_Load は常にボタン イベントの前に実行されます。つまり、データが変更される前に、Page_Load のデータ バインディング コードが最初に実行され、元のデータがコントロールに割り当てられます。ボタンイベントが実行されますが、実際に取得されるのは元のデータなので当然更新の影響はありません。
この問題を変更するのは非常に簡単です。より合理的な方法は、データ バインディング コードをメソッドに記述することです。これを BindData:
private void BindData()
とします。
{
//データをバインドする
、
PageLoad を変更します:
private void Page_Load( object sender,EventArgs e)
{
if(!IsPostBack)
{
BindData(); //ページへの初回アクセス時にデータをバインドする}
最後
にボタン イベント:
private Button1_Click( object sender,EventArgs e )
{
//dataBindData()を更新;//データを再バインド
7.
事前レンダリングの最終リクエストの処理は、サーバーに返される応答に変換されます。これは、コントロールをレンダリングする前に、事前レンダリング段階で行われた状態変更を実行することです
。
最も典型的な例である Style 属性などのプロパティに基づいて HTML を生成します。プリレンダリングが実行されると、スタイルを保存して HTML を表示できます。レンダリング段階としてのスタイル情報。
8. 状態を保存します。
このステージはロード状態のためのものであり、リクエスト間で異なるインスタンスが処理されるため、このページとコントロールの状態を保存する必要があります。 。
9.
この時点で、ページのリクエスト処理は基本的に終了します。Render メソッドでは、ページ全体のコントロール ツリーが再帰され、Render メソッドが順番に呼び出され、対応する HTML コードが書き込まれます。最終応答ストリームに追加されます。
10. 破棄は
実際には Dispose メソッドです。この段階で、データベース接続などの占有されたリソースが解放されます。
11.
アンロードの最後に、ページは OnUnLoad メソッドを実行して UnLoad イベントをトリガーし、ページ オブジェクトが破棄される前の最終処理を処理します。実際、ASP.Net は、通常は設計上の考慮事項のためにのみこのイベントを提供します。リソースの処理は Dispose メソッドで完了するため、このメソッドは役に立ちません。
ページのライフ サイクルを簡単に紹介し、サーバー側のイベントの処理についてはあまり詳しく説明しませんでしたが、今日は主にページの実行サイクルについて理解していただきたいと思います。イベントと存続期間についてもう少し詳しく書きます。サーバー制御については今後の記事で説明します。
これらの内容は、私が ASP.Net を学習していたときに Page で調べた経験の一部です。詳細については MSDN を参照してください。ただし、初心者が犯しやすい間違いや間違いをいくつか挙げました。 、皆さんにインスピレーションを与えられれば幸いです。