Xamarin Http 请求超时问题
Xamarin Http Request Timeout Issue
我有一个基于 Xamarin 的移动应用程序和一个基于 .Net Core 的 Web API。移动应用程序通过 HttpClient 使用 Web API 的方法。下面的代码是我调用任何 Web API 方法的基本方法,重点是我想设置超时但无论我实现了什么都无法设置准确的超时值。尝试了 Timespan.FromSeconds() 或 TimeSpan.FromMilliseconds() 等。当客户端向 Web API 发出请求时,显示加载程序以锁定 UI 并在 API 之后删除回复。一些客户给我的反馈是加载程序永远显示并且请求永远不会结束。也许,服务器在这个特定时间无法访问,或者客户端的互联网连接中断等。我只想设置超时并中断请求并向客户端显示警报消息。当然,我用谷歌搜索并尝试了很多,但没有结果。如果有人能帮助我,将不胜感激。
public async Task<BaseResponseModel> Post(BasePostModel postModel)
{
var responseModel = new BaseResponseModel();
var json = postModel.ToString();
var jsonParam = new StringContent(json, Encoding.UTF8, "application/json");
var isPosted = true;
var clientHandler = new HttpClientHandler()
{
AllowAutoRedirect = true,
};
var url = GetURL(postModel.UrlKey);
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
ContractResolver = new DefaultContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var client = new HttpClient(clientHandler);
//client.Timeout = TimeSpan.FromSeconds(10);
//var cancellationTokenSource = new CancellationTokenSource();
//cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("X-Env", "MOBILE_API");
AttachToken(ref client, responseModel.Id);
try
{
if (Preferences.ContainsKey("UserJwtExprieDate"))
{
var expiryDate = Preferences.Get("UserJwtExprieDate", null);
if (DateTime.Now > DateTime.Parse(expiryDate))
{
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
int index = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
Page currPage = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack[index];
if (currPage as SigninForFactorOne != null)
{}
else
{
App.LogoutUser();
}
}
else
{
var response = await client.PostAsync(url, jsonParam);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
if (resultModel.ErrorType == APIErrorTypes.NULL)
{
if (resultModel.IsSucceed)
{
responseModel.Data = resultModel.Data;
}
else
{
responseModel.Error = resultModel.Error;
}
responseModel.Message = resultModel.Message;
}
else
{
responseModel.Error = "Token Expried Date.";
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
App.LogoutUser();
}
}
else
{
new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
isPosted = false;
}
}
}
else
{
var response = await client.PostAsync(url, jsonParam);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
if (resultModel.ErrorType == APIErrorTypes.NULL)
{
if (resultModel.IsSucceed)
{
responseModel.Data = resultModel.Data;
}
else
{
responseModel.Error = resultModel.Error;
}
responseModel.Message = resultModel.Message;
}
else
{
responseModel.Error = "Token Expried Date.";
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
App.LogoutUser();
}
}
else
{
new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
isPosted = false;
}
}
}
catch (Exception ex)
{
new AppException(ex, responseModel.Id, 500, "anonymous.user", "Unable to post data to API!");
isPosted = false;
}
finally
{
if (!isPosted)
{
responseModel.Error = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
responseModel.Message = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
}
}
return responseModel;
}
我已经使用下面的解决方案手动设置了一个工作正常的超时。
internal class TimeOutHandler : DelegatingHandler
{
private readonly TimeSpan TimeOut;
public TimeOutHandler(TimeSpan timeOut) => TimeOut = timeOut;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage req, CancellationToken ct)
{
using (var ctTimeOut = CancellationTokenSource.CreateLinkedTokenSource(ct))
{
ctTimeOut.CancelAfter(TimeOut);
try
{
return await base.SendAsync(req, ctTimeOut.Token);
}
catch (OperationCanceledException) when (!ct.IsCancellationRequested)
{
throw new TimeoutException();
}
}
}
}
如何使用
var interval = TimeSpan.FromSeconds(10);
var handler = new TimeOutHandler(interval)
{
InnerHandler = new HttpClientHandler()
};
var client = new HttpClient(handler);
有关更多信息,请查看:https://thomaslevesque.com/2018/02/25/better-timeout-handling-with-httpclient/
我有一个基于 Xamarin 的移动应用程序和一个基于 .Net Core 的 Web API。移动应用程序通过 HttpClient 使用 Web API 的方法。下面的代码是我调用任何 Web API 方法的基本方法,重点是我想设置超时但无论我实现了什么都无法设置准确的超时值。尝试了 Timespan.FromSeconds() 或 TimeSpan.FromMilliseconds() 等。当客户端向 Web API 发出请求时,显示加载程序以锁定 UI 并在 API 之后删除回复。一些客户给我的反馈是加载程序永远显示并且请求永远不会结束。也许,服务器在这个特定时间无法访问,或者客户端的互联网连接中断等。我只想设置超时并中断请求并向客户端显示警报消息。当然,我用谷歌搜索并尝试了很多,但没有结果。如果有人能帮助我,将不胜感激。
public async Task<BaseResponseModel> Post(BasePostModel postModel)
{
var responseModel = new BaseResponseModel();
var json = postModel.ToString();
var jsonParam = new StringContent(json, Encoding.UTF8, "application/json");
var isPosted = true;
var clientHandler = new HttpClientHandler()
{
AllowAutoRedirect = true,
};
var url = GetURL(postModel.UrlKey);
var settings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
MissingMemberHandling = MissingMemberHandling.Ignore,
ContractResolver = new DefaultContractResolver(),
ReferenceLoopHandling = ReferenceLoopHandling.Ignore
};
var client = new HttpClient(clientHandler);
//client.Timeout = TimeSpan.FromSeconds(10);
//var cancellationTokenSource = new CancellationTokenSource();
//cancellationTokenSource.CancelAfter(TimeSpan.FromSeconds(10));
client.DefaultRequestHeaders.Add("Accept", "application/json");
client.DefaultRequestHeaders.Add("X-Env", "MOBILE_API");
AttachToken(ref client, responseModel.Id);
try
{
if (Preferences.ContainsKey("UserJwtExprieDate"))
{
var expiryDate = Preferences.Get("UserJwtExprieDate", null);
if (DateTime.Now > DateTime.Parse(expiryDate))
{
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
int index = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack.Count - 1;
Page currPage = Xamarin.Forms.Application.Current.MainPage.Navigation.NavigationStack[index];
if (currPage as SigninForFactorOne != null)
{}
else
{
App.LogoutUser();
}
}
else
{
var response = await client.PostAsync(url, jsonParam);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
if (resultModel.ErrorType == APIErrorTypes.NULL)
{
if (resultModel.IsSucceed)
{
responseModel.Data = resultModel.Data;
}
else
{
responseModel.Error = resultModel.Error;
}
responseModel.Message = resultModel.Message;
}
else
{
responseModel.Error = "Token Expried Date.";
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
App.LogoutUser();
}
}
else
{
new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
isPosted = false;
}
}
}
else
{
var response = await client.PostAsync(url, jsonParam);
if (response.IsSuccessStatusCode)
{
string result = response.Content.ReadAsStringAsync().Result;
var resultModel = JsonConvert.DeserializeObject<BaseResponseModel>(result, settings);
if (resultModel.ErrorType == APIErrorTypes.NULL)
{
if (resultModel.IsSucceed)
{
responseModel.Data = resultModel.Data;
}
else
{
responseModel.Error = resultModel.Error;
}
responseModel.Message = resultModel.Message;
}
else
{
responseModel.Error = "Token Expried Date.";
Preferences.Remove("UserJwtExprieDate");
Preferences.Remove("HomePageInformation");
App.LogoutUser();
}
}
else
{
new AppException(new Exception("HTTP Client response is not succeed!"), responseModel.Id);
isPosted = false;
}
}
}
catch (Exception ex)
{
new AppException(ex, responseModel.Id, 500, "anonymous.user", "Unable to post data to API!");
isPosted = false;
}
finally
{
if (!isPosted)
{
responseModel.Error = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
responseModel.Message = AppConfiguration.GetSystemMessage(contactYourSystemAdministratorMessage);
}
}
return responseModel;
}
我已经使用下面的解决方案手动设置了一个工作正常的超时。
internal class TimeOutHandler : DelegatingHandler
{
private readonly TimeSpan TimeOut;
public TimeOutHandler(TimeSpan timeOut) => TimeOut = timeOut;
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage req, CancellationToken ct)
{
using (var ctTimeOut = CancellationTokenSource.CreateLinkedTokenSource(ct))
{
ctTimeOut.CancelAfter(TimeOut);
try
{
return await base.SendAsync(req, ctTimeOut.Token);
}
catch (OperationCanceledException) when (!ct.IsCancellationRequested)
{
throw new TimeoutException();
}
}
}
}
如何使用
var interval = TimeSpan.FromSeconds(10);
var handler = new TimeOutHandler(interval)
{
InnerHandler = new HttpClientHandler()
};
var client = new HttpClient(handler);
有关更多信息,请查看:https://thomaslevesque.com/2018/02/25/better-timeout-handling-with-httpclient/