我的Monotouch应用程序正在与Web服务进行定期后台同步。它运行得很完美,并正确检测到飞行模式。当我关闭WiFi时,它会自动开始使用WWAN(GPRS,3G)连接。到目前为止,我非常满意,但是...在关闭飞行模式后,如果没有WiFi可用,我的应用程序将无法重新连接。
它使用NetworkReachability对象正确检测到WWAN可用并且需要连接。但第一次尝试超时(90秒后,我使用计时器中止运行请求)。当我再试一次时,只要调用EndGetRequestStream,就会出现WebException“错误:连接失败(无法访问主机)”。重新连接的唯一方法是启动另一个应用程序,比如Mail,以建立连接。之后,我的应用程序再次连接无缺陷。或者等待几分钟,直到iPhone进入睡眠状态。唤醒后,连接再次正常建立。
我做错了什么?
以下代码是使用ThreadPool.QueueUserWorkItem(CreateRequest)启动的。
它使用NetworkReachability对象正确检测到WWAN可用并且需要连接。但第一次尝试超时(90秒后,我使用计时器中止运行请求)。当我再试一次时,只要调用EndGetRequestStream,就会出现WebException“错误:连接失败(无法访问主机)”。重新连接的唯一方法是启动另一个应用程序,比如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;
}