次の方法で共有


ASP から ASP.NET への変換

Microsoft .NET へのアップグレード

Scott Mitchell
4guysfromrolla.com

November 2001
日本語版最終更新日 2002 年 1 月 30 日

目標

  • ASP と ASP.NET を同じ Web サーバー上で実行する
  • 一般的な ASP アプリケーションの内容を検討する
  • ASP アプリケーションを ASP.NET に移植する

前提

このドキュメントを活用するためには、読者の側に以下の条件が必要となります。

  • Visual Basic のプログラミング概念と用語を知っていること。
  • ASP についての知識があること。

同じ Web サーバー上での ASP と ASP.NET の実行

ASP.NET を使い始めて最初に気づくことの 1 つが、ファイル拡張子が新しくなったことでしょう。ASP では .asp という拡張子が使用されていましたが、ASP.NET ページは .aspx という拡張子を使用します。さらに、ASP.NET ページが要求されると、IIS はその要求を aspnet_wp.exe プロセスに渡しますが、ASP では asp.dll が使用されます。

ASP と ASP.NET は、同じ Web サーバー上で使用することができます。つまり、Web サイトや Web サイト内のアプリケーションは、ASP.NET ページと ASP ページの両方を含むことができます。ASP ページと ASP.NET ページには同じ Web サーバーからアクセスできるので、既存の ASP ページを ASP.NET 互換のページに移植する必要はありません。ただし、アプリケーションの ASP から ASP.NET への移植にはさまざまな利点があります。特に重要な利点を以下に示します。

  • パフォーマンスの向上。Microsoft のテストによると、ASP.NET アプリケーションは従来の ASP アプリケーションと比べて、1 秒当たり 2~3 倍の数の要求を処理することができます。
  • 安定性の向上。プロセスは ASP.NET ランタイムによって細かく監視、管理されるので、あるプロセスが異常な動作 (リークやデッドロックなど) を起こした場合には、新しいプロセスをその場で作成することができます。これにより、アプリケーションはいつでも要求を処理することができます。
  • 開発者の生産性の向上。ASP.NET のサーバー コントロールやイベント処理などの新機能により、開発者はアプリケーションをより短期間で、より少ないコード量で構築することができます。また、コードを HTML コンテンツから分離するのも簡単になっています。

残念ながら、既存の ASP ページを ASP.NET ページに移植するのは、ファイル拡張子を .asp から .aspx に変えるだけで済むような簡単な作業ではありません。これは特に、VBScript と Visual Basic .NET の間に大きな違いがあるためです。幸いなことに、必要な変更の大部分は構文上のものであり、自動的に処理できます。COM コンポーネント (ADO や、開発者が作成したカスタム COM コンポーネントなど) を使用する Visual Basic .NET コードは、実質上、そのままの形で実行できます。C# コードでは COM コンポーネントを扱うために余分な作業が必要となりますが、これはこのドキュメントの範囲を超えています。

このドキュメントは 2 つのセクションに分かれています。最初のセクションでは、典型的なデータ ドリブン型の ASP アプリケーションを取り上げます。次のセクションでは、この ASP アプリケーションを ASP.NET に移植します。

注: この記事では、元の ASP コードに加える変更をできるだけ抑えて、ASP アプリケーションを ASP.NET に移植する方法に焦点を当てています。ASP.NET の新機能を使用して ASP アプリケーションをゼロから再構築する方法については触れていません。

サンプルの ASP アプリケーションについて

ASP.NET に移植するサンプルの ASP アプリケーションは、金融機関のためのプロジェクト レポート アプリケーションです。このアプリケーションは VBScript で書かれています。この典型的なアプリケーションは、進行中および過去のプロジェクトに関する情報を表示し、ユーザーがプロジェクト レポートの表示に対して一定の条件を指定できるようになっています。

この ASP アプリケーションは、プロジェクト情報がデータベースに格納されているという意味で、データ ドリブンです。具体的には、Project と Department という 2 つのテーブルが使用されます。Department テーブルは社内の各部門についての情報を含んでおり、Project テーブルは各プロジェクトについて、プロジェクト名、開始日、終了予定日、実際の終了日、優先度、プロジェクトの担当部門 (Department テーブルへの外部キー経由)、およびプロジェクトに関する詳しい説明などの情報を含んでいます。

プロジェクト情報 Web ページをブラウズするユーザーには、昨年開始されたプロジェクトのリストが表示されます。ユーザーは 2 つのリスト ボックスを使って、現在のプロジェクトの表示をカスタマイズすることができます。最初のリスト ボックスでは、ユーザーは進行中のプロジェクト、完了したプロジェクト、およびすべてのプロジェクトのいずれを表示するかを指定できます (進行中のプロジェクトは終了日が NULL のもの、完了したプロジェクトは実際の終了日を持ち、その期日を過ぎているものです)。第 2 のリスト ボックスでは、ユーザーはプロジェクトを部門ごとに表示することで、レポートをさらにカスタマイズできます。

図 1 はプロジェクト レポートのユーザー インターフェイスを示しています。この例では、ユーザーは Internal Computer Services 部門のすべての進行中のプロジェクトを表示するように指定しています。

図 1: Internal Computer Services 部門の進行中のプロジェクトのレポート
図 1: Internal Computer Services 部門の進行中のプロジェクトのレポート

プロジェクト レポート コードについて

プロジェクト レポート アプリケーション全体のソース コードは 1 つの ASP ページに収められており、このページはポストバック フォームを使ってユーザーのレポート カスタマイゼーション オプションを処理しています。このドキュメントでは ASP アプリケーションの ASP.NET への移植に焦点を当てているので、ASP コードの動作については説明しません。読者は、いま現在、ASP と ADO データ アクセスがアプリケーションの構築にどのように使われているかという点での実践的な知識を持っているものと仮定しています。

次のコードでは、ADO Connection オブジェクトを作成し、Access データベースに対してオープンしています。


Set objConn = Server.CreateObject("ADODB.Connection")
objConn.ConnectionString = _      
     "PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=" & _  
     Server.MapPath("Projects.mdb") & ";"
objConn.Open

Department テーブルの個々の行の Name と DepartmentID がレコードセットに格納されます。その後、このレコードセットの内容がリストボックス内に表示されます。


Set objDeptListRS = Server.CreateObject("ADODB.Recordset")
objDepartmentListingRS.Open "Department", objConn, _
            adOpenForwardOnly, adLockReadOnly, adCmdTable
  
'レコードセットを繰り返し処理
Response.Write " < b >Department:< /b >  " & _
       " < select size=""1"" name=""lstDepartmentID"" ID="Select1" > "
Response.Write "< option value=""-1"" >" & _
       "-- Show All Departments --< /option >" & vbCrLf
 
Do While Not objDeptListRS.EOF
   Response.Write "< option value=""" & _
          objDepartmentListingRS("DepartmentID") & """"
 
   'この項目を選択状態にする必要はあるか?          
   If CInt(objDepartmentListingRS("DepartmentID")) = _
                                 CInt(iDepartmentID) then
      Response.Write " selected"
   End If
                  
   Response.Write " >" & objDeptListRS("DepartmentName") &_
                   "< /option >"
   objDeptListRS.MoveNext
Loop
Response.Write "< /select >" & vbCrLf & vbCrLf

次に、ユーザーが選択したオプションに基づいて、動的な SQL 文字列が作成されます。次のコードでは、SQL 文字列の WHERE 句が作成され、前年に開始されたプロジェクトのみが取得されるようになっています。ユーザーの選択項目によっては、WHERE 句はさらに拡張されることがあります。変数 iDepartmentID および strProjectView は、以前に定義され、ユーザーによって選択されたリスト ボックス値に代入された変数です。


strSQL = "SELECT D.DepartmentName, ProjectName, " & _
        "StartDate, EstimatedEndDate, ActualEndDate, " & _
        "Priority, ProjectDescription " & _ 
     "FROM Project P " & _ 
          "INNER JOIN Department D ON " & _
                    "D.DepartmentID = P.DepartmentID " & _
     "WHERE StartDate >= #" & _
                DateAdd("yyyy", -1, Date()) & "# "
 
'必要ならば、追加の WHERE 句を作成する
If CInt(iDepartmentID) <> -1 then
   '部門 ID のための句を追加する
   strSQL = strSQL & " AND P.DepartmentID = " & _
                                       iDepartmentID
End If
 
'どのタイプのプロジェクトを表示するか
Select Case strProjectView
   Case "ongoing":
      strSQL = strSQL & " AND ActualEndDate IS NULL"
   Case "completed":
      strSQL = strSQL & " AND ActualEndDate IS NOT NULL"
End Select

別の Recordset オブジェクトである objProjectsRS が作成され、上記の動的な SQL クエリの結果が格納されます。最後に、このレコードセットが繰り返し処理されて、HTML テーブルとして表示されます。


'HTML の table タグと th タグを出力する
Response.Write "< p >< table align=""center"" " & _
               "border=""1"" cellspacing=""1"" >" & vbCrLf
Response.Write "< tr >< th >Project< /th >< th >StartDate< /th >" &_
      "< th >Estimated Completion< /th >< th >Actual " & _
      "Completion< /th >< th >Priority< /th >" & _ 
      "< th >Description< /th >< /tr >" & vbCrLf
 
'レコードセット全体をループ処理する
Do While Not objProjectsRS.EOF
   'レコードセット情報を表示する
 
   objProjectsRS.MoveNext  'move to the next record
Loop
Response.Write "< /table >" & vbCrLf & vbCrLf

ASP アプリケーションの ASP.NET への移植

ASP アプリケーションを ASP.NET に移植するときには、ASP.NET の新機能を既存の ASP アプリケーションに組み込むのにどれだけの時間を費やすかを決定しなくてはなりません。通常は、ASP ページのファイル拡張子を .asp から .aspx に変更し、いくつかの構文上の変更を反映させるだけで、ASP ページを ASP.NET ページとして動作させることができます。このような移植は、短時間で終了するものの、ASP.NET Web コントロール、ADO.NET、.NET Framework クラスなどの.NET の新機能を利用することはできません。これよりも細かい移植作業には時間がかかるかもしれませんが、完成した ASP.NET ページは可読性と保守可能性が高まり、より高度な機能を利用することができます。

開発者は、ASP アプリケーションを ASP.NET に移行するときには、各アプローチのトレードオフを検討する必要があります。時間に制約がある場合には、ASP から ASP.NET への単純な移植が適しているでしょう。厳しい締切がない場合には、時間をかけて、リッチな ASP.NET アプリケーションをゼロから構築するといいかもしれません。もちろん、インクリメンタルなアプローチをとることもできます。ビジネス ルールの実装に多数の COM コンポーネントを使用している大規模なサイトでは、Web アプリケーションの UI の部分のみを移植し、従来の COM コンポーネントを使い続けることもできます。

次のセクションでは、変更箇所を可能な限り抑えて、既存の ASP コードを ASP.NET に移植する方法を検討します。

ASP アプリケーションの ASP.NET への移植

既存の ASP アプリケーションを ASP.NET に移植するときには、まず最初に ASP ページのファイル拡張子を .asp から .aspx に変更します。プロジェクト レポート アプリケーションは 1 つの ASP ページしか持っていないので、名前の変更は簡単です。この変更を加えたら、新しい.aspx ページを Web ブラウザで表示してみてください。エラーなしにロードされましたか? おそらく、VBScript コードにはいくつかの構文上の問題が含まれているでしょう。

前に示した ASP アプリケーションの移植にあたって最初に表示されるエラー メッセージは、Option Explicit に関連するエラーです。

Error message concerning Option Explicit

このステートメントは、ASP.NET Web ページでは @Page ディレクティブに移動する必要があります。.aspx ファイルを編集し、行 1 と 2 を削除し、次の @Page ディレクティブに置き換えてください。


< % @Page Language="VB" Explicit="True" % >

この変更を加えたら、ページをブラウザに再ロードします。Response.Write ステートメントの前後に括弧がないというエラーが表示されるはずです。

Error concerning the lack of parantehsis around the Response.Write statements

Visual Basic .NET では、サブルーチンと関数の両方のすべての引数リストが括弧で囲まれている必要があります。ドキュメント全体を確認し、すべての Response.Write ステートメントの引数リストを括弧で囲んだ後に、ASP.NET ページをブラウザに再ロードしてください。

Visual Basic 6.0/VBScript と Visual Basic .NET のもう 1 つの違いに、Visual Basic .NET が既定のプロパティをサポートしていないということがあります。既定のプロパティは開発者にとってのショートカットとなっていました。Visual Basic 6.0/VBScript で従来の COM コンポーネントを使用するとき、開発者がプロパティを指定しなければ、既定のプロパティが使用されました。たとえば、ADO Recordset の既定のプロパティは Fields コレクションで、Fields コレクションの既定のプロパティは Value プロパティです。したがって、従来の ASP で次のように指定したとします。


Response.Write objRecordset("columnName")

これは、実際には次のものと等価です。


Response.Write objRecordset.Fields("columnName").Value

従来の ASP ページを ASP.NET に移植するときには、Cast from __ComObject to String is not valid というわかりにくいエラーが発生することがあります。

Error message: Cast from _ComObject to String is not valid

このようなエラーが起こるのは、Visual Basic .NET が次のようなケースで既定のプロパティをサポートしていないからです。


Response.Write(objRecordset("columnName"))

Visual Basic .NET は Field オブジェクトを String にキャストしようとして失敗しています。この場合には、出力するプロパティを明示的に指定して、Value プロパティを出力したいということを指定する必要があります。


Response.Write(objRecordset.Fields("columnName").Value)

ASP.NET アプリケーションの移植作業を進めていくと、これ以外にも構文上のエラーが必ず発生するでしょう。表 1 は、プロジェクト レポート アプリケーションを ASP から ASP.NET に移植するときに発生する構文エラーを示しています。

注: Visual Basic は Visual Basic .NET のリリースに伴い、プログラミング言語として成熟し、try.catch のエラー処理、真のオブジェクト指向開発、およびその他の待望されていたさまざまな機能強化がサポートされています。ただし、Visual Basic を現代的な言語に作り替えるためには、言語の構文にいくつかの変更を加える必要がありました。このため、Visual Basic .NET は VBScript や Visual Basic 6.0 との 100% の互換性は備えていません。Visual Basic .NET における変更点の詳細については、"Visual Basic .NET へのアップグレードを円滑に行うための Visual Basic 6.0 アプリケーションの準備" を参照してください。

 

エラー 理由 解決方法
Option Explicit statement not valid inside procedure. Option Explicit は Page ディレクティブの中で Explicit 属性を使って定義されなくてはなりません。 ASP.NET ページの先頭に

< % @Page Explicit="True" % >
を追加します。
There can only be one Page Directive. Page ディレクティブを追加した結果、ASP ページの

@LANGUAGE = "VBSCRIPT"
ディレクティブが余分なディレクティブとなっています。

< %@ LANGUAGE = "VBSCRIPT" % >
を含んでいる行を削除し、Page ディレクティブに

Language="VB"
属性を追加します。
Argument lists in call statements must now be enclosed in parenthesis. Visual Basic .NET では、すべてのサブルーチン呼び出しで、パラメータを括弧で囲む必要があります。いくつかの Response.Write 文にこのような括弧がありません。 必要な括弧を追加します。
たとえば

Response.Write str

Response.Write(str)
に変更します。
Let and Set statement are no longer supported on assignment statements. Visual Basic .NET は既定のプロパティをサポートしなくなっているので、Let および Set キーワードは Visual Basic 言語から削除されています。 Let または Set キーワードをすべて削除します (プロジェクト レポート アプリケーションでは、Set キーワードで Connection および Recordset オブジェクトを変数に代入しています)。
Date is a type, and so is not a valid expression. Expected a variable, constant, or procedure. プロジェクト レポート アプリケーションでは、Date () 関数を使って現在の日付を取得しています。この関数はサポートされなくなりました。

Date()

DateTime.Now
に置き換えます。
The name IsNull is not declared. Visual Basic .NET は IsNull 関数をサポートしなくなりました (プロジェクト レポート アプリケーションでは、実際の終了日が NULL ならば、そのプロジェクトは未完了であることを思い出してください。ASP バージョンでは、IsNull を使って、フィールドが NULL でないかどうかをチェックしています)。

IsNull

IsDBNull
に置き換えます。
Cast from __ComObject to String is not valid. Visual Basic .NET はデフォルト プロパティをサポートしなくなったので、従来の COM コンポーネントを使用するときには、使用したいプロパティを明示的に指定するようにします。

objRS("colName")
のインスタンスを

objRS.Fields("colName").Value
に変更します。

表 1: プロジェクト レポート アプリケーションを移植するときに発生する構文エラー

COM コンポーネントのスレッドの問題

ASP.NET ページ内で COM コンポーネントを使用するときには、特にアパートメント スレッド (STA) としてマークされた COM コンポーネントや、ObjectContext オブジェクトを通して ASP 組み込みオブジェクト (Request、Response、Server、Application、および Session) にアクセスする COM オブジェクトの場合には問題が生じることがあります。

たとえば、ADO オブジェクトは、デフォルトではレジストリ内でアパートメント スレッドとしてマークされています。このようなアパートメント スレッド コンポーネントを ASP.NET ページを通して使用しようとすると、作成しようとしたアパートメント スレッド コンポーネントが作成できなかったというエラーが表示されます。図 2 は、プロジェクト レポート アプリケーションの ASP.NET への移植バージョンを示しています。このエラーが発生するのは、ADO オブジェクトがデフォルトではアパートメント スレッドとしてマークされているためであることに注意してください。

Figure 2: An error occurs when attempting to access an apartment threaded COM component through an ASP.NET page
図 2: ASP.NET ページを通してアパートメント スレッドの COM コンポーネントにアクセスしようとするとエラーが発生する

幸いなことに、ASP.NET はエラー メッセージに表示されているように ASP 互換性モードを用意しています。ASP 互換性モードをオンにするには、Page ディレクティブに aspcompat=true 属性を追加します。この属性を追加すると、次の 2 つの効果があります。

  • ASP.NET は COM コンポーネントにアクセスするときにシングル スレッド アパートメント (STA) スレッドを使用します。デフォルトでは、マルチスレッド アパートメント (MTA) スレッドが使用されます。
  • ASP.NET は、後方互換性のある形で、ASP 組み込みオブジェクトへのアクセスを提供します。

この 2 つの変更により、ASP 互換性モードは、アパートメント スレッドの COM コンポーネントや、ASP 組み込みオブジェクトにアクセスする COM コンポーネントの使用をサポートします。

注: COM スレッド モデルの詳細は、このドキュメントの範囲を超えています。各種の COM スレッド モデルとその影響の詳細については、"Understanding and Using COM Threading Models" を参照してください。

要約

この記事では、ASP アプリケーションを ASP.NET に移植する方法について説明しました。ASP ページの移植にあたっては、ページのファイル拡張子の変更に加えて、若干の作業を行うだけで済みます。200 行のコードを含んだ 1 ページの ASP アプリケーションであるプロジェクト レポート アプリケーションの ASP から ASP.NET への移植は 5 分以内で完了しました。独自の ASP アプリケーションを ASP.NET に移植するときには、以下の点に注意してください。

  • VBScript と Visual Basic .NET の間の構文上の違いを理解しておきます。小さな構文エラーを防ぐことで、移植プロセスははるかにスムーズに進行します。
  • 移植しようとしている ASP ページが、アパートメント スレッド COM コンポーネントや、ASP 組み込みオブジェクトにアクセスする COM コンポーネントを使用している場合には、Page ディレクティブに aspcompat="true" 属性を追加します。それ以外の場合には、このディレクティブは不要です。