So I have a program that Calls an API once the user has entered a search term Like so:
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;
}
the var getTvShow simply calls the class to run the api and return true once done, storing the values needed within its own class for access outside.
However when I get to storing the data in the text fields, I am met with this error message.
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
Due to this I am quite unsure how to get around this, so any thoughts and ideas would be a big help.
LoadTvShows Class provided in case:
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; }
}
Probably the error is on ConfigureAwait
it's not the error, but you must check 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);
}
You could read this article to improve the code.
https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-implementation
Firstly, using ConfigureAwait(false)
in the below line of code is not at all required.
var getTvShow = await load.GetAPI(searchString).ConfigureAwait(false);
You are updating your UI from the non UI thread context. So one solution will be to wrap your UI related code inside the BeginInvokeOnMainThread
method.
Device.BeginInvokeOnMainThread (() =>
{
showName.Text = load.name;
showSummary.Text = load.summary;
airTime.Text = load.time;
countryCode.Text = load.country;
};
User contributions licensed under CC BY-SA 3.0