非同期性と非 UI フリーズ アプリケーションの重要性を理解することから始めます。私が本当に愛している async/await の世界全体、さらには APM や、Task
.
これで問題ありませんが、Web サービスの POST が完了するまで待ってから続行する必要があるというシナリオがあります。
public void DoSomeWorkNow()
{
// Do stuff...
// Do more stuff...
// Make the web service call..
// The request should finish and I should continue doing stuff....
// Do stuff...
}
たとえ欲しかったとしても、async/await を使用することはできませんが、問題は解決しません。使用できますが、ここでTask.FromAsync
ヒットした問題を参照でき
ます。これはライブラリであり、サードパーティの依存関係が必要ないため、サードパーティのライブラリを使用できません。
これが同期的であるべき理由は本当にあります。詳細には入りません。これは設計上の問題ではなく、設計上の機能です。
WebRequest の Begin/End 操作を使用すると、Request/Response はコールバックで発生します。それは素晴らしく、うまく機能します。現在、Web サービスに対して同期的に呼び出しを行う API はありません。GetRequest/GetRespone は Windows Phone 8 SDK ではサポートされていません。
Mutex を使用してWait
、Web サービス クラス呼び出し内でMutex.WaitOne()
、要求を終了して応答を取得する最後のコールバックが解放されるまで呼び出し元のメソッドを一時停止するメソッドを呼び出そうとしました。
理論的には動作するはずですが、 を呼び出すWaitOne()
と、最後のコールバックが戻って仕事をすることはありません。
次にIAsyncResult
、BeginXyz/EndXyz メソッドからの戻り値を使用IsComplete
して while ループをチェックし、true の場合は中断して続行すると考えました。失敗。
では、Web サービスを同期的に呼び出すための実行可能な効率的なソリューションはあるのでしょうか?
Google と stackoverflow を検索しても、有効なソリューションは返されませんでした。
更新しました
ここに私が試したいくつかのコードがあります:
public void ExecuteRequest(string url, string requestData, string filePath)
{
WebRequest request = WebRequest.Create(new Uri(url));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
((HttpWebRequest)request).UserAgent = "Tester";
request.Headers["UserName"] = "Tester";
DataWebRequest webRequestState = new DataWebRequest
{
Data = requestData,
FileName = filePath,
Request = request
};
IAsyncResult requestResult = request.BeginGetRequestStream(ar =>
{
DataWebRequest webRequestData = (DataWebRequest )ar.AsyncState;
HttpWebRequest requestStream = (HttpWebRequest)webRequestData.Request;
string data = webRequestData.Data;
// Convert the string into a byte array.
byte[] postBytes = Encoding.UTF8.GetBytes(data);
try
{
// End the operation
// Here the EndGetRequestStream(ar) throws exception System.InvalidOperationException:
// Operation is not valid due to the current state of the object
using (Stream endGetRequestStream = requestStream.EndGetRequestStream(ar))
{
// Write to the request stream.
endGetRequestStream.Write(postBytes, 0, postBytes.Length);
}
requestStream.BeginGetResponse(GetResponseCallback, webRequestData);
}
catch (WebException webEx)
{
WebExceptionStatus status = webEx.Status;
WebResponse responseEx = webEx.Response;
Debug.WriteLine(webEx.ToString());
}
}, webRequestState);
// The below while loop is actually breaking as the IsCompleted is true, but an
// exception System.InvalidOperationException is thrown after a while
while (true)
{
if (requestResult.IsCompleted) break;
}
IAsyncResult responseResult = request.BeginGetResponse(ar =>
{
DataWebRequest webRequestData = (DataWebRequest)ar.AsyncState;
HttpWebRequest httpWebRequest = (HttpWebRequest)webRequestData.Request;
try
{
// End the operation
using (HttpWebResponse response = (HttpWebResponse)httpWebRequest.EndGetResponse(ar))
{
HttpStatusCode rcode = response.StatusCode;
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
// The Response
string responseString = streamRead.ReadToEnd();
if (!string.IsNullOrWhiteSpace(webRequestData.FileName))
{
FileRepository fileRepo = new FileRepository();
fileRepo.Delete(webRequestData.FileName);
}
Debug.WriteLine("Response : {0}", responseString);
// Maybe do some other stuff....
}
}
catch (WebException webEx)
{
WebExceptionStatus status = webEx.Status;
WebResponse responseEx = webEx.Response;
Debug.WriteLine(webEx.ToString());
}
}, webRequestState);
// This while loop never actually ends!!!
while (true)
{
if (responseResult.IsCompleted) break;
}
}
ありがとうございました。