WebSurfer's Home

トップ > Blog 1   |   Login
Filter by APML

Web Forms アプリの Email Confirmation

by WebSurfer 10. August 2020 14:05

ASP.NET Web Forms アプリで登録・パスワード再取得のためのメール送信機能を利用する場合、テンプレートで実装されたコードを使うとメール本文に含まれる確認先の URL にアプリケーション名が含まれないという注意事項を書きます。(結果、メール本文に張られたリンクの URL が正しくないのでクリックしても確認できません)

アプリケーション名が含まれない

.NET Framework 版の ASP.NET Web Forms の Web アプリケーションプロジェクトを Visual Studio 2019 のテンプレートを使って、ユーザー認証に「個別のユーザーアカウント」(ASP.NET Identity) を選んで作った場合の話です。ASP.NET MVC5 ではこの問題はありません。

元の話は Teratail のスレッド「リセット画面のURLをアプリケーションルートにしたい」のものです。そのスレッドを見て初めてそういう問題があることを知りました。

メール本文に含めて送信する確認先の URL は、Models/IdentityModels.cs に含まれるヘルパーメソッド GetUserConfirmationRedirectUrl と GetResetPasswordRedirectUrl で Uri(Uri, String) コンストラクタを使って取得しています。

Uri(Uri, String) コンストラクタの第 1 引数に HttpRequest.Url プロパティで取得する Uri を、第 2 引数に "/Account/..." から始まる相対 URL の文字列を設定して Uri オブジェクトを作り、それから AbsoluteUri プロパティを使って絶対 URL を取得して確認メールの本文に張り付けています。

この記事の一番上のデバッグ画像を見てください。問題のヘルパーメソッド GetUserConfirmationRedirectUrl, GetResetPasswordRedirectUrl ではないですが、簡単に問題を再現するために Page_Load メソッドに同等のコードを書いて検証してみました。

なお、Visual Studio (IIS Express) では以下のように Request.Uri にアプリケーション名 myapp が含まれるよう[プロジェクトの URL (J)]を設定しています。

アプリケーション名 myapp を設定

上のデバッグ画像のとおり、ローカル変数の rquestUri にはアプリケーション名 myapp を含めた Uri オブジェクトを取得できています。ローカル変数 callbackUrl が確認先の URL になりますが、アプリケーション名 myapp は含まれません。これが問題です。

ちなみに、ASP.NET MVC アプリでは Url.Action を使ってアプリケーション名を含めた絶対 URL を取得していますのでこういう問題はないです。

対処方法として、ヘルパーメソッド GetUserConfirmationRedirectUrl と GetResetPasswordRedirectUrl 内にアプリケーション名をハードコーディングするのは好ましくはなさそうです。アプリケーション名の変更、アプリの移植で問題となりますので。

ルート演算子 (~) と VirtualPathUtility.ToAbsolute メソッドを利用して "~" に相当するパスを取得するのがよさそうです。具体例は以下の画像を見てください。

VirtualPathUtility.ToAbsolute メソッド利用

この記事の例のように、アプリケーション名が myapp の場合、VirtualPathUtility.ToAbsolute メソッドの引数に "~" を設定すると戻り値は "/myapp" になります。引数に "~/Account/ResetPassword" を設定すると(文字列先頭に "~" を付与している点に注意)戻り値は "/myapp/Account/ResetPassword" となります。以下の画像を見てください。

このようにすればアプリケーション名をハードコーディングしなくて済みます。


その他のパス設定の問題

テンプレートで生成されたコードのパス設定の問題は他にもあって、例えば Account/Manage.aspx ページでも以下のようにリンク先の URL にルート演算子 (~) が設定されてないです。

URL にルート演算子 (~) が設定されてない

リンクをクリックしても、普通はパスが通らないので、404 Not Found エラーとなってすぐ気が付くと思うかもしれませんが、開発環境ですと訳が分からないサーバーエラーになることがあるかもしれません。

実は、上の画像にあるように Visual Studio で[プロジェクトの URL (J)]を設定したのですが、その際 IIS Express 用の applicationHost.config 設定で application path="/" と application path="/myapp" が両方有効になって、/Account/ManagePassword.aspx に遷移できてしまったのです。

認証チケットは /mayapp/Acount/Login.aspx で取得しているのですが、/Account/ManagePassword.aspx では認証されないので User.Identity.GetUserId() でユーザー ID を取得できず訳が分からないサーバーエラーになりました。

これには半日ぐらい悩まされました。どうも Microsoft としては Web Forms アプリには力が入ってなくて、テンプレートで生成されるコードでも 100% 信頼できないような感じがします。

Tags: , ,

ASP.NET

ASP.NET アプリの Settings.settings

by WebSurfer 13. July 2020 16:44

ASP.NET Web アプリでも Web アプリケーションプロジェクトであれば Settings.settings を利用できます。ASP.NET Web アプリでこれを使うことはあまりなさそうですし、実際、自分は使ったことがないのですが、こういうこともできるということで備忘録に残しておきます。

Settings.settings の設定

上の画像は ASP.NET MVC5 アプリのプロジェクトの例です。プロジェクトルート直下にある Properties フォルダを右クリックして開き、[設定]タブを選択すると「このプロジェクトには既定の設定ファイルが含まれていません。ファイルを作成するにはここをクリックしてください。」と表示されるので、それをクリックして情報を設定できます。

Windows Forms アプリなどと同様に「種類」には文字列の他に bool, int, double, 接続文字列などを選択でき、Settings.Designer.cs に定義されている強く型付けされたプロパティを使って値を取得できます。その点では web.config の appSettings を使うよりメリットがあるかもしれません。

ただし「スコープ」はアプリケーションのみで、ユーザーは選択できません。複数のユーザーがアクセスしてくる ASP.NET Web アプリなので、当然と言えば当然なのですが。

情報の保存場所はどこになるかと言えば、.NET Framework 版の ASP.NET Web アプリでは当たり前かもしれませんが、アプリケーションルート直下の web.config になります。

web.config 内のどこにどのような形で設定情報が保存されるかと言うと、上の画像の設定例では以下のようになります。

<configuration>
  <configSections>
    <!-- 中略 -->
    <sectionGroup name="applicationSettings" 
      type="System.Configuration.ApplicationSettingsGroup, 
            System, Version=4.0.0.0, Culture=neutral, 
            PublicKeyToken=b77a5c561934e089">
      <section name="Mvc5App.Properties.Settings" 
        type="System.Configuration.ClientSettingsSection, 
              System, Version=4.0.0.0, Culture=neutral, 
              PublicKeyToken=b77a5c561934e089" 
              requirePermission="false"/>
    </sectionGroup>
  </configSections>

  <connectionStrings>
    <!-- 中略 -->
    <add name="Mvc5App.Properties.Settings.connString" 
         connectionString="Data Source=lpc:(local)\SQLEXPRESS;
                           Initial Catalog=ContosoUniversity;
                           Integrated Security=SSPI;" />
  </connectionStrings>

  <!-- 中略 -->

  <applicationSettings>
    <Mvc5App.Properties.Settings>
      <setting name="settingsInfo" serializeAs="String">
        <value>Settings.settings に追加した文字列</value>
      </setting>
      <setting name="intValue" serializeAs="String">
        <value>100</value>
      </setting>
    </Mvc5App.Properties.Settings>
  </applicationSettings>
</configuration>

configSections 要素で Settings.Designer.cs に定義された Settings クラスを利用できるように設定しています。接続文字列は connectionStrings 要素内に、int 型と string 型の値は applicationSettings 要素内に設定されています。

では、ASP.NET Web アプリが利用する別プロジェクトのクラスライブラリがあるとして、それが Settings.settings を使っている場合はどうなるでしょうか?

自動的に web.config に取り込んでくれるということはなさそうです。自分が試した限りですが、.dll.config という構成ファイルが .dll と一緒に bin フォルダに配置され、それが使われるようです。先の記事「構成ファイルの保存場所」に書いたのと同様な配置になるようです。

どのように試したかを以下に書いておきます。

MVC アプリのプロジェクトと同じソリューション内にクラスライブラリ LibraryA を追加し、Settings.settings ファイルに文字列情報を追加します。クラスファイル Class1.cs の中には設定した文字列を取得するコードを書きます。

クラスライブラリの Settings.settings

注: スコープは全て「アプリケーション」でなければなりません。一つでも「ユーザー」に設定されていると、MVC アプリから情報を取得する際、その項目が「アプリケーション」であっても ConfigurationErrorsException がスローされます。エラーメッセージは "現在の構成システムでは、ユーザーによってスコープされた設定はサポートされません" です。

MVC プロジェクトで LibraryA を参照に追加します。

参照の追加

ソリューションをビルドすると自動的に MVC プロジェクトの bin フォルダに LibraryA の .dll とともに .dll.config が コピーされます。

bin フォルダの .dll と .dll.config

その .dll.config に LibraryA の Settings.Settings ファイルに設定した情報が含まれています。MVC アプリから .dll のコード経由でその情報を取得できます。

Tags: , , ,

ASP.NET

ASP.NET / IIS の要求サイズの制約

by WebSurfer 20. November 2019 13:55

ASP.NET と IIS には要求のサイズを制限する組み込みのセキュリティ機能があります。httpRuntime 要素の maxRequestLength 属性と requestLimits 要素の maxAllowedContentLength 属性が良く知られています。

それ以外に serverRuntime 要素の uploadReadAheadSize 属性というのもあって、それに気が付かないでハマるということがありましたので、備忘録としてまとめて書いておきます。元の話は Teratail のスレッド「asp.net ajax upload でエラーになる」です。

(1) httpRuntime 要素の maxRequestLength 属性

ASP.NET の制限でデフォルトで 4MB になっています。詳しくは Microsoft のドキュメント httpRuntime 要素 (ASP.NET 設定スキーマ) を見てください。肝心な部分のみ以下に抜粋しておきます。

"入力ストリームのバッファリングしきい値の限界値を KB 単位で指定します。 この限界値は、たとえば大きいファイルをサーバーにポストするユーザーなどにより引き起こされる、サービス拒否攻撃を防止するために使用できます。既定値は 4096 です。 しきい値を超えると、ConfigurationErrorsException 例外がスローされます。"

(2) requestLimits 要素の maxAllowedContentLength 属性

IIS7 から導入された要求のフィルタリング <requestFiltering>の機能の中の requestLimits 要素の maxAllowedContentLength 属性がそれで、デフォルト値が 30,000,000 バイトになっています。下の IIS Manager での設定画面を見てください。

maxAllowedContentLength 属性

設定変更は上の画像のように IIS Manager で行うのがお勧めです。applicationHost.config ファイルをメモ帳などで開いて編集することでも可能ですが。

(3) serverRuntime 要素の uploadReadAheadSize 属性

以下の IIS Manager の画像の通りデフォルトで 49,152 バイトになっており、この制約にかかると HTTP 413 Request Entity Too Large というエラーになります。上に紹介した Teratail のスレッドの話がこの問題です。

uploadReadAheadSize 属性

Microsoft のドキュメント Solution for “Request Entity Too Large” errorLarge file upload failure for Web application calling WCF service – 413 Request entity too large によると、SSL 通信を利用しているとき、または WCF に要求を出す場合は uploadReadAheadSize 属性の制約の影響を受けるとのことです。

ただ、SSL だけでそういう問題が出るとすると FAQ レベルの話&周知の事例なのに、ググって調べた限りそうでもなさそうなのが不思議でした。

さらに調べてみると、IIS randomly returns 413 Request Entity Too Large when uploading large files and using TLS という記事が見つかり、それによると client certificate も絡んだ問題と書いてあります。

上の記事の回答で黄色のバックグラウンドとなっている部分は IIS Express を使った時のエラーメッセージのようです。その中に:

Most likely causes: The Web server cannot service the request because it is trying to negotiate a client certificate but the request entity is too large.

If using client certificates, try: Increasing system.webServer/serverRuntime@uploadReadAheadSize

・・・とあります。

実際、上に紹介した Teratail の記事の問題のサイトでは client certificate を使っているようです。

ただし、自分の環境の Visual Studio Community 2015 で IIS Express で SSL 通信を利用する設定にし、sslFlags を SslNegotiateCert に設定して試してみましたが、uploadReadAheadSize はデフォルトの 49,152 バイトのままでも問題を再現できませんでしたが・・・

(4) JSON 文字列を送信する場合の制約

JSON 文字列のデシリアライズに使用されている(と思われる)JavaScriptSerializer クラスの MaxJsonLength プロパティによって、Web サービスの場合はデフォルトで 102,400 文字に、ASP.NET MVC のアクションメソッドの場合は 2,097,152 文字に制限されています。

前者(Web サービス)の方は jsonSerialization 要素の maxJsonLength 属性の設定によって変更可能です。後者(ASP.NET MVC のアクションメソッド)の場合は 2,097,152 文字から変更できません。

2013 年時点の情報なので今は変更されているかもしれませんが、詳しくは別の記事「MVC は maxJsonLength を無視」を見てください。

Tags: , ,

ASP.NET

About this blog

2010年5月にこのブログを立ち上げました。その後 ブログ2 を追加し、ここは ASP.NET 関係のトピックス、ブログ2はそれ以外のトピックスに分けました。

Calendar

<<  September 2020  >>
MoTuWeThFrSaSu
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

View posts in large calendar