使用 C# 和 Xamarin 调用 API 和获取数据

Posted

技术标签:

【中文标题】使用 C# 和 Xamarin 调用 API 和获取数据【英文标题】:API Calls and Fetching Data with C# and Xamarin 【发布时间】:2020-10-06 19:19:52 【问题描述】:

所以我有一个程序可以在用户输入搜索词后调用 API 如下所示:

        LoadTVShows load = new LoadTVShows();

        private async void searchShow(object sender, EventArgs e)
        
            searchString = searchBox.Text;
            try
            
                var getTvShow = await load.GetAPI(searchString).ConfigureAwait(false);

            
            catch
            

            

            showName.Text = load.name;
            showSummary.Text = load.summary;
            airTime.Text = load.time;
            countryCode.Text = load.country;


        

var getTvShow 只是调用类来运行 api 并在完成后返回 true,将所需的值存储在其自己的类中以供外部访问。

但是,当我将数据存储在文本字段中时,我遇到了此错误消息。

System.Exception
  HResult=0x8001010E
  Message=The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))
  Source=Windows
  StackTrace:
   at Windows.UI.Xaml.Controls.TextBlock.put_Text(String value)
   at Xamarin.Forms.Platform.UWP.LabelRenderer.UpdateTextPlainText(TextBlock textBlock)
   at Xamarin.Forms.Platform.UWP.LabelRenderer.UpdateText(TextBlock textBlock)
   at Xamarin.Forms.Platform.UWP.LabelRenderer.OnElementPropertyChanged(Object sender, PropertyChangedEventArgs e)
   at System.ComponentModel.PropertyChangedEventHandler.Invoke(Object sender, PropertyChangedEventArgs e)
   at Xamarin.Forms.BindableObject.OnPropertyChanged(String propertyName)
   at Xamarin.Forms.Element.OnPropertyChanged(String propertyName)
   at Xamarin.Forms.BindableObject.SetValueActual(BindableProperty property, BindablePropertyContext context, Object value, Boolean currentlyApplying, SetValueFlags attributes, Boolean silent)
   at Xamarin.Forms.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
   at Xamarin.Forms.BindableObject.SetValue(BindableProperty property, Object value, Boolean fromStyle, Boolean checkAccess)
   at Xamarin.Forms.Label.set_Text(String value)
   at MajorProjectTvApplication.SearchView.<searchShow>d__15.MoveNext() in D:\Tafe Work\Mobile Apps\wk12\MajorProjectTvApplication\MajorProjectTvApplication\MajorProjectTvApplication\SearchView.xaml.cs:line 70

因此,我很不确定如何解决这个问题,所以任何想法和想法都会有很大帮助。

LoadTvShows 类提供的情况:

public class LoadTVShows
    
        public string name;
        public string summary;
        public string time;
        public string country;

        public async Task<bool> GetAPI(string searchString)
        
            string search = searchString;
            try
            
                using (var client = new HttpClient())
                
                    var response = await client.GetAsync("http://api.tvmaze.com/singlesearch/shows?q=" + search + "");
                    var responseString = await response.Content.ReadAsStringAsync();
                    var rawTvListings = JsonConvert.DeserializeObject<OpenTVGuideResponse>(responseString);

                    name = rawTvListings.Name;
                    time = rawTvListings.Schedule.Time;
                    summary = rawTvListings.Summary;
                    country = rawTvListings.Network.Country.Code;

                    return true;
                
            
            catch (HttpRequestException httpRequestError)
            
                return false;
            
        
    

    public class OpenTVGuideResponse
    
        public string Name  get; set;  

        public GetTime Schedule  get; set; 

        public string Summary  get; set; 

        public GetNetwork Network  get; set; 

    
    public class GetTime
    
        public string Time  get; set; 
    

    public class GetNetwork
    
        public GetCountry Country  get; set; 
    

    public class GetCountry
    
        public string Code  get; set; 
    

【问题讨论】:

你为什么打电话给ConfigureAwait(false)?你知道它的作用吗? 【参考方案1】:

首先,在下面的代码行中使用ConfigureAwait(false) 是完全不需要的。

var getTvShow = await load.GetAPI(searchString).ConfigureAwait(false);

您正在从非 UI 线程上下文更新您的 UI。因此,一种解决方案是将与 UI 相关的代码包装在 BeginInvokeOnMainThread 方法中。

Device.BeginInvokeOnMainThread (() => 

  showName.Text = load.name;
  showSummary.Text = load.summary;
  airTime.Text = load.time;
  countryCode.Text = load.country;
;

【讨论】:

或者只是删除 ConfigureAwait(false)。类似的效果。 是的,正确。这就是为什么一开始我提到ConfigureAwait(false)没有用。【参考方案2】:

可能错误在ConfigureAwait

这不是错误,但你必须检查 response.IsSuccessStatusCode:

>

HttpResponseMessage response = await client.GetAsync("http://api.tvmaze.com/singlesearch/shows?q=" + search + "");
if (response.IsSuccessStatusCode)

    var responseString = await response.Content.ReadAsStringAsync();
    var rawTvListings = JsonConvert.DeserializeObject<OpenTVGuideResponse>(responseString);

您可以阅读这篇文章来改进代码。

https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-implementation

【讨论】:

以上是关于使用 C# 和 Xamarin 调用 API 和获取数据的主要内容,如果未能解决你的问题,请参考以下文章

操作方法:使用 AWS Cognito 进行 C# .net 核心 API (APIGateway/Lambda) + Xamarin + Facebook 身份验证

Xamarin原生跨平台概述(精简概述,命中要害。PS:无图)

Xamarin 和 Telerik nativescript 之间的区别

进行 api 调用时 Xamarin 应用程序死锁

C# Xamarin Forms - 调用事件总是返回 null

使用异步等待 C# Xamarin