前提・実現したいこと
単体では正常動作を確認できている実行ファイルが、
本番環境で他のASP.NETアプリケーションから呼び出すとエラーになります。
Foam_Loadの末尾にWebBrowserから指定URLにナビゲートする際に
エラーが発生しているのですが、
どこをどう修正すればいいのか検討がつかない状態です。
私自身がWeb系開発の初心者で、
周囲にもASP.NET Web フォームアプリケーション開発に詳しい人がいないため
初歩的な知識が抜けている可能性があります。
特定条件でのみ発生するため、環境の違いが原因だと考えています。
確認すべき点や、検索ワードのアドバイスをいただけないでしょうか。
【大まかな処理の流れ】
1.許可IPアドレスからPOSTがあればWebAPIがA.exeを実行。
2.A.exeの処理の途中でB.exeを実行。
3.B.exeの完了後にA.exeの残りの処理を実施。
4.A.exeの完了後にWebAPIからHTTPレスポンスを送信。
【実行ファイルB.exeの概要】
WebBrowserで特定のサイトにアクセスし、
ログイン~データ登録までを自動処理する
ASP.NET Webフォームアプリケーションです。
発生している問題・エラーメッセージ
B.exeのWebBrowserでのサイトへの初回アクセス時に
サイト内のファーストパーティークッキーが無効な場合のエラー画面に遷移。
ログイン画面に入ることができず、残りの処理を行えないためエラーになります。
初回のDocumentCompletedイベントの段階で、アクセスしたかったURLの末尾に
おそらくエラー時のURLパラメータが追加されており、
改めてブラウザで開くとエラー内容のみ記載された画面が表示されました。
(「jsp」拡張子のウェブサイトについては全く知識が無いため
内部の処理はいまいち想像できていません。
クッキーに関係無くこのようなエラー画面を出すこともあるのでしょうか?)
本来アクセスしたいURL(例):https://xxxxxxx/login.jsp
エラー時に取得したURL(例):https://xxxxxxx/login.jsp?Try=y
WebAPI→A.exe呼び出し(2018/10/31追記)
VB
1Dim MyProc As Process 2MyProc = New Process 3MyProc.EnableRaisingEvents = False 4MyProc.StartInfo.FileName = "C:\xxxxx\A.exe" 5MyProc.StartInfo.Arguments = "99999" '引数はユーザーID 6MyProc.Start()
A.exe→B.exe呼び出し(2018/10/31追記)
VB
1Dim procUp As New Process 2procUp.StartInfo.FileName = "C:\xxxxx\B.exe" 3'引数はエラーログとサイトでのアップロードに使用するファイルのパス 4procUp.StartInfo.Arguments = "C:\xxxxx\err.txt" & " " & "C:\xxxxx\upload.csv" 5 6Try 7 procUp.Start() 8Catch ex As Exception 9 'exeの実行で例外が出た場合は即中止 10 MyErrStream = New StreamWriter(wErrFilePath, True, System.Text.Encoding.GetEncoding("Shift-JIS")) 11 MyErrStream.WriteLine("B.exe実行時に例外が発生しました。(" & ex.GetType().ToString & ")") 12 ExeErrFG = True 13End Try 14 15If ExeErrFG = False Then 16 procUp.WaitForExit(600000) 17 If procUp.HasExited = False Then 18 procUp.Kill() 19 End If 20 '(省略) 21End If
B.exe内のWebBrowser関連の処理(2018/10/31追記)
VB
1Public WithEvents WebBrowser1 As New WebBrowser2() 2Private pURL As String = "https://xxxxxxx/" 3 4Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 5 6 '(省略) 7 8 '拡張したWebBrowser2をFormに追加 9 WebBrowser1.Dock = DockStyle.Fill 10 Controls.Add(WebBrowser1) 11 WebBrowser1.ScriptErrorsSuppressed = True 12 WebBrowser1.Navigate(pURL & "login.jsp") 'ログイン画面 13End Sub 14 15Private Sub WebBrowser1_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted 16 '「試したこと」に記載しているクッキーのチェックを行ったコード 17 'MyWStream.WriteLine("url:" & WebBrowser1.Document.Url.ToString) 18 'MyWStream.WriteLine("cookie:" & WebBrowser1.Document.Cookie) 19 20 If Environment.ExitCode = 9 Then 21 Application.Exit() 22 Else 23 If WebBrowser1.Document.Url.ToString.Contains(pURL) Then 24 '画面ごとに必要なhtml要素の有無を確認してから操作していく処理(省略) 25 Else 26 MyWStream.WriteLine("URLが不正です。(" & WebBrowser1.Document.Url.ToString & ")") 27 AppCloseRtn(9) 28 Exit Sub 29 End If 30 End If 31End Sub
WebBrowser2クラス(2018/10/31追記)
(他の人が作りかけていたものを引き継いで手探りで調べながら作成しためコメントに誤りがあるかもしれません。)
VB
1Imports System.Runtime.InteropServices 2Imports System.Security.Permissions 3 4Public Class WebBrowser2 5 Inherits WebBrowser 6 7 Private cookie As AxHost.ConnectionPointCookie 8 Private helper As WebBrowser2EventHelper 9 10 'イベントデリゲートの宣言 11 Public Event NavigateError As WebBrowserNavigateErrorEventHandler 12 13 'デリゲートの宣言 14 Public Delegate Sub WebBrowserNavigateErrorEventHandler(ByVal sender As Object, _ 15 ByVal e As WebBrowserNavigateErrorEventArgs) 16 17 <PermissionSetAttribute(SecurityAction.LinkDemand, _ 18 Name:="FullTrust")> Protected Overrides Sub CreateSink() 19 20 '派生元クラスのCreateSinkを呼び出す 21 MyBase.CreateSink() 22 23 'コントロールのイベント処理をActiveXに接続する 24 helper = New WebBrowser2EventHelper(Me) 25 cookie = New AxHost.ConnectionPointCookie( _ 26 Me.ActiveXInstance, helper, GetType(DWebBrowserEvents2)) 27 28 End Sub 29 30 <PermissionSetAttribute(SecurityAction.LinkDemand, _ 31 Name:="FullTrust")> Protected Overrides Sub DetachSink() 32 33 'ActiveXに接続されているコントロールのイベント処理を解放する 34 If cookie IsNot Nothing Then 35 cookie.Disconnect() 36 cookie = Nothing 37 End If 38 39 '派生元クラスのDetachSinkを呼び出す 40 MyBase.DetachSink() 41 42 End Sub 43 44 'ActiveXからのナビゲートエラーイベントによるコールバック 45 Protected Overridable Sub OnNavigateError( _ 46 ByVal e As WebBrowserNavigateErrorEventArgs) 47 48 RaiseEvent NavigateError(Me, e) 49 50 End Sub 51 52 'NavigateErrorイベント情報クラス 53 Private Class WebBrowser2EventHelper 54 Inherits StandardOleMarshalObject 55 Implements DWebBrowserEvents2 56 57 Private parent As WebBrowser2 58 59 Public Sub New(ByVal parent As WebBrowser2) 60 Me.parent = parent 61 End Sub 62 63 Public Sub NavigateError(ByVal pDisp As Object, _ 64 ByRef URL As Object, ByRef frame As Object, _ 65 ByRef statusCode As Object, ByRef cancel As Boolean) _ 66 Implements DWebBrowserEvents2.NavigateError 67 68 ' Raise the NavigateError event. 69 Me.parent.OnNavigateError( _ 70 New WebBrowserNavigateErrorEventArgs( _ 71 CStr(URL), CStr(frame), CInt(statusCode), cancel)) 72 73 End Sub 74 75 End Class 76 77End Class 78 79'NavigateErrorイベントのプロパティセット 80Public Class WebBrowserNavigateErrorEventArgs 81 Inherits EventArgs 82 83 Private urlValue As String 84 Private frameValue As String 85 Private statusCodeValue As Int32 86 Private cancelValue As Boolean 87 88 Public Sub New( _ 89 ByVal url As String, ByVal frame As String, _ 90 ByVal statusCode As Int32, ByVal cancel As Boolean) 91 92 Me.urlValue = url 93 Me.frameValue = frame 94 Me.statusCodeValue = statusCode 95 Me.cancelValue = cancel 96 97 End Sub 98 99 Public Property Url() As String 100 Get 101 Return urlValue 102 End Get 103 Set(ByVal value As String) 104 urlValue = value 105 End Set 106 End Property 107 108 Public Property Frame() As String 109 Get 110 Return frameValue 111 End Get 112 Set(ByVal value As String) 113 frameValue = value 114 End Set 115 End Property 116 117 Public Property StatusCode() As Int32 118 Get 119 Return statusCodeValue 120 End Get 121 Set(ByVal value As Int32) 122 statusCodeValue = value 123 End Set 124 End Property 125 126 Public Property Cancel() As Boolean 127 Get 128 Return cancelValue 129 End Get 130 Set(ByVal value As Boolean) 131 cancelValue = value 132 End Set 133 End Property 134 135End Class 136 137' NavigateErrorのインターフェース定義 138<ComImport(), Guid("34A715A0-6587-11D0-924A-0020AFC7AC4D"), _ 139InterfaceType(ComInterfaceType.InterfaceIsIDispatch), _ 140TypeLibType(TypeLibTypeFlags.FHidden)> _ 141Public Interface DWebBrowserEvents2 142 143 <DispId(271)> Sub NavigateError( _ 144 <InAttribute(), MarshalAs(UnmanagedType.IDispatch)> _ 145 ByVal pDisp As Object, _ 146 <InAttribute()> ByRef URL As Object, _ 147 <InAttribute()> ByRef frame As Object, _ 148 <InAttribute()> ByRef statusCode As Object, _ 149 <InAttribute(), OutAttribute()> ByRef cancel As Boolean) 150 151End Interface
試したこと
エラー画面でクッキーが無効という旨が記載されていたため、
B.exeを実行する状況の条件を変えながらクッキーの確認を行いました。
※クッキー=WebBrowser.Document.Cookieの想定です。
■本番に一番近い状況を確認
・FiddlerからIISで実行しているWebAPIに必要データをPOSTし、一連の処理を実行。
→エラー画面に遷移。クッキーは空でした。
・WebAPIのIIS設定「IPアドレスおよびドメインの制限」で
B.exeで操作したいサイトのIPアドレスを許可エントリに追加して
FiddlerからIISで実行しているWebAPIに必要データをPOSTし、一連の処理を実行。
→エラー画面に遷移。クッキーは空でした。
■本番サーバ上で確認
・A.exeをコマンドプロンプトでを呼び出して大まかな処理の流れの2~3を実行。
→ログイン画面に遷移。クッキーの取得はできました。
・ASP.NETのWebサイトからA.exeを呼び出して大まかな処理の流れの2~3を実行。
→エラー画面に遷移。クッキーは空でした。
■開発環境で確認
・FiddlerからVisualStudioで実行しているWebAPIに必要データをPOSTし、
一連の処理を実行。
→ログイン画面に遷移。クッキーの取得はできました。
・ASP.NETのWebサイトからA.exeを呼び出して大まかな処理の流れの2~3を実行。
→ログイン画面に遷移。クッキーの取得はできました。
なお、クッキーにはIDなど毎回テストのたびに異なっている項目があるのですが、
B.exe側から強引にクッキーをセットしてログイン画面に入る、というような方法は
不可能という認識でいいでしょうか。
補足情報(FW/ツールのバージョンなど)
【言語・環境等】
・VB
・ASP.NET v4.0
・Visual Studio 2013
・本番サーバ:Windows Server 2012 R2(IIS Version 8.5.9600.16384)
・開発環境:Windows 7 Professional(IIS Version 7.5.7600.16385)
他に試したこと2
・アプリケーションプールの詳細設定でアプリケーションプールのIDを
DefaultAppPoolから管理者権限のあるユーザーに変更。(2018/11/09追記)
期待した動作は得られるようになりましたが下記の理由で没に。現在は設定していません。
・アプリケーションプールの権限が強すぎてセキュリティ面に不安がある。
・確認した日によって動作が変わるが、理由が不明。
【サーバーメンテナンス前】
・Administartorsグループのユーザーだとクッキー無効時のエラー画面に遷移。
・Administratorがログイン状態でないとクッキー無効時のエラー画面に遷移。
【サーバーメンテナンス後】
・Administratorsグループのユーザーでも正常動作。
・ログイン状態でなくても正常動作。
・WebBrowserControl.exeのバージョンをIE11に設定。(2018/11/09追記)
→クッキー無効時のエラー画面に遷移。
・HTTPClientでの実装(2018/11/09追記)
クッキーの一部が取得できませんでした。ブラウザでサイトを開いたときの動作をFiddlerで確認したところ、ログインページのソースで指定されている外部スクリプトをGET後、その内部の処理で作成したURLをGETしてCookieの設定を追加しているようでした。作成されるURLは毎回変わります。(用語・表現が正確ではないかもしれません。)JavaScriptはブラウザで実行するもの、という認識のためHTTPClientのみではログイン不可能なサイトだと考えています。
回答2件
あなたの回答
tips
プレビュー