Мое приложение monotouch периодически выполняет фоновую синхронизацию с веб-сервисом. Он отлично работает и правильно определяет режим полета. Когда я отключаю Wi-Fi, он автоматически запускается через соединение WWAN (GPRS, 3G). Пока что я очень доволен, но ... После отключения режима «В самолете» мое приложение не сможет восстановить соединение, когда WiFi недоступен.
Он правильно определяет с помощью объекта NetworkReachability, что WWAN доступен и требуется соединение. Но время первой попытки истекло (через 90 секунд я отменяю запущенный запрос, используя таймер). При повторной попытке я получаю WebException «Ошибка: ConnectionFailure (нет маршрута к хосту)», как только я вызываю EndGetRequestStream. Единственный способ подключиться снова - запустить другое приложение, такое как Mail, которое устанавливает соединение. После этого мое приложение снова без проблем подключается. Или подождать несколько минут, пока iPhone не заснет. После пробуждения соединение снова устанавливается нормально.
Что я делаю не так?
Приведенный ниже код запускается с использованием ThreadPool.QueueUserWorkItem (CreateRequest);
/// <summary>
/// Sync step 1: Create the request and start asynchronously sending the data.
/// </summary>
private void CreateRequest(object state)
{
try
{
Console.WriteLine("Phase 1 started...");
if (!IsNetworkAvailable())
{
Ready(SyncState.NoConnection);
return;
}
UIApplication.SharedApplication.NetworkActivityIndicatorVisible = true;
_request = (HttpWebRequest)WebRequest.Create(SyncUrl);
_request.Method = HttpMethodPost;
_request.ContentType = HttpContentTypeJson;
Console.WriteLine("Phase 2 is starting...");
_request.BeginGetRequestStream(new AsyncCallback(StartRequest), null);
}
catch (WebException e)
{
Console.WriteLine("WebException: " + e.Message + "\r\nStatus: " + e.Status);
Ready(SyncState.ConnectionError);
}
}
/// <summary>
/// Sync step 2: Read syncdata from database and send to server.
/// Start getting the response asynchronously.
/// </summary>
private void StartRequest(IAsyncResult asyncResult)
{
Console.WriteLine("Phase 2 started...");
try
{
using (var stream = _request.EndGetRequestStream(asyncResult))
{
using (var textStream = new StreamWriter(stream))
{
Database.Instance.CreateSyncData().Save(textStream);
}
}
Console.WriteLine("Phase 3 is starting...");
_request.BeginGetResponse(new AsyncCallback(ProcessResponse), null);
}
catch (WebException e)
{
Console.WriteLine("WebException: " + e.Message + "\r\nStatus: " + e.Status);
Ready(SyncState.ConnectionError);
}
}
/// <summary>
/// Sync step 3: Get the response and process.
/// </summary>
private void ProcessResponse(IAsyncResult asyncResult)
{
Console.WriteLine("Phase 3 started...");
try
{
using (HttpWebResponse response = (HttpWebResponse)_request.EndGetResponse(asyncResult))
{
using (var textStream = new StreamReader(response.GetResponseStream()))
{
var data = (JsonObject)JsonObject.Load(textStream);
Database.Instance.ProcessSyncReply(data);
Console.WriteLine("Success: " + data.ToString());
LastSyncTime = DateTime.Now;
Ready(SyncState.Synchronized);
}
}
}
catch (WebException e)
{
Console.WriteLine("WebException: " + e.Message + "\r\nStatus: " + e.Status);
Ready(SyncState.ConnectionError);
}
}
private bool IsNetworkAvailable(out bool connectionRequired, out bool onlyWWAN)
{
bool flagsAvailable;
NetworkReachabilityFlags networkReachabilityFlags = (NetworkReachabilityFlags)0;
using (var networkReachability = new NetworkReachability(HostName))
{
flagsAvailable = networkReachability.TryGetFlags(out networkReachabilityFlags);
}
connectionRequired = 0 != (networkReachabilityFlags & NetworkReachabilityFlags.ConnectionRequired);
onlyWWAN = 0 != (networkReachabilityFlags & NetworkReachabilityFlags.IsWWAN);
return flagsAvailable && 0 != (networkReachabilityFlags & NetworkReachabilityFlags.Reachable);
}
private bool IsNetworkAvailable()
{
bool connectionRequired;
bool onlyWWAN;
bool available = IsNetworkAvailable(out connectionRequired, out onlyWWAN);
string status = "Network status: ";
if (!available)
status += "Not available";
else
{
status += "Available; ";
if (onlyWWAN)
status += "Mobile; ";
if (connectionRequired)
status += "Connection required";
}
Console.WriteLine(status);
return available;
}