WebSurfer's Home

トップ > Blog 1   |   ログイン
APMLフィルター

VS2010 によるエラーチェック

by WebSurfer 2016年7月2日 15:48

Visual Studio によるエラーチェックは Web サイトプロジェクトと Web アプリケーションプロジェクトでは異なるという話を書きます。

VS2010 エディタのエラーチェック

自分の環境(Vista SP2 32-bit, Visual Studio 2010 Professional)で検証した結果をまとめると以下のようになりました:

  1. Web サイトプロジェクト
    設定したターゲットフレームワークに応じた言語バージョンに準拠(FW3.5 なら C# 3 または VB9.0、FW4 なら C# 4 または VB10.0)
  2. Web アプリケーションプロジェクト
    Visual Studio に採用された言語バージョンに準拠(VS2010 なら C# 4 または VB10.0)

これは、基本的にソースコードのままサーバーにデプロイしてサーバー側で動的にコンパイルを行う Web サイトプロジェクトと、Visual Studio で単一アセンブリ (.dll) にコンパイルして出来上がった .dll をサーバーにデプロイする Web アプリケーションプロジェクトとの違いからきていると思われます。

言語に C# を使って検証した場合の具体的な結果を以下に書いておきます。

(1) Web サイトプロジェクト

MSDN ライブラリの記事「What's New for Visual C#」によると、VS2010 の C# の言語バージョンは C# 4 で、Dynamic、名前付き引数と省略可能なパラメーター、ジェネリックの共変性/反変性が新機能としてサポートされたとのことです。

なので、名前付き引数を使ったメソッドをターゲットフレームワーク 3.5 の Web サイトプロジェクトのコードビハインドに実装して VS2010 によるエラーチェックがどうなるかを見てみました。

その結果が一番上の画像です。エディタレベルで VS2010 のエラーチェックに引っかかり、「3.0 C# 言語使用の一部ではないため、機能 '名前付き引数' を使用することはできません。」というエラーメッセージが出ています。

Visual Studio 上でビルドをかけると、[エラー一覧]にエラーが表示され(エディタレベルのエラーメッセージとは異なりますが)、ビルドに失敗します。もちろん実行はできません。

ブラウザのアドレスバーに直接 URL を入力して、ブラウザから問題のページを要求すると、サーバー側での動的コンパイルでコンパイルエラーとなり、以下の画像のサーバーエラーが応答として返ってきます。

動的コンパイルでのエラー

これは web.config で、サーバー側で動的コンパイルに使うコンパイラが以下のように設定されており、これに従って C:\Windows\Microsoft.NET\Framework\v3.5 にあるコンパイラ csc.exe(自分の環境では製品バージョン 3.5.307129.1・・・名前付き引数はサポートしていない)が使用されるためです。

<system.codedom>
  <compilers>
    <compiler 
      language="c#;cs;csharp" 
      extension=".cs" 
      warningLevel="4"
      type="Microsoft.CSharp.CSharpCodeProvider, System, 
            Version=2.0.0.0, 
            Culture=neutral, 
            PublicKeyToken=b77a5c561934e089">
      <providerOption name="CompilerVersion" value="v3.5"/>
      <providerOption name="WarnAsError" value="false"/>
    </compiler>
 </compilers>
</system.codedom>

同じコードをターゲットフレームワークが 4 の Web サイトプロジェクトに実装すれば、当然ながらエラーメッセージ等は一切出ず、ビルドも実行も問題ありません。

(2) Web アプリケーションプロジェクト

上記 (1) と同じコードをターゲットフレームワーク 3.5 の Web サイトプロジェクトのコードビハインドに実装してみます。動的コンパイルに使うコンパイラの設定(web.config の system.codedom 要素の設定)は上の (1) Web サイトプロジェクトの場合と同じです。

結果、上記 (1) Web サイトプロジェクトの時のようなエディタ上のエラーは出ません。ビルドも通りますし、実行上も問題ありません。

ということは、ターゲットフレームワークの設定には関係なく、VS2010 に採用された言語バージョン C# 4 をベースに VS2010 のエディタ上でエラーチェックが行われ、ビルドも言語バージョン C# 4 のコンパイラで行われているということになります。

では、動的コンパイルが行われる部分はどうでしょうか?(Web アプリケーションプロジェクトでも .aspx ファイルや App_Code のソースなどはデフォルトではサーバー側で動的コンパイルが行われます)

まず、.aspx ファイルに以下のようなコードブロック(<% から %> までのコード)を実装してみます。

<body>
  <form id="form1" runat="server">
  <div>
    <asp:Label ID="Label1" runat="server"></asp:Label>
    <br />
    <% =CalculateBMI(height: 64, weight: 123) %>
  </form>
</body>

そうすると、エディタレベルで一番上と同様なエラーが表示されます。ただし、コードブロックの部分は Visual Studio ではコンパイルされないためか、ビルドは通ります。実行したりブラウザから要求をかけた場合は動的コンパイルが行われ、コードブロックの部分でコンパイルエラーとなり、上の 2 つ目の画像と同様なサーバーエラーとなります。

次に、App_Code に以下のようなクラスファイルを実装してみます。クラスファイル Class1.cs のビルドアクションは「コンテンツ」「コンパイル」いずれの場合もエディタレベルではエラーは表示されません。ビルドも通ります。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Framework35CSharp.App_Code
{
  public class Class1
  {
    public int CalculateBMI(int weight, int height)
    {
      return (weight * 703) / (height * height);
    }

    public string BMI64x123()
    {
      return CalculateBMI(height: 64, weight: 123).ToString();
    }
  }
}

2 重コンパイルの問題を避けるためにクラスファイル Class1.cs のビルドアクションは「コンテンツ」として実行してみます。するとサーバー側で動的コンパイルが行われ、名前付き引数を使っているところでコンパイルエラーとなり、上の 2 つ目の画像と同様なサーバーエラーとなります。ブラウザから要求をかけた場合も同様にサーバーエラーが返ってきます。(ビルドアクションを「コンパイル」にしても同様に動的コンパイルでエラーになります)

元は MSDN Forum の「ASPNET WEBサイト(VB)で、yieldが使用できない」という表題のスレッドでの話で、VB.NET の場合の検証結果はそちらに書きましたが若干様子が異なります。

また、そのフォーラムに VS2012 / 2013 では Web アプリケーションプロジェクトの App_Code フォルダでもエディタによるエラーチェックは働くという話があります。Visual Studio のバージョンによって異なるのかもしれません。(自分は検証できる環境を持ってないので未確認ですが)

Tags: ,

ASP.NET

IIS ログの time-taken

by WebSurfer 2016年7月1日 14:39

IIS のログの中に time-taken という項目があります。具体的にいつからいつまでの時間かについて調べたのですが、その過程でいくつか発見があったので備忘録として書いておきます。

リクエスト処理の流れ

上の図は IIS7 がブラウザから要求を受けて応答を返すまでの流れを示しています。この図で time-taken はいつからいつまでになるかを簡単に書くと、上の図の ② で HTTP.sys が要求の最初のバイトを受け取ってから、⑨ で要求に対する最後の応答を返すまでとなります。

それに加えて、IIS6 からは最後のパケットに対するクライアントからの ACK を受け取るまでが time-taken に含まれるようになったとのことです。

詳しくは以下の Microsoft Support KB944884 の記事を見てください。

Description of the time-taken field in IIS 6.0 and IIS 7.0 HTTP logging

タイトルが "IIS 6.0 and IIS 7.0" となっていますが、IIS7.5 以降も同じだと思います。また、また例外の "TCP buffering is used" は ASP.NET Web アプリには関係なさそうです(公式文書などで裏は取れていませんが、この記事の下の方に書いた報告などからも ASP.NET でバッファを有効にしているとは考えにくいです)。

Microsoft の別の記事(例えば、Default Log File Settings for Web Sites とか W3C Logging)に "Time taken does not reflect time across the network" と書いてあるものもありますが、古い記述のままで修正がされてないものと思われます。

というわけで、今回分かったことを箇条書きにすると以下の通りです:

  1. time-taken は上の図で ② から ⑨ までの時間。
  2. 通常、一番最初の要求を受けてワーカープロセスを起動・初期化しログファイルを開くという操作が行われる。なので、一番最初の要求では time-taken はその分長くなる。
  3. IIS6 以降では上に紹介した KB944884 の記事に書いてあるように network time も time-taken に含まれる。それゆえ、サイズの大きなファイルを遅いネットワークでダウンロードしたりすると time-taken の値は予想よりかなり大きくなることがある。
  4. トレース情報で調べられる時間やプログラムで Stopwatch などを使って調べられる時間は上の図の ⑦ から ⑧ までの範囲内なので、当然 time-Taken の方が長くなる。

上記 3 すなわち「network time も time-taken に含まれる」を裏付けるような、time-taken の値が executionTimeout を越えているとか、プログラムのコードで実際に計った時間よりはるかに長いという報告を stackoverflow に見つけましたので、参考にリンクを張っておきます。

In our IIS logs, why do requests last 5 min and longer when executionTimeout is 110 seconds?

Difference in time-taken in IIS and ASP.NET

Tags: , ,

Windows Server

WCF と executionTimeout

by WebSurfer 2016年6月18日 13:23

ASP.NET でホストされていても、WCF サービスを要求した場合は httpRuntime 要素の executionTimeout 属性の設定は効かない(タイムアウトしない)という話を書きます。

元は MSDN Forum の「webconfig 内の executionTimeout 値が有効にならない」という表題のスレッドでの話です。

MSDN Forum での話では、非同期ではないのかとか ASP.NET 互換モードの設定がされてないのではとかいろいろ紆余曲折ありましたが、結局一番の原因は:

ASP.NET でホストされていても、.NET 3.0 SP1 以降 WCF サービスを要求した場合は executionTimeout が Int32.MaxValue に設定される

・・・ということだと分かりました。

ググって見つけた記事「All WCF timeouts explained」にそれが書いてありました。記事の一番下に "Nowadays (.NET 3.0 SP1 and later) there is no more to say. The ExecutionTimeout is set to int.MaxValue for WCF requests. Thereby WCF is granted full control over its own request lifetimes." という記述があります。

上記の記事を裏付ける Microsoft の公式文書は見つかっていませんが、実際に検証してタイムアウトしないことやHttpServerUtility.ScriptTimeout プロパティ設定値を調べた結果から、間違いないようです。

MSDN Blog の記事(例えば「Timeouts in WCF and their default values」)などによると、WCF サービスでも ASP.NET でホストされていれば executionTimeout 属性の設定は有効というようなことが書いてあって惑わされましたが、それは .NET 3.0 SP1 適用前の話だったようです。

主な話は以上ですが、これを調べる過程でタイムアウトや WCF に関することがいろいろわかったので、忘れないように以下にまとめて書いておきます。

  1. WCF サービスでは executionTimeout 属性の設定は効かない
    WCF サービスを要求した場合は executionTimeout が Int32.MaxValue に設定されます。ScriptTimeout プロパティの値で確認すると、compilation debug="false" / "true" の設定に関わらず Int32.MaxValue 即ち 2147483647 になることが確認できます。
  2. タイムアウトのチェックは 15 秒毎
    MSDN Blog の記事「How the Execution Timeout is managed in ASP.NET」によると、タイムアウトは System.Threading.Timer によって 15 秒毎に発生するイベントでチェックしているとのことです。従って、普通の .aspx ページなど executionTimeout が有効な場合でも、設定された時間で正確にタイムアウトすることはないです。
  3. 非同期ではタイムアウトさせられない
    ASP.NET の非同期というのは MSDN の記事「ASP.NET の非同期/待機の概要」に書いてあることですが、その記事の図3にあるように、「外部リソースを非同期に待機中」はスレッドプールにスレッドが戻されます。一方、上記 2 で紹介した MSDN Blog の記事に書かれていますように、タイムアウトはスレッドを Abort することで行われるそうです。ということは、非同期の場合はタイムアウトさせるスレッドが存在しない(=タイムアウトさせられない)ということになります。.NET 4.5 では async / await が使えるようになって、Visual Studio でコードを生成する際に自動的に非同期になるようですが、その場合は executionTimeout が有効にならないと思います。(未検証です)
  4. WCF サービスには非同期 HTTP ハンドラを利用できる
    MSDN Blog の記事「Orcas SP1 Improvement: Asynchronous WCF HTTP Module/Handler for IIS7 for Better Server Scalability」によると、.NET 3.5 SP1 から非同期版ハンドラが利用できるようになったそうです。自分の開発マシン (Vista SP2 32-bit, IIS7) を調べてみると、記事に書いてある通りの同期版・非同期版両方のハンドラが存在してました。記事によるとデフォルトでは同期版を使うそうです。しかし、自分の環境でHttpContext.Handler プロパティを使って調べた限りでは非同期版が使われていました。MSDN Blog の記事と矛盾する理由は不明です。
  5. debag="true" の場合の executionTimeout
    MSDN ライブラリの executionTimeout 属性の説明には "このタイムアウトは、compilation 要素のデバッグ属性が False の場合だけ適用されます" と書いてありますが、普通の .aspx ページを呼び出したとき compilation debug="true" では、ScriptTimeout プロパティの値で確認すると 30000000 になります。(WCF サービスを呼び出したときは、debug="false" / "true" に関わらず、ScriptTimeout プロパティの値は Int32.MaxValue 即ち 2147483647 になります)

Tags: ,

ASP.NET

About this blog

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

Calendar

<<  2017年1月  >>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

View posts in large calendar