我开始在MacBook Pro上使用Xamarin Studio开发Xamarin.Forms。我构建了一个应用程序,其目的是查询PrestaShop网站,检索产品并显示它们。
在将应用程序部署到Android时,我在Marshmallow下面的版本遇到了一些问题,但是我解决了它们,所以我不会在这里描述它们。
将应用程序部署到iOS(模拟器)时,我仍然遇到严重问题。应用程序运行,但是当我单击按钮以检索数据时,它会崩溃,给我一个System.ObjectDisposedException,其消息为" CancellationTokenSource已被处理"。我将在此粘贴相关的源代码:
async void button1_Click(object sender, System.EventArgs e)
{
try
{
HttpClientHandler hnd = new HttpClientHandler();
hnd.Credentials = new NetworkCredential("[apikey]", "");
string res;
using (var client = new HttpClient(hnd))
{
var responseText = await client.GetStringAsync("[endpoint]/products");
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(responseText.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
writer.Flush();
stream.Position = 0;
XDocument doc = XDocument.Load(stream);
res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
}
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
//Result.Text = data["products"].GetType().ToString() + Result.Text;
Func<string, Task> creator_method = async (string id) =>
{
try
{
var responseProd = await client.GetStringAsync($"[endpoint]/products/{id}"); // AT THIS ROW THE EXCEPTION IS RAISED!!!
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(responseProd.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
writer.Flush();
stream.Position = 0;
XDocument doc = XDocument.Load(stream);
res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
}
var product_rawData = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
var productData = (JObject)product_rawData["product"];
try
{
views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), productData["id_default_image"]["@xlink:href"].ToString()));
}
catch (NullReferenceException nre)
{
views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), ""));
}
}
catch (Exception gex) { throw; }
};
foreach (var product in ((JObject)data["products"])["product"])
try
{
Device.BeginInvokeOnMainThread(async () => { await creator_method.Invoke(product["@id"].ToString()); });
}
catch (TaskCanceledException tce) { continue; }
catch (WebException we) { continue;}
}
}
catch (HttpRequestException ex)
{
Result.Text = ex.Message;
}
}
我怎么能解决这个问题?
答案 0 :(得分:5)
&#34; CancellationTokenSource已被处理&#34;
第一次CancellationToken
来电似乎已经消耗了client.GetStringAsync()
using
。
如何解决此问题
我建议将你的第二个电话放在自己的using
块中,以避免这种情况。
以下是您的代码现在应该是什么样子,并使用第二个async void button1_Click(object sender, System.EventArgs e)
{
try
{
HttpClientHandler hnd = new HttpClientHandler();
hnd.Credentials = new NetworkCredential("[apikey]", "");
string res;
using (var client = new HttpClient(hnd))
{
var responseText = await client.GetStringAsync("[endpoint]/products");
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(responseText.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
writer.Flush();
stream.Position = 0;
XDocument doc = XDocument.Load(stream);
res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
}
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
//Result.Text = data["products"].GetType().ToString() + Result.Text;
Func<string, Task> creator_method = async (string id) =>
{
try
{
using (var newClient = new HttpClient(hnd)) // Create a new client to avoid your other one's token being consumed
{
var responseProd = await newClient.GetStringAsync($"[endpoint]/products/{id}");
using (MemoryStream stream = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
writer.Write(responseProd.Replace("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", string.Empty));
writer.Flush();
stream.Position = 0;
XDocument doc = XDocument.Load(stream);
res = JsonConvert.SerializeXNode(doc, Formatting.Indented, true);
}
var product_rawData = JsonConvert.DeserializeObject<Dictionary<string, object>>(res);
var productData = (JObject)product_rawData["product"];
try
{
views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), productData["id_default_image"]["@xlink:href"].ToString()));
}
catch (NullReferenceException nre)
{
views.Children.Add(new ProductXaml(productData["name"]["language"]["#cdata-section"].ToString(), float.Parse(productData["price"]["#cdata-section"].ToString().Replace('.', ',')), ""));
}
}
}
catch (Exception gex) { throw; }
};
foreach (var product in ((JObject)data["products"])["product"])
try
{
Device.BeginInvokeOnMainThread(async () => { await creator_method.Invoke(product["@id"].ToString()); });
}
catch (TaskCanceledException tce) { continue; }
catch (WebException we) { continue;}
}
}
catch (HttpRequestException ex)
{
Result.Text = ex.Message;
}
}
声明:
QuerySet.extra()
希望这有帮助! :)
答案 1 :(得分:0)
我遇到了同样的问题,我使用单个httpclient来处理所有api请求。
private static HttpClient httpClient;
public static HttpClient GetHttpClient()
{
if (httpClient == null)
{
httpClient = new HttpClient()
{
BaseAddress = new Uri(BaseUrl)
};
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
}
return httpClient;
}
看来你正在使用(var client = new HttpClient())...&#39; s CancellationToken已被第一个消费 client.GetStringAsync()调用。
杰夫的回答我删除了静态httpclient,现在为所有请求创建了一个新的httpclient,它解决了我的问题。
public static HttpClient GetHttpClient()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(BaseUrl)
};
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return httpClient;
}
答案 2 :(得分:0)
像这样创建HttpClient的新实例
public static HttpClient GetHttpClient()
{
HttpClient httpClient = new HttpClient()
{
BaseAddress = new Uri(BaseUrl)
};
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
return httpClient;
}