それだけの価値があるため、既存の ASP.NET Web アプリケーションで自分自身を認証するコンソール アプリケーションを取得することができました。ビューステート情報を含むログイン ページに POST リクエストを送信することで、ログイン ページを模倣するだけです (ブラウザがリクエストを行ったかのように)。
次に、応答として返された Cookie を CookieContainer でキャッチします。
その後、アプリケーションは同じページに対して複数のリクエストを行います (これには承認が必要です)。ページは何らかの作業を行い、サーバーにファイルを書き出します。
私が遭遇している問題は、偽のログインの後、最初の 2 つの要求が問題なく通過することです。3 番目の要求は、応答を受け取ることさえありません。以下は、リクエストを行うために使用しているコードです。
ログインします:
private static CookieContainer PerformLoginRequest()
{
string loginURL = "http://www.myDomain.com/mySite/login.aspx";
//Set up the request and give it a cookie container.
CookieContainer cookieJar = new CookieContainer();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(loginURL);
request.CookieContainer = cookieJar;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
//Grab the request body so we can put important information in it.
Stream requestBody = request.GetRequestStream();
string postData = "__VIEWSTATE=GIBBERISH&UserName=USERNAME&Password=PASSWORD%21&LoginButton.x=0&LoginButton.y=0";
//Throw the string into the body.
ASCIIEncoding encoding = new ASCIIEncoding();
byte[] byte1 = encoding.GetBytes(postData);
requestBody.Write(byte1, 0, byte1.Length);
requestBody.Close();
//Get the response to the login request.
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string result = reader.ReadToEnd();
reader.Close();
return cookieJar;
}
ページをリクエストするには:
private static long RequestPage(string url)
{
//If we've already got a CookieContainer, then we've logged in already. Otherwise, log in.
if (cookieJar == null)
{
try
{
cookieJar = PerformLoginRequest();
}
catch
{
throw;
}
}
//Set up the request.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
request.CookieContainer = cookieJar;
request.Method = "GET";
request.ContentType = "application/x-www-form-urlencoded";
request.Timeout = timeout; //5 minutes.
WebResponse response = request.GetResponse();
return response.ContentLength;
}
cookieJar およびタイムアウト変数は、アプリケーションに対してグローバルです。
何が原因でしょうか?
更新 (2010 年 1 月 17 日午後 3 時 30 分 EST)
Fiddler を実行してアプリケーションを起動すると、すべてがうまくいきます。期待どおり、すべてのリクエストが機能します。
IIS ログ ファイルを調べました。それらの中で、最初のログイン リクエスト、ログイン後のリダイレクト、および最初の 2 ページのリクエストを確認できます。しかし、その後...何もありません。リクエストがWebサーバーに届かないようです。
更新 (2010 年 1 月 18 日午前 11 時 29 分 EST)
Chris B. Behrens によって提案された変更を反映するために、コードを更新しました。しかし、役に立たない。重要な場合、上記の関数を呼び出すループは次のようになります。
private static void RegenerateNecessaryForms(MyEntities context)
{
var items = context.Items.Where(i => i.NeedsProcessing == true);
var area = context.Areas;
foreach (Item i in items)
{
bool success = true;
foreach (Area area in areas)
{
try
{
string url = string.Format("http://{0}/mySite/process.aspx?item={1}&area={2}", targetDomain, i.ItemName, area.AreaName);
long result = RequestPage(url, m);
}
catch
{
success = false;
}
}
if (success)
{
i.NeedsProcessing = false;
}
}
}
更新 (2010 年 1 月 18 日、東部標準時午後 1 時 3 分) これはおそらく、これまでに提供できた中で最も有用な情報です。
IIS ログをもう一度見ていました。ログイン要求が送信されたら、ログをフラッシュするとすぐに表示されます。ただし、コンソール アプリケーションを閉じるまで、ページ リクエストは表示されません。ログの関連するビットは次のとおりです。
2011-01-18 17:44:54 X.X.X.X POST /MySite/login.aspx - 80 - X.X.X.X - 302 0 0 148
2011-01-18 17:44:54 X.X.X.X GET /MySite/default.aspx - 80 AutomatedUser X.X.X.X - 200 0 0 48
2011-01-18 17:54:33 X.X.X.X GET /MySite/process.aspx model=ITEM_ONE&area=US 80 AutomatedUser X.X.X.X - 200 0 995 579100
2011-01-18 17:54:33 X.X.X.X GET /MySite/process.aspx model=ITEM_ONE&area=CANADA 80 AutomatedUser X.X.X.X - 200 0 995 553247
2011-01-18 17:54:33 X.X.X.X GET /MySite/process.aspx model=ITEM_TWO&area=US 80 AutomatedUser X.X.X.X - 200 0 995 532824
process.aspx に対する各 GET 要求は、上記の RequestPage メソッドの呼び出しに対応しています。「request.GetResponse();」という行 約 10 秒ほどしかかかりませんが、アプリケーションを閉じるまで、(少なくとも IIS によると) リクエストが完了しないように見えます。(各行の最後の数字を見ると、それはミリ秒単位でページを提供するのにかかった時間ですが、私はそれよりもはるかに短い時間でアプリケーションに応答を返しました。) ) IIS が 1 つの IP から受け入れる接続の量を制限していること。
これは私に質問をもたらします: 私が行っている要求について、それらがそのように「オープン」のままになる原因は何ですか?
リクエストは HTML ページを返さず (問題がある場合)、PDF を返します。