読者です 読者をやめる 読者になる 読者になる

プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

続 IISとASP.NETとApplicationPoolをいじっていたらよくわからない現象に悩まされたこと

前回のブログ

puni-o.hatenablog.com

の続き

前回の設定でちゃんと動くようになったと思っていたんですが、やっぱり駄目でした

そこそこ効果がありそうなおまじないを唱えることができたので、前回のものに追記しつつその対策までを(おまじないなので解決策になっていないですし、原因も大外れかもしれないです)

やったこと

追加 →

IISのApplication Initialization(だったっけ?)を有効にしてOS起動したら即Web APIをアクセスするようにした (これでサーバー起動してからお茶していれば使えるようになっている・・・)

現象

OSを起動してWeb APIにアクセスすると30分以上応答がかえって来ない

追加 →

イベントログをみたらアプリケーションプールの再起動が多発

アプリケーションプールのPingタイムアウトで強制終了 → 起動でWeb APIアクセスを繰り返していた

何かのタイミングでWeb APIが応答を返すと使えるようになる

Web APIと同じこと(Web API内ではサードパーティー製の64bit DLL (Cで使うやつ)をラップしたDLLをP/Invokeで使用)をするデスクトップアプリ(WPF製)を実行すると似たような現象が発生

アプリ起動 → 固まる(かなり待っても応答なし) → 強制終了 → 起動 → 動く

リソースモニタでアクセスするファイルを見ているとサードパーティ製DLLのインストールフォルダにあるファイル(DLLとかいろいろ)のアクセスで止まっている感じ(正常起動時はその後に別のデータの読み込みまで確認できる)

サードパーティ製DLLに付属しているアプリ(多分ネイティブアプリ)はすんなり動く

上記アプリを起動するとなぜか.Net製もいきなり動く

よく外れる予想

サードパーティ製DLLのOS起動後初回P/Invokeで、OS(または.Net)が何らかのセキュリティチェックを行っているのでは?

そのチェックがデッドロックしているので再起動でのみ復帰するのでは?

チェック結果はある程度保持されていて2回目以降のチェックは省略されるのでは?

という仮説を立てた

ちなみに私は仮説を立てて文章にするとよく外れる

おまじない1

プリロード専用のWeb APIを作成

上記APIではまずサードパーティ製DLL付属のアプリを起動(即殺す)

その後いつもの処理を実行

効果は微妙

おまじない2

サービスを一つ作成

サービスでサードパーティ製DLL付属のアプリを起動(即殺す)

効果はそこそこ

ということで現在はこの二つのおまじないでだましだまし使ってもらっている状態です

原因わかって解決する日は来るのだろうか・・・

IISとASP.NETとApplicationPoolをいじっていたらよくわからない現象に悩まされたこと

原因がわかっていないので私が気付いている範囲で環境とかやったことを書きます

環境

Windows Server 2012 R2

アプリ

ASP.NET MVCでWeb API 2 (だっけ?)を作成

Web API内ではサードパーティー製の64bit DLL (Cで使うやつ)をラップしたDLLをP/Invokeで使用

サードパーティー製DLLはそこそこ大きくてそれが読むデータも大きい (データサイズは関係ないかも)

やったこと

Administratorですべてセットアップ(ランタイムのインストールとか)

アクセス権とか面倒なのでAdministratorで動くApplicationPoolを新たに作成

アプリは上記ApplicationPoolで動かすように

現象

OSを起動してWeb APIにアクセスすると30分以上応答がかえって来ない

P/InvokeしていないAPIにアクセスするとすぐに応答を返してくれる

応答が返ってこない時のディスクアクセスとかCPU使用率はそんなに上がっていない

一度応答を返すとそのあとは普通に返ってくる

応答を返し始めるタイミングは不明 (ログとか見ていると突然返す感じ)

iisreset等で再起動かけた場合はすぐに返ってくる (返ってこない場合もあったかも)

応答が返ってこない間にApplicationPoolのpingエラーで勝手にApplicationPoolが再起動させられているっぽい (?)

解決策 (?)

使用するApplicationPoolをDefaultAppPoolに戻したら現象は発生しなくなった

ユーザー(Administratorsグループ)を新規に作ってそのアカウントでApplicationPoolを動かしても問題なし (新規ユーザーは一度もログインしていない)

 

うん、全然わからない

とりあえず動いているからいいやって感じで終了

WPFで雑にウォーターマーク付きのテキストボックスを作る

ウォーターマークのあるテキストボックス(未入力だと透かしがでるやつ)がたまにほしくなりますよね

ガッツリ作る必要もない時はテンプレートで適当に作ってしまえばいいんじゃない?

<Window.Resources>
    <Style x:Key="WatermarkTextbox" TargetType="{x:Type TextBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid Background="White">
                        <ScrollViewer x:Name="PART_ContentHost" Margin="5,0,0,0" VerticalAlignment="Center"/>
                        <TextBlock x:Name="WaterMarkLabel" Text="{TemplateBinding Tag}" Opacity=".5" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5,0,0,0" Visibility="Collapsed"/>
                    </Grid>
                    <ControlTemplate.Triggers>
                        <Trigger Property="Text" Value="">
                            <Setter Property="Visibility" TargetName="WaterMarkLabel" Value="Visible"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>
<Grid Background="Blue">
    <TextBox Style="{StaticResource WatermarkTextbox}" VerticalAlignment="Center" HorizontalAlignment="Center" Width="200" Tag="Input please"/>
</Grid>

できあがり

f:id:puni-o:20161215110421g:plain

TextBox.TagをTextBlock.Textに入れて、TriggerでTextが空白の時に表示しているだけです