ASP.NET WebForms で非同期処理を行う (.net4.5)

WebPageではasync/awaitをそのまま使うことができません。
利用するには以下の手順を踏みます。

1,Web.config設定

/configuration/appSettingsに、key=UseTaskFriendlySynchronizationContextな項目を追加。
詳細は下記を参照。

<configuration>
  ....
  <appSettings>
    <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" />
    ....
  </appSettings>
  ....
</configuration>

2,aspxファイルのページディレクティブ設定

末尾の「Async="true"」を追加する。コード例は下記を参照。

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm.aspx.cs" Inherits="Sample.WebForm" Async="true" %>

3,RegisterAsyncTaskメソッドに非同期タスク登録

Page.RegisterAsyncTask()に非同期なタスクを登録する。コード例は下記を参照。
登録タスクを実行するには、Page.ExecuteRegisteredAsyncTasks()を明示的に呼び出す必要あり。
未実行タスクはPreRenderイベントとPreRenderCompleteイベントの間で実行される。

protected override void OnLoad(EventArgs e)
{
    ....
    RegisterAsyncTask(new PageAsyncTask(async () =>
    {
        var httpClient = new System.Net.Http.HttpClient();
        var res = await httpClient.GetAsync("http://localhost/Hogege");
        ....
    }));
    ....
}

ExpresswebでSQLServerCe4を使用する

で確認

はじめに

SQLServerは3つまでしかDBを作成することができない。これは嬉しくないのでSQLServerCompact4を使うことにした。
インメモリデータベースを使うのは初めてで、現状はホスティング先で使用可能であることを確認しただけなので、
これから先色々SQLServerCe4に起因する事象が発生すると思われる。

Web.config

コネクション文字列

*sdfを作成してテーブル作成、それを使用してモデル作成しただけなのでVSによる自動生成されたものを使用している。

<configuration>
	<connectionStrings>
		<add name="Database1Entities" connectionString="metadata=res://*/Models.Model1.csdl|res://*/Models.Model1.ssdl|res://*/Models.Model1.msl;provider=System.Data.SqlServerCe.4.0;provider connection string=&quot;Data Source=|DataDirectory|\Database1.sdf&quot;" providerName="System.Data.EntityClient" />
	</connectionStrings>
...
</configuration>
アセンブリバージョン指定

こんな感じで指定する。

<configuration>
...
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Data.SqlServerCe" publicKeyToken="89845dcd8080cc91" />
        <bindingRedirect oldVersion="4.0.0.0" newVersion="4.0.0.1" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

SQLServerCe4アセンブリファイルの配置

Expresswebにはインストールされていないようなので、アセンブリファイル一式もアップロードしてやる必要がある。
<SQLServerCe4のインストールフォルダ>/private フォルダ以下すべてのファイルをMVCプロジェクトのbinフォルダにコピーする。
ファイルのプロパティ(ビルドアクション,ディレクトリにコピー)は特に変更していない。

配置後作業

アプリケーションデプロイ後jに *sdfのパーミッション設定を行う必要がある。
screenshot
ブラウザからsdfファイルへアクセスはできなさそうなので、とりあえずはこれでよしとする。

ASP.NETページのトレース

ページ単位

チュートリアル : ASP.NET トレースと System.Diagnostics トレースの統合

WindowsFormアプリケーションの場合はConsole.Writeline()でデバッグメッセージをコンソール出力していたが、ASP.NETで同じことはできない。 System.Diagnostics.Traceクラスを使用し、Webページへトレース情報を出力する方法がもっとも手っ取り早い。 下記2点の作業で利用可能となる。

  • 対象ページのページディレクティブ(@Page)にTraceを"True"で追加する。*1
  • Web.configの /configuration/system.diagnostics/trace/listeners ノードにWebPageTraceListenerを追加する。
<system.diagnostics>
  <trace>
    <listeners>
      <add name="WebPageTraceListener" type="System.Web.WebPageTraceListener, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
    </listeners>
  </trace>
</system.diagnostics>

アプリケーション単位

方法 : ASP.NET アプリケーションのトレースを有効にする
ページ単位のデバッグではページごとにTrace有効無効を切り替える必要があり面倒である。 アプリケーション単位でのトレースを行うことで一括切り替え操作が可能になる。下記操作を行い、/trace.axdへアクセスするとトレース情報が表示される。

  • 全ページのページディレクティブ(@Page)にTraceを"False"にする。またはTraceを追加しない。
  • Web.configのトレースリスナーにWebPageTraceListenerを追加する。(ページ単位と同じ)
  • Web.configの /configuration/System.web/trace ノードを追加する。
<system.web>
  <trace enabled="true" pageOutput="false" requestLimit="40" localOnly="false"/>
</system.web>

ASP.NET MVCの場合

  • ビューエンジンがASPXの場合はページ単位、アプリケーション単位どちらも使用可能。*2
  • RAZORの場合はアプリケーション単位のみ使用可能。*3 *4

*1:PageクラスのTraceEnabledプロパティに設定される。

*2:ページクラスとしてASP.NETと同じViewPageクラスを使用しているため。

*3:razor用ページクラスとして既存のものとは互換性の無いSystem.Web.Mvc.WebViewPageを使用しているため。

*4:それにしてもクラス名がややこしい

ASP.NET 認証まわりメモ

メンバシップフレームワーク

メンバシップ プロバイダの実装
サンプル メンバシップ プロバイダの実装
方法 : サンプル メンバシップ プロバイダを実装する
方法 : カスタム メンバシップ ユーザーを実装する

DataSourceごとにプロバイダクラスを生成する必要がある。(DBのSQL方言など?)
プロバイダの実装例ではmdb(Access)をデータストアとしたプロバイダの実装例が掲載されている。

メンバシップユーザーの項目を追加する場合は、独自のユーザークラスを作成する必要がある。
また、それに伴いプロバイダクラスも拡張が必要になる。これらクラスのソースコードが一部抜粋して掲載されている。

メンバーシップによるチェックが成功した後の動き

Membership.ValidateUser()でユーザー名とパスワードの確認を行い、
パスするとFormsAuthenticationクラスを使用して認証処理を行う。
(ASP.NET MVCの場合は自動生成されるAccountControllerクラスのソースコードを参照。)

認証チケットとは

より
フォーム認証では、いったん認証されると認証チケットと呼ばれる資格情報がクッキーとしてクライアントへ送信される。 クライアントはこのクッキーを送信することで認証済みであることを示し、アプリケーションへアクセスすることができる。

認証チケット設定

認証チケット保存にCookieを使用するかWeb.configに指定しておく必要がある。
authentication/forms@cookieless 属性値に値をセットする。
ここで指定された値は、FormsAuthentication.CookieModeプロパティへセットされる。

※参照 FormsAuthentication.CookieMode プロパティ (System.Web.Security)
クッキーレスでの動作
Web.configのformsノードのcookieless属性値に"UseUri"を指定する。
<authentication mode="Forms">
  <forms loginUrl="~/Account/LogOn" timeout="2880" cookieless="UseUri" />
</authentication>


ログインするとURLが長くなる。これが認証チケット情報。


トップページではない別のページを表示。
"http://localhost/<認証チケット情報>/<以降のUrl>" となる。


認証チケット情報をUrlからはずすとログアウトしてしまう。
認証クッキー名の変更
Web.configのformsノードのname属性値に"test"を指定する。デフォルト値は".ASPXAUTH"
<authentication mode="Forms">
  <forms loginUrl="~/Account/LogOn" timeout="2880" name="test" />
</authentication>

認証クッキー名称がname属性値になる。

認証チケットの保存

FormsAuthentication.RedirectFromLoginPage()を呼び出すとチケットが発行され、
Cookieが有効な場合はCookieへ、無効な場合はHttpRequest.QueryStringプロパティへセットされる。
その後ページリダイレクトが発生する。

現在のログインユーザー情報をセットする

HttpモジュールのSystem.Web.Security.FormsAuthenticationModuleクラスが行う。
(C:\Windows\Microsoft.NET\ 以下にあるデフォルト設定のWeb.configで設定されている。)
認証チケットを復号してユーザー情報を生成、HttpContext.Userへセットする。

FormsAuthenticationModule クラス (System.Web.Security)

ユーザー情報(Principal)

System.Security.Principal.IPrincipalインターフェイス実装クラス。
Identityプロパティでユーザー情報2を返す。たいていはGenericPrincipalクラスが使用される?

IPrincipal インターフェイス (System.Security.Principal) GenericPrincipal クラス (System.Security.Principal)

ユーザー情報2(Identity)

System.Security.Principal.IIdentityインターフェイス実装クラス。
フォーム認証では、認証チケットからFormsIdentityオブジェクトを生成してユーザー情報にセット。
そしてHttpContext.Userへセットされる。

IIdentity インターフェイス (System.Security.Principal) FormsIdentity クラス (System.Web.Security)

PrincipalとIdentity

Principalはグループアカウント、Identityはユーザーアカウントだと考えることができる。詳しくは下記URLを参照。

プリンシパル オブジェクトと ID オブジェクト

ルーティング機能

ASP.NETのルーティング機能。ASP.NET MVCのそれがASP.NETへ統合されたらしい。

ルーティングの有効化

IIS7.0以前のバージョンで使用する場合、modulesノードへUrlRoutingModuleを追加する必要がある。 以降の場合はmodulesノードのrunAllManagedModulesForAllRequests属性値をtrueにすることで、 すべてのリクエストに対してルーティングが適用されるようになる。

ルーティングテーブル

HttpApplicationのApplication_Startイベントでルーティングテーブルをセットアップする。 System.Web.Routing.RouteTable.Routesプロパティ(static)へRouteオブジェクトを追加する。 RouteクラスコンストラクタのIRouteHandler実装クラスとして、基本的にはPageRouteHandlerオブジェクトを渡す。 RouteCollectionコレクションクラスの拡張メソッドであるSystem.Web.Mvc.RouteCollectionExtensions.MapRouteを使用して、 ルーティング情報を追加する。このメソッド内でRouteオブジェクトを生成し、Routesコレクションへ追加する。 IRouteHandler実装クラスは、MvcRouteHandlerオブジェクト。

ルーティング処理

HttpApplicationのPostResolveRequestCache、PostMapRequestHandlerイベントで UrlRoutingModuleモジュールによるルーティングが行われる。 一致するルートが存在しなかった場合は以降の処理を通常ASP.NETフロー?で行う。

最初に一致したルート情報(Routeオブジェクト)のGetHttpHandler()から、IHttpHandlerオブジェクトを取得し、これをHttpApplicationに渡す? (それぞれ、HttpHandlerクラス、MVCHandlerクラス)

ハンドラ処理

HttpApplicationのPreRequestHandlerExecuteイベント直後に行われる。 ハンドラからコントローラークラス生成〜アクションメソッド呼び出しを行う。 MVCHandler.ProcessRequest()で、ルーティング情報のコントローラー名からControllerクラスを生成し、そのcontrollerのExecute()呼び出しを行う。 このとき、ルーティング情報からcontroller内部で呼び出すアクションメソッドが決定される。 アクションメソッドでProcessRequest()パラメタのHttpContextオブジェクトに応答書き込みを行う。

アクションメソッドの実行はcontrollerが持つ、ControllerActionInvokerクラスオブジェクトによって実行される。 この時に、コントローラーのフィルタリング属性なども処理される。

ASP.NETのちょっと内側

ASP.NET MVCソースコードを読むにあたっての事前調査メモ。



  • ISAPI(Internaet ServerApplication Programming Interface)
  • IISの機能拡張。

    asp.netもその1つ。

  • HttpApplicationクラス
  • リクエストに対する処理を行うクラス。最初のリクエストでインスタンスが生成され、1リクエスト毎に処理が行われる。(この辺りは設定で調整可能)

    HttpApplication継承クラスが存在する場合(Global.aspx)はそれが生成される。また処理の手順毎にイベントが発生する。このイベントを捕捉する場合、

    先ほどの継承クラスで対応を行う必要がある。



    ※参照

    ASP.NETアプリケーションのライフサイクルの概要

  • HTTPモジュール
  • HttpApplicationクラスの各イベント処理を拡張する。

    独自のHTTPモジュールを作成する場合は、IHttpModuleインターフェイス実装クラスを作成し、Web.configへ登録する。

    (拡張は、モジュールクラス内でHttpApplicationの各イベントハンドラを実装し、Init()を実装するときにそれらをイベントを接続することで可能。)

    モジュール例として、アクセスロギングクラスが考えられる。



    ※参照

    カスタムHTTPモジュールを作成する

  • HTTPハンドラ
  • 要求種類・拡張子に対応する応答処理クラス。最終的なレスポンスはハンドラクラスが生成している。

    最も身近なものは、*.aspxへの要求を処理するASP.NETページハンドラ。

    独自のHTTPハンドラを作成する場合は、IHttpHandlerインターフェイス実装クラスを作成し、Web.configとIISへ登録する。

    ASP.NET開発サーバーではページアクセス時に、web.configのhttpHandlersノード記述エラー(ハンドラのtypeがあいまい)が発生。動作しないっぽい。(VS2005,IIS5の場合)

    使いどころとしてはアクセスチェック処理が考えられる。(画像への直接アクセス禁止など。チェックNGの場合はエラーページへリダイレクト、成功時は実ページへリダイレクトする)直接応答を生成するということはあまり行わないと思われる。


    ※参照

    HTTP ハンドラの概要

    方法 : 同期 HTTP ハンドラを作成する


  • HTTPハンドラーファクトリ
  • 応答を適切なHTTPハンドラへ割り振るファクトリクラス。


    ※参照

    方法 : HTTP ハンドラ ファクトリを作成する