返回大量数据时,WebAPI调用会挂起

时间:2017-11-02 17:40:52

标签: xamarin.forms asp.net-web-api2 httpclient

我最近添加到我的应用中的网络API呼叫。我返回应用程序中所有国家,州和城市的完整列表(当前486行)当我的应用程序的所有参考数据加载时,我执行此调用(我有一个基本加载页面并在我的启动类中调用该函数加载那里的所有数据)。我们面临的挑战是,召集所有国家的人......挂起,最终我得到“操作被取消”的错误。如果我修改我的存储过程,从服务器上的数据库中选择数据只返回20行,它运行正常。有什么建议吗?

以下是启动类的代码:

using System;
using System.Diagnostics;
using System.Threading.Tasks;

namespace GBarScene
{
class StartUpClass
{

    public event GeneralDataLoad BaseDataLoadComplete;

    public async Task<GBSStartUpEventArgs> ProcessStartup()
    {
        GBSStartUpEventArgs lobj_EventArgs;
        lobj_EventArgs = new GBSStartUpEventArgs();
        App.InStartUpDataLoad = true;
        try
        {

            if (!App.IsGeolocationEnabled)
            {
                lobj_EventArgs.ErrorOccurred = true;
                lobj_EventArgs.ShowRetry = true;
                lobj_EventArgs.ShowWebSite = false;
                lobj_EventArgs.ErrorMessage = resourcestrings.GetValue("NoLocationServicesMessage");
            }
            else if (!App.InternetIsAvailable)
            {
                lobj_EventArgs.ErrorOccurred = true;
                lobj_EventArgs.ErrorMessage = resourcestrings.GetValue("NoInternetConnectionFound");
                lobj_EventArgs.ShowRetry = true;
                lobj_EventArgs.ShowWebSite = false;
            }
            else
            {
                Debug.WriteLine("Process StartUp");

                await Task.Delay(500);

                //Reset values
                ViewModelObjects.DayOfWeek.DataLoadProcessed = false;
                ViewModelObjects.Languages.DataLoadProcessed = false;

                if (await ViewModelObjects.DayOfWeek.LoadData() == false)
                    //    //try it once more 
                    await ViewModelObjects.DayOfWeek.LoadData();

                Debug.WriteLine("GBar After DayofWeek Load");


                await ViewModelObjects.Languages.LoadData();
                Debug.WriteLine("GBar After Languages Load");

                if ((ge_AppMode)ViewModelObjects.AppSettings.AppMode == ge_AppMode.CitySelected)
                {
                    //We need to reload the NearbyCities and set the selected one
                    await ViewModelObjects.NearbyCities.LoadData();
                }

                Debug.WriteLine("Before load of coutries");

                await ViewModelObjects.CountryStateCity.LoadData();
                Debug.WriteLine("After load of coutries");
                Debug.WriteLine("Count: " + ViewModelObjects.CountryStateCity.CountryItems_ForList.Count.ToString());

                ViewModelObjects.NumberOfResults.LoadData();

                ViewModelObjects.Perspectives.LoadData();

                ViewModelObjects.SearchRadiuses.LoadData();
                ViewModelObjects.UseMetric.LoadData();

                while (!ViewModelObjects.DayOfWeek.DataLoadProcessed && !ViewModelObjects.Languages.DataLoadProcessed && !App.IsGeolocationEnabled)
                {
                    await Task.Delay(100);
                }


                if (App.BaseDataLoadError)
                {
                    lobj_EventArgs.ErrorOccurred = true;
                    lobj_EventArgs.ShowRetry = true;
                    lobj_EventArgs.ShowWebSite = true;
                    lobj_EventArgs.ErrorMessage = resourcestrings.GetValue("ErrorLoadingReferenceData");
                }

            }
            Debug.WriteLine("StartUp Process Ended");

            BaseDataLoadComplete(this, lobj_EventArgs);
        }
        catch (Exception ex)
        {
            App.ProcessException(ex);
        }
        App.InStartUpDataLoad = false;
        return lobj_EventArgs;
    }
}
}

这是进行所有WebAPI调用的辅助类:

using Newtonsoft.Json;
using System;
using System.Diagnostics;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace GBarScene
{

public class WebAPICaller: IDisposable

{
    HttpClient iobj_HTTPClient = null;
    public void Dispose()
    {
        if (iobj_HTTPClient != null)
            iobj_HTTPClient.Dispose();

    }

    public async Task<string> HTTPGetWebServiceAsync(string ps_URI)
    {

        string ls_Response = "";
        string ls_JSONData = "";
        string ls_Prefix = "";

        try
        {
            iobj_HTTPClient = await GetClient();

            switch (Device.RuntimePlatform)
            {
                case Device.Android:
                    ls_Prefix = App.APIStandardPrefix;
                    break;
                //case Device.Android:
                //    ls_Prefix = App.APISecurePrefix;
                //    break;
                //case Device.Windows:
                //case Device.WinPhone:
                //    ls_Prefix = App.APISecurePrefix;
                //    break;
                default:
                    ls_Prefix = App.APISecurePrefix;
                    break;
            }

            Debug.WriteLine("before api call");
            iobj_HTTPClient.BaseAddress = new Uri(ls_Prefix);
            ls_JSONData = await iobj_HTTPClient.GetStringAsync(ps_URI);
            Debug.WriteLine("after api call");
            ls_Response = System.Net.WebUtility.HtmlDecode(ls_JSONData);

        }
        catch (Exception ex)
        {
            Debug.WriteLine("api call error");
            App.ProcessException(ex);
        }
        return ls_Response;

    }

    public async Task<bool> HTTPPostWebService(string ps_URI, object pobj_BodyObject)
    {
        HttpResponseMessage lobj_HTTPResponse = null;
        bool lb_Response = false;
        HttpContent lobj_Content = null;

        try
        {
            if (iobj_HTTPClient != null)
                iobj_HTTPClient = await GetClient();

            iobj_HTTPClient.BaseAddress = new Uri(App.APISecurePrefix);

            lobj_Content = new StringContent(JsonConvert.SerializeObject(pobj_BodyObject == null ? "" : pobj_BodyObject));
            lobj_Content.Headers.ContentType = new MediaTypeHeaderValue("application/json");


            lobj_HTTPResponse = await iobj_HTTPClient.PostAsync(ps_URI, lobj_Content);


            if (!lobj_HTTPResponse.IsSuccessStatusCode)
            {
                Exception lobj_Exception = new Exception(lobj_HTTPResponse.ToString());
                lobj_Exception.Source = "HTTPGetWebService for: " + ps_URI;

                App.ProcessException(lobj_Exception);
            }
            else
            {
                lb_Response = true;
            }
        }
        catch (Exception ex)
        {
            App.ProcessException(ex);
        }
        finally
        {
          if (lobj_HTTPResponse != null)
            {
                lobj_HTTPResponse.Dispose();
            }
            //Debug.WriteLine("WebAPICaller-CallWebService-1: Done");
        }

        return lb_Response;

    }


    private async Task<HttpClient> GetClient()
    {
        HttpClient lobj_HTTPClient = null;

        if (lobj_HTTPClient == null)
        {
            lobj_HTTPClient = new HttpClient();
            lobj_HTTPClient.DefaultRequestHeaders.Add("Accept", "application/json");
            lobj_HTTPClient.MaxResponseContentBufferSize = 2147483647;
            lobj_HTTPClient.Timeout = new TimeSpan(0,0,0,0,60000);
        }

        return lobj_HTTPClient;
    }

}
}

抱歉,我忘了在调用webapi助手类的CountryStateCity视图模型中包含该方法。

    public async Task<bool> LoadData()
    {
        string ls_Response = "";
        string ls_WorkURI = "";
        WebAPICaller lobj_WebAPICaller = null;
        bool lb_DataLoaded = false;

        try
        {
            IsDataLoaded = false;

            //Debug.WriteLine("City Data Load");

            lobj_WebAPICaller = new WebAPICaller();
            ls_WorkURI = ic_CoutryStateCityAPIUrl.Replace("{Language}", "EN");
            ls_Response = await lobj_WebAPICaller.HTTPGetWebServiceAsync(ls_WorkURI);

            if (ls_Response.Trim().Length == 0)
            {
                AddErrorEntry();
            }
            else
            {

                CountryItems_ForList = new ObservableCollection<GBSCountry_ForList>();
                StateItems_ForList = new ObservableCollection<GBSState_ForList>();
                CityItems_ForList = new ObservableCollection<GBSCity_ForList>();

                iobj_CountryStateCity = JsonConvert.DeserializeObject<ObservableCollection<GBSCountryStateCity>>(ls_Response);

                //Now load the display lists
                CountryItems_ForList = new ObservableCollection<GBSCountry_ForList>(
                (from lobj_Country in iobj_CountryStateCity
                 select new GBSCountry_ForList()
                 {
                     ID = lobj_Country.Country_Code,
                     Value = lobj_Country.Country_Name_Text
                 }).Distinct().ToList());

                CountryItems_ForList.Insert(0, new GBSCountry_ForList
                {
                    ID = "XX",
                    Value = "Base Value"
                });

                lb_DataLoaded = true;
            }
        }
        catch (Exception ex)
        {
            AddErrorEntry();
            App.ProcessException(ex);

        }
        finally
        {
            IsDataLoaded = true;
            if (lobj_WebAPICaller != null)
                lobj_WebAPICaller.Dispose();
        }
        return lb_DataLoaded;
    }

1 个答案:

答案 0 :(得分:0)

因此,经过很多时间,我相信我已经弄清了问题所在。问题开始再次以较少的数据量开始显现,我不知道为什么。问题出现了。问题似乎是我使用的IP地址。 (我使用的是托管App和WebAPI的实际笔记本电脑的IP地址。)看来您必须使用其他网络适配器之一才能使仿真器可靠地完成此工作。

以下是我用来解决此问题的步骤:

  1. 我启动了Windows 10移动模拟器。
  2. 单击模拟器工具栏中的>>(工具)图标。
  3. 单击“其他工具”窗口的“网络”选项卡。
  4. 在列表中查找标记为“桌面适配器#1”的网络适配器,然后复制IP地址。
  5. 在WebAPI项目的文件夹中编辑Applicationhost.config文件。
  6. 在文件中找到站点名称=“ XXXXX”的条目,其中XXXXX是用于托管WebAPI的Visual Studio项目的名称。
  7. 在您的WebAPI项目条目的部分中,为您在步骤4中复制的IP地址添加一个绑定。它看起来应该像这样:

    <binding protocol="http" bindingInformation="*:56952:169.254.69.220" />
    

其中56952是我的IIS Express托管WebAPI的端口,而169.254.69.220是我从第4步复制的IP地址。添加此地址之后,我能够连接到IIS Express中的本地托管WebAPI。

希望这会有所帮助。