【发布时间】:2017-01-22 21:11:08
【问题描述】:
我有一个使用 System.Net.Http.HttpClient 的项目。我正在尝试集中对我的 Web API 的所有调用,以便我有常见的错误处理等。我在我的项目中创建了以下类。
using ModernHttpClient;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading.Tasks;
namespace WebAPIHelper
{
class WebAPICaller
{
public async Task<string> CallWebService(string ps_URI)
{
HttpClient lobj_HTTPClient = null;
HttpResponseMessage lobj_HTTPResponse = null;
string ls_Response = "";
//We assume the internet is available.
try
{
//Get the Days of the Week
lobj_HTTPClient = new HttpClient(new NativeMessageHandler());
lobj_HTTPClient.BaseAddress = new Uri(App.APIPrefix);
lobj_HTTPClient.DefaultRequestHeaders.Accept.Clear();
lobj_HTTPClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
lobj_HTTPResponse = await lobj_HTTPClient.GetAsync(ps_URI);
if (!lobj_HTTPResponse.IsSuccessStatusCode)
{
Debug.WriteLine(lobj_HTTPResponse.ReasonPhrase);
}
else
{
ls_Response = await lobj_HTTPResponse.Content.ReadAsStringAsync();
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
if (lobj_HTTPClient != null)
lobj_HTTPClient.Dispose();
if (lobj_HTTPResponse != null)
{
lobj_HTTPResponse.Dispose();
}
}
return ls_Response;
}
}
}
我从我在 ViewModel 类中为语言创建的实例对象调用函数,如下所示:
using ModernHttpClient;
using Newtonsoft.Json;
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace WebAPIHelper
{
public class VM_Languages : INotifyPropertyChanged
{
/// <summary>
/// A collection for CGSLanguage objects.
/// </summary>
public ObservableCollection<GBSLanguage_ForList> Items_ForList { get; private set; }
const string ic_LanguagesAPIUrl = @"/languages/true";
/// <summary>
/// Constructor for the Languages view model.
/// </summary>
public VM_Languages()
{
this.Items_ForList = new ObservableCollection<GBSLanguage_ForList>();
}
/// <summary>
/// Indicates of the view model data has been loaded
/// </summary>
public bool IsDataLoaded
{
get;
private set;
}
/// <summary>
/// Creates and adds a the countries to the collection.
/// </summary>
public async Task LoadData()
{
HttpClient lobj_HTTPClient = null;
HttpResponseMessage lobj_HTTPResponse = null;
string ls_Response = "";
try
{
IsDataLoaded = false;
string ls_WorkLanguageURI = ic_LanguagesAPIUrl;
//Get the Days of the Week
lobj_HTTPClient = new HttpClient(new NativeMessageHandler());
lobj_HTTPClient.BaseAddress = new Uri(App.APIPrefix);
lobj_HTTPClient.DefaultRequestHeaders.Accept.Clear();
lobj_HTTPClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
**//This call will not work
//WebAPICaller lobj_APICaller = new WebAPICaller();
//ls_Response = lobj_APICaller.CallWebService(ls_WorkLanguageURI).Result;
//This call will work
lobj_HTTPResponse = await lobj_HTTPClient.GetAsync(ls_WorkLanguageURI);**
if (lobj_HTTPResponse.IsSuccessStatusCode)
{
if (this.Items_ForList != null)
this.Items_ForList.Clear();
ls_Response = await lobj_HTTPResponse.Content.ReadAsStringAsync();
Items_ForList = JsonConvert.DeserializeObject<ObservableCollection<GBSLanguage_ForList>>(ls_Response);
}
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
finally
{
this.IsDataLoaded = true;
NotifyPropertyChanged("GBSLanguages_ForList");
}
}
/// <summary>
/// Notifies subscribers that a property has changed.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (null != handler)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
我的所有 ViewModel 都在一个静态类中,所以我只能得到它们的一个实例,如下所示:
namespace WebAPIHelper
{
public static class ViewModelObjects
{
private static VM_Languages iobj_Languages;
public static VM_Languages Languages
{
get
{
if (iobj_Languages == null)
iobj_Languages = new VM_Languages();
return iobj_Languages;
}
}
}
}
在我的主页出现的代码中,我有以下调用来从 WebAPI 检索数据
protected override async void OnAppearing()
{
Device.BeginInvokeOnMainThread(() =>
{
if (!ViewModelObjects.Languages.IsDataLoaded)
ViewModelObjects.Languages.LoadData();
});
//If the DOW and Language data are not loaded yet - wait
while (!ViewModelObjects.Languages.IsDataLoaded)
{
await Task.Delay(1000);
}
}
问题是当我尝试使用我的 WebAPICaller 类时,它似乎在线崩溃。我从来没有从中得到回报。从未引发异常,我的程序也永远不会继续。
lobj_HTTPResponse = await lobj_HTTPClient.GetAsync(ps_URI);
如果我从我的 ViewModel 发出我认为完全相同的调用,它就会起作用。 (我既有对 WebAPICaller 类的调用,也有对 View Model 中 GetAsync 的直接调用,因此您可以通过注释和取消注释对其进行测试。)
知道我做错了什么吗?
完整示例项目的链接: https://1drv.ms/u/s!Ams6cZUzaeQy3M8uGAuaGggMt0Fi-A
【问题讨论】:
-
使用 Fiddler 或类似工具查看对 API 发出的请求。这听起来更像是一个调试问题...
-
这是因为你混合了异步和阻塞调用。除非
OnAppearing是事件处理程序,否则该方法中的异步调用将死锁。 -
出现实际上是来自页面的事件处理程序。你所描述的是我的想法,但不知道如何解决它
-
@GeorgeMCeaserJr,
OnAppearing不是事件处理程序。它是在Page.Appearing事件的实际事件处理程序中调用的受保护方法。 -
@GeorgeMCeaserJr,如果你看一下source code on github,你就会明白我指的是什么。
标签: c# async-await xamarin.forms asp.net-web-api2 dotnet-httpclient