はじめに
Visual Studio 2008(以下、VS2008)ではASP.NETの開発生産性が大幅に向上しています。ASP.NET自身の進化もありますが、IDEの進化はWebデベロッパーにとって大きなインパクトを与えました。どれほど便利になったかは、以下の連載を参考にしていただければ理解が深まるかと思います。
- Visual Studio 2008で進化するASP.NETの開発手法(前篇)
- Visual Studio 2008で進化するASP.NETの開発手法(中篇)
- Visual Studio 2008で進化するASP.NETの開発手法(後篇)
本稿では、これらの連載では触れられなかった、クライアントサイドのテクノロジーを中心に紹介したいと思います。
これまでの記事
- 第1回:新しい統合開発環境 Visual Studio 2008ってなんだ!?
- 第2回:ここが違う! Visual Studio 2008
- 第3回:とことん理解する .NET Framework 3.5
対象読者
- Visual Studio 2008に興味がある方
- .NET Framework 3.5に興味がある方
- ASP.NET 2.0の開発経験がある方
必要な環境と準備
Visual Studio 2008入門第1回の必要な環境と準備を参考にしてください。
ASP.NET 3.5の新機能(本稿で触れる部分)
- VS2008のWeb開発用のホットフィックスについて
- UpdatePanelの機能拡張
- JavaScriptを使用してWebサービスを呼び出す
- ASP.NET AJAXのWCFサポート
- JavaScriptを使用したフォーム認証の利用
- JavaScriptを使用したロール情報の利用
VS2008のWeb開発用のホットフィックスについて
ASP.NET開発チーム(現マイクロソフトコーポレーション副社長)のScott Guthrie氏によると、今後VS2008では、報告が多いバグフィックスをまとめてパッチとしてリリースしていくことになるとされています。2月8日には、その第一弾となるVWD 2008(Visual Web Developer 2008)とVS2008のWebシナリオで報告されていたホットフィックスがリリースされました。このホットフィックスでは以下のパフォーマンスが改善されています。
- HTMLソースビュー
- デザインビュー
- Webサイトのビルド時
また、HTML、JavaScriptエディタ時の機能改善とバグフィックスがされています。RTM段階では正しく動作しなかったjQueryのインテリセンスも有効になりました。jQueryユーザーには非常に嬉しい変更点です。
肝心のホットフィックスのダウンロードはこちらからできます。なお、このホットフィックスをダウンロードするにはWindows Live IDが必要です。
ホットフィックスのインストール
Vista環境とXP環境で若干の違いがあるので、ここでは、Vista環境におけるインストール手順を記します。
- ダウンロードしたKB946581フォルダ内にある338649_ENU_i386_zip.exeを実行してC:\以外の場所に解凍
- 解凍されたVS90-KB946581.exeを実行
- ウィザードが起動するので、ウィザードに沿って進めるとインストール完了
UpdatePanelの機能拡張
ASP.NET 2.0 AJAX Extensionsには目玉とも言えるUpdatePanelコントロールがあります。このUpdatePanelコントロール内では、JavaScriptを利用しているコントロールが正しく動作しませんでした(もちろん、組み方によっては正しく動作するものもありました)。VS2008で利用可能なASP.NET 3.5 AJAX ExtensionsではUpdatePanelコントロール内で正しく動作するコントロールの幅が広がっています。
正しく動作しないコントロール
早速、違いを見てみたいと思います。まずはASP.NET 2.0 AJAX ExtensionsのUpdatePanelコントロール内で正しく動作しないコントロールです。
- TreeView/Menuコントロール
- WebPartsコントロール
- FileUploadコントロール
- GridView/DetailsViewコントロール(EnableSortingAndPagingCallbacksプロパティがTrueの時)
- Login/PasswordRecovery/ChangePassword/CreateUserWizardコントロール(編集可能なテンプレートではない時)
- Substitutionコントロール
- 検証コントロール
正しく動作するコントロール
続いてASP.NET 3.5 AJAX ExtenisonsのUpdatePanelコントロールで制限付きですが、正しく動作するコントロールと、その特徴をピックアップします。
- WebPartsコントロール
- WebPartZoneコントロールが複数ある場合は同じUpdatePanelコントロール内に配置する
- UpdatePanelを入れ子にする場合、WebPartManagerコントロールは親UpdatePanelコントロールに配置する
- 非同期ポストバックを使用してWebPartsコントロール(.webpartsファイル)のインポート・エクスポートは不可(実行すると通常のポストバックが実行)
- 非同期ポストバック中にWebPartsコントロールのスタイルの追加・変更は不可(エディタパーツによる設定変更)
- 検証コントロール
- 検証対象のコントロールと同一パネル内に配置することを推奨
以上の点からUpdatePanelコントロールを利用する際には、AJAX Extensionsのバージョンには注意してください。VS2008で開発を行う際はASP.NET 3.5を選択することが多いと思いますが、もしASP.NET 2.0 AJAX Extensionsの開発を行いたい場合は次のコラムを参照してください。
JavaScriptとScriptManagerコントロールを使用してWebサービスを呼び出す
これは、VS2005+ASP.NET 2.0 AJAX Extensionsから利用できた機能ですが、以下の説明にもつながってくる重要な技術なので紹介します。
ScriptManagerコントロールにはServicesプロパティがあります。このServicesプロパティにアクセスしたいWebサービスを設定すると、SriptManagerコントロールは、JavaScriptを使用したプロキシクラスを自動生成し、Webサービスへのアクセスを可能にします。このWebサービスへのアクセスは自作したWebサービス以外に、メンバシップサービスや、ロール管理サービスなどのアプリケーションサービスにアクセスすることもできます。
<asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="Webサービス.asmx" /> </Services> </asp:ScriptManager>
本稿を理解するために重要なポイントはプロキシクラスの構文です。クライアントサイドからWebサービスを呼び出す場合、基本は以下のようになります。
クラス名.メソッド名( [パラメータ, ……], 処理成功時のコールバック関数, サービス側で例外が発生時のコールバック関数, 任意のコンテキスト値 )
動作の流れや仕組みなどは、「[ASP.NET AJAX]XML Webサービスを非同期呼び出しするには?」(@IT)にて詳しく解説されているので、そちらを参考にしてください。
ASP.NET AJAXのWCFサポート
VS2008では「AJAX 対応 WCF サービス」テンプレートが用意されています。これとScriptManagerコントロールを利用すると、WCFサービスをJSON形式でASP.NET AJAXと共に使用できます。WCFに関する基礎知識は「WCF(Windows Communication Foundation)チュートリアル 前編」と「WCF(Windows Communication Foundation)チュートリアル 後編」を参考にしてください。また、「Visual Studio 2008徹底入門」の第7回でもWCFについて扱う予定です。
web.config(構成ファイル)を使用したエンドポイント追加方法
ここでのサンプルはシンプルにテキストに入力された数字に3をかけた値を返すWCFサービスを作成します(図1~2)。
[新しい項目の追加]で「AJAX 対応 WCF サービス」を選択すると(図3)AJAX対応のWCFサービスが作成されます。その時web.configやendpointは自動的に記述されます。
<system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="AJAXAspNetAjaxBehavior"> <enableWebScript /> </behavior> </endpointBehaviors> </behaviors> <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> <services> <service name="AJAX"> <endpoint address=""
behaviorConfiguration="AJAXAspNetAjaxBehavior"
binding="webHttpBinding" contract="AJAX" /> </service> </services> </system.serviceModel>
Service name属性とcontract属性にサービス名が、binding属性にはwebHttpBindingが設定されています。webHttpBindingはwebプログラミングでWCFを利用する場合のバインディングです。
自動追記されたweb.configには、エンドポイントの作成、コントラクトの設定がされているので、このWCFサービスを利用するにはサービスメソッドを記述するだけでOKです。
<ServiceContract(Namespace:="AJAXIAN")> _ <AspNetCompatibilityRequirements(RequirementsMode:= AspNetCompatibilityRequirementsMode.Allowed)> Public Class AJAX <OperationContract()> _ Public Function Math(ByVal item As Integer) As Integer Return item * 3 End Function End Class
続いて、ASP.NET AJAX(Webフォーム)側での設定ですが、こちらも簡単でScriptManagerコントロールのServicesプロパティを設定すると、WCFサービスとアクセスすることが可能になります。
<asp:ScriptManager ID="ScriptManager1" runat="server"> <Services> <asp:ServiceReference Path="サービス名.svc" /> </Services> </asp:ScriptManager>
WCFサービスにアクセスできるようになったので、後はASP.NET AJAX(Webフォーム)側でそれを利用するコードを記述するだけです。
function Click(){ var txt = $get("TextBox1").value; var service = new AJAXIAN.AJAX(); service.Math(txt,Finish); return false; } function Finish(res){ $get("Label1").innerHTML=res; }
web.config(構成ファイル)を使用しないエンドポイント追加方法
web.configにエンドポイントの追記を行うことなく、WCFを利用する方法もあります。この方法はWCFサービスがIISに配置されていることが必要です。
また、この方法のメリットは、web.configへの追記を行うことなくWCFを利用できるという点になります(前項の方法を利用すれば、web.configへの自動記述がされるのでなおさら利用機会が少ないかもしれません。個人的見解としては、ASP.NETを使用しない場合にエンドポイント作成を簡略化させるために存在しているという認識です)。
前項で作成したWebサイトから、web.configのsystem.serviceModel要素の記述をコメントアウトしてIISにWebサイトを配置します。そして、web.configの代わりに@ServiceHostディレクティブのFactory属性に WebScriptServiceHostFactory を指定します。手順はこれだけです。
<%@ ServiceHost Language="VB" _ Debug="true" Service="名前空間.クラス" _ CodeBehind="~/App_Code/Service.cs" _ Factory=System.ServiceModel.Activation.WebScriptServiceHostFactory %>
このFactory属性を指定することで、本来必要なweb.configに対する設定をFactory属性で指定されたファクトリクラスの中で実施します。これによって、クライアントサイドのJavaScriptからWCFサービスを呼び出すことができます。
ASP.NETを使用しないAJAXエンドポイント追加方法
WCFは使いたいけど、ASP.NETは使用していないAJAX対応のページを作成する事も考えられます。WCFはこのシナリオにも対応しています。手順は以下のようになっています。
- AJAXエンドポイントの作成
- AJAX対応コントラクトの作成
- WCFへのアクセス
このうち、「AJAXエンドポイントの作成」については、既に述べている構成ファイルを使用するパターンと、しないパターンの2種類ですので解説は割愛します。
AJAX対応コントラクトの作成
JSON形式でデータのやり取りをするにはWCFサービス側で、対応のコントラクトを作成する必要があります。クライアントサイドではJSON形式でのデータを送信し、WCFサービス側はJSON形式のデータを受け取るためのコントラクトと、WebGetAttribute属性かWebInvokeAttribute属性を設定する必要があります。GETを使用する場合はWebGetAttribute属性を、POST、PUTなどを利用するときはWebInvokeAttribute属性を使用します。
サンプルでは、苗字と名前を入力してもらい、結合して返すシンプルなサービスにしています。
var name = '{"FirstName":'; name = name + '"' + firstname + '"' + ',"LastName":'; name = name + '"' + lastname + '"' + '}';
<ServiceContract()> _ Public Interface IService <OperationContract()> _ <WebInvoke(ResponseFormat:=WebMessageFormat.Json, bodystyle:=WebMessageBodyStyle.WrappedRequest)> _ Function NameCombine(ByVal FirstName As String, ByVal LastName As String) As String End Interface Public Class Service Implements IService Public Function NameCombine(ByVal FirstName As String, ByVal LastName As String) As String _ Implements IService.NameCombine Return "こんにちは " + LastName + " " + FirstName + " さん" End Function End Class
WCFへのアクセス
WCF AJAXエンドポイントは、JSON/XMLどちらの形式の要求も受け取り可能です。
ただし、JSONで利用したい場合はXMLHttpRequestのsetRequestHeaderのContent-typeをapplication/jsonに設定する必要はあります。もちろんポストするデータはJSON形式で処理したい場合はJSONシリアライズする必要があります。Content-typeがtext/xmlの場合のPOST要求はXML として処理されます。
function nameCombine() { var firstname = document.getElementById("firstname").value; var lastname = document.getElementById("lastname").value; var xmlHttp = new XMLHttpRequest(); // WCFサービスへのURL var url = "Service.svc/jsonEndpoint/NameCombine"; //JSON形式へシリアライズ var name = '{"FirstName":'; name = name + '"' + firstname + '"' + ',"LastName":'; name = name + '"' + lastname + '"' + '}'; // WCFサービスへJSON形式でのリクエスト xmlHttp.open("POST", url, true); xmlHttp.setRequestHeader("Content-type", "application/json"); xmlHttp.send(name); // サービスからの応答処理 xmlHttp.onreadystatechange = function Status(){ if (xmlHttp.readyState == 4){ document.getElementById("combinename").innerHTML = xmlHttp.responseText; } } }
JavaScriptを使用したフォーム認証の利用
JavaScriptとScriptManagerコントロールの組み合わせで、ASP.NETのフォーム認証サービスを呼び出して利用できます(図4・図5)。
この機能を利用すると、クライアントサイドからプロファイルサービスや、ロールサービス(次項で解説)を呼び出して活用することができます。この機能はASP.NET 2.0 AJAX Extensionsでも実装可能でしたが次項の理解を深めるために、ここでも解説します。
なお、この利用方法は、「[ASP.NET AJAX]クライアントサイド・スクリプトからASP.NETの認証機能を利用するには?」にて詳しく解説されています。
手順としては以下のようになります。
- Web サイト管理ツールからユーザーを登録する
- web.configに認証サービスの有効化設定をする
- Webフォームを作成する
- 認証サービスを呼び出すJavaScriptを記述する
Web サイト管理ツールからユーザーを登録する
メニューバーの[Webサイト]から[ASP.NET 構成]を選択し、Webサイト管理ツールを起動します。その後、ロールの作成(サンプルではAdminとUser)、ユーザーの作成を行います(図6、図7)。
web.configで認証サービスを有効化する
続いて、認証サービスを利用するためにweb.configに有効化するためにauthenticationService要素のenabled属性をtrueに設定します。
<system.web.extensions> <scripting> <webServices> <authenticationService enabled="true"/> </webServices> </scripting> </system.web.extensions>
なお、本稿では認証ユーザーのみがアクセス可能なフォルダとしてRoleフォルダを用意しています。ソリューション エクスプローラ上でRoleフォルダを作成し、その直下に以下の記述をしたweb.configを配置します。これで、ログインしたユーザーのみがRoleフォルダ内にアクセスできます。
<authorization> <deny users="?"/> <allow users="*"/> </authorization>
Webフォームを作成する
それでは、実際に利用するWebフォームの作成をします。
<asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="~/Authentications.js" /> </Scripts> </asp:ScriptManager> <table> <tr> <td>ユーザー名</td> <td><input type="text" id="username" /></td> </tr> <tr> <td>パスワード</td> <td><input type="password" id="password" /></td> </tr> <tr> <td colspan="2" align="center"> <button onclick="OnClickLogin(); return false;">Login</button> </td> </tr> </table>
ポイントはASP.NETで提供されているログインコントロールを一切利用していない点です。
認証サービスを呼び出すJavaScriptを記述する
最後に、認証サービスを呼び出すJavaScriptファイルの記述を行います。前項で設定したLoginボタンをクリックされた時に、Microsoft AJAX LibraryのSys.Services.AuthenticationServiceクラスを利用して認証サービスにアクセスします。
/// <reference name="MicrosoftAjax.js"/> var username; var password; // ページロード時に実行される処理 function pageLoad() { username = $get("username"); password = $get("password"); } // Loginボタンクリック時に実行される処理 function OnClickLogin() { // 認証サービスへのアクセス // 今回はユーザー名・パスワード・ログイン認証後の //リダイレクト先のURLを設定 Sys.Services.AuthenticationService.login(username.value, password.value,false,null,"Role/Default.aspx",null,null,null); }
以上の設定でJavaScriptを使用したフォーム認証は完成です。実行すると、登録したユーザー・パスワードを入力した時のみ「Role/Default.aspx」へとリダイレクトされます(図4・図5)。
Sys.Services.AuthenticationService.loginメソッドでは、次のような構文で記述することになっています。実際に設定した内容と照らし合わせて見てください。
Sys.Services.AuthenticationService.login( ユーザー名(必須), パスワード。既定値はnull, クッキーを永続的に保持するかどうか。既定値はfalse, カスタム情報(将来使用するために予約済)。既定値はnull, リダイレクト先のURL。既定値はnull, 処理成功時のコールバック関数。既定値はnull, 例外発生時のコールバック関数。既定値はnull, ユーザー コンテキスト)
また、同じような手順でクライアントサイドからプロファイルサービスの呼び出しも可能です。こちらについては、「[ASP.NET AJAX]クライアントサイド・スクリプトからASP.NETのプロファイル機能を利用するには?」にて詳しく解説されているので、そちらを参考にしてください。
JavaScriptを使用したロール情報の利用
ASP.NET 3.5ではMicrosoft AJAX LibraryとScriptManagerコントロールを利用して、ASP.NETロールサービスを呼び出して利用することができます。つまり、クライアントサイドでロールベースの制御が可能になりました。
クライアントサイドでロールを参照できると、ロールによってコントロールの表示やデザインを変更、表示するデータの範囲を絞ることが可能になります(図8・図9)。
手順としては以下のようになります(前項で作成したWebサイトを利用しています)。
- web.configにロールサービスの有効化設定をする
- Webフォームを作成する
- ロールサービスを呼び出すJavaScriptを記述する
web.configにロールサービスの有効化設定をする
ロールサービスを利用するためにweb.configに有効化設定を記述します。
<system.web.extensions> <scripting> <webServices> <authenticationService enabled="true"/> <roleService enabled="true"/> </webServices> </scripting> </system.web.extensions>
ロールサービスを利用するために、roleService要素のenabled属性をtrueに設定しています。
Webフォームを作成する
今回はロールによる外観を変化させるために、認証後リダイレクトされるページ(Role/Default.aspx)Webフォーム上にいくつかのコントロールと、ロールサービスにアクセスするためにScriptManagerコントロールを配置します。
<form id="form1" runat="server"> <h1><div id="Role" ></div></h1> <asp:ScriptManager ID="ScriptManager1" runat="server"> <Scripts> <asp:ScriptReference Path="Role.js" /> </Scripts> </asp:ScriptManager> <asp:Calendar ID="Calendar1" runat="server"></asp:Calendar> <asp:HyperLink ID="HyperLink1"
runat="server" NavigateUrl="~/LogIn.aspx"> Login状態保持のままLoginページへ</asp:HyperLink> <asp:Button ID="Button1" runat="server"
Text="Button" OnClientClick="return false;" /> <div id="placeHolder"> <button id="LogOutButton"
onclick="OnClick_LogOut();">LogOut</button> </div> </form>
また、外観を変更するためのCSSも記述します。こちらも至ってシンプル。
.Admin { background-color: #0000FF; color: #FFFFFF; font-family: メイリオ; font-size: x-large; } .User { background-color: #000000; color: #FFFFFF; font-family: メイリオ; font-size: x-large; }
ロールサービスを呼び出すJavaScriptを記述する
ロールサービスを呼び出すJavaScriptファイルの記述は以下のようになります。今回はAdminとRoleの2種類、そしてどちらかのロールにしか属していないことからシンプルなコードにしています。
/// <reference name="MicrosoftAjax.js"/> var roleProxy; // ページロード時に実行される処理 function pageLoad(){ roleProxy = Sys.Services.RoleService; roleProxy.load(LoadCompletedCallback); } // 読み込み処理完了時のコールバック関数 function LoadCompletedCallback(roles) { // roles[0]は認証済みのユーザーのロール // それぞれにロールのテキストを表示 var roleInfo = "Role: " + roles[0]; $get("Button1").value = roleInfo; $get("Role").innerHTML = roles[0]; // Adminロール・Userロールによって表示を切り替え // .classNameにてRoleのクラス名を設定し、CSSを反映 if (roles[0] == "Admin"){ $get("Button1").className = "Admin"; $get("Role").className = "Admin"; $get("Calendar1").style.visibility = "visible"; $get("HyperLink1").style.visibility = "hidden"; } else if(roles[0] == "User") { $get("Button1").className = "User"; $get("Role").className = "User"; $get("Calendar1").style.visibility = "hidden"; $get("HyperLink1").style.visibility = "visible"; } }
以上の設定でJavaScriptを使用したロールサービスの利用は完成です。実際に実行すると、ユーザーのロールによって、「Role/Default.aspx」のページの表示が変わります(図8・図9)。
Sys.Services.RoleService.loadメソッドでは、以下のような構文で記述することになっています。実際に設定した内容と照らし合わせて見てください。
Sys.Services. RoleService.load ( 処理成功時のコールバック関数。既定値はnull, 例外発生時のコールバック関数。既定値はnull, ユーザー コンテキスト)
Sys.Services. RoleServiceは他に以下メンバがあります。
メンバ | 概要 |
DefaultWebServicePathフィールド | ロールサービスへのパスを指定 |
loadメソッド | 認証ユーザーのロールを読み込む |
defaultFailedCallbackプロパティ | 例外発生時のコールバック関数の取得・設定 |
defaultLoadCompletedCallbackプロパティ | 読み込み完了時のコールバック関数の取得・設定 |
defaultSucceededCallbackプロパティ | 処理成功時のコールバック関数の取得・設定 |
defaultUserContextプロパティ | ユーザーコンテキストの取得・設定 |
IsUserinRoleプロパティ | 認証ユーザーが指定されたロールかチェック |
pathプロパティ | ロールサービスのパスを取得・設定 |
roles プロパティ | 認証ユーザーのロールを取得 |
timeoutプロパティ | ロールサービスサービスのタイムアウトを取得・設定 |
まとめ
今回はASP.NET 3.5周りの変更点をいくつかピックアップして紹介してきました。今回の記事でサーバーサイドからのアプローチ以外に、クライアントサイドからのアプリケーション作成の可能性も感じてもらえたかと思います。今まで、ASP.NET(サーバーサイド)のみでしか利用していなかった方も、少しクライアントサイド開発に目を向けていただけたら幸いです。
次回は、VS2008を利用することで開発を行いやすくなったWPFです。お楽しみに。