I am using the below code to read JSON from an endpoint in my Xamarin crossplatform project and I am getting error
Cannot read disposed object exception or it fires ObjectDisposedException
IS it something wrong with code Can I write it in a better way ?
public async Task<APISchoolDetailModel> GetSchooDetailsAsync()
{
APISchoolDetailModel api_data = new APISchoolDetailModel();
try
{
var client = new System.Net.Http.HttpClient();
client.DefaultRequestHeaders.Add("Accept", "application/json");
var web_client = await client.GetAsync("http://appapitest.net/APIs/Student/Schooldetails");
var response_string= web_client.Content.ReadAsStringAsync().Result;
DataContractJsonSerializer serializer = new DataContractJsonSerializer(api_data.GetType());
MemoryStream ms = new MemoryStream(Encoding.Unicode.GetBytes(response_string));
api_data = serializer.ReadObject(ms) as APISchoolDetailModel;
}
catch (Exception ex) { }
return api_data;
}
The controller comes till the line var web_client = await client.GetAsync(" and then its not going further and after few seconds I am getting exception
Is any better way to write this code for reading and parsing JSON
#Gserg pointed out something important you should not do this:
var response_string= web_client.Content.ReadAsStringAsync().Result;
in stead of that use:
var response_string= await web_client.Content.ReadAsStringAsync();
within an async Task method:
is you use .Result this may be causing deadlocks within threads or the same stuff that you are experiencing because a thread may be trying to update or use a variable that is already collected from the GC.
Related
using System;
using System.Text;
namespace ConsoleApp7
{
class Program
{
static void Main(string[] args)
{
YourClient client = new YourClient();
client.Put();
}
public class YourClient
{
private readonly HttpClient _client;
public YourClient()
{
_client = new HttpClient();
}
public async Task Put() // must be async
{
using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
{
request.Headers.Add("Authorization", "Bearer token");
request.Content = new StringContent("body", Encoding.UTF8, "content-type");
using (var response = await _client.SendAsync(request))
{
var data = await response.Content.ReadAsStringAsync();
var code = response.StatusCode;
Console.WriteLine(Convert.ToString(code));
// do something with data
}
}
}
}
}
}
I'm not getting any output and I don't know why. I'm trying to print the response code of the request but nothing is output, is it to do with my method?
I have tried printing hi after Client.Put() and it was printed, so I know that my code is actually running, I just don't know why it isn't printing the status code ...
The excellent comment by Prolog points out one of two issues. If your Console app is built on < C# 7.1 you will need a workaround to prevent the app from exiting (before the request has time to process) so in this case add Console.ReadKey() as the very last line. This will spin the message loop until you hit a key. But this is not the main issue and I would like to offer a couple of debugging tips.
The big issue is this:
If I run your code, your http request is failing and is throwing a System.FormatException
Usually this type of exception is not set to Break when Thrown. (You can verify this by looking in the Exception Settings window.) Unfortunately, this is giving you a silent failure in this case, so you must take matters into your own hands to observe it.
Suggestions for debugging your code
Use a try-catch block around any code that has any likelihood of failing.
Use System.Diagnostics.Debug.Assert which will cause your program to break on a line if any condition expression evaluates to false (but only when you're running in Debug mode not Release mode).
Add output statements to trace execution. Using Debug.WriteLine will send messages to the Output window (but again, only in Debug mode). Alternatively, since we have a Console app here, I'm using the main app window to output trace statements.
Example using 1-3:
public async Task Put() // must be async
{
Console.WriteLine("Begin Put()");
try
{
using (var request = new HttpRequestMessage(HttpMethod.Put, "https://api.minecraftservices.com/minecraft/profile/name/egg"))
{
request.Headers.Add("Authorization", "Bearer token");
request.Content = new StringContent("body", Encoding.UTF8, "content-type");
using (var response = await _client.SendAsync(request))
{
var data = await response.Content.ReadAsStringAsync();
var code = response.StatusCode;
Console.WriteLine(Convert.ToString(code));
// do something with data
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.Assert(condition: false, message: ex.Message);
}
Console.WriteLine("End Put()");
}
Now, if I run the code it will break and show what the problem is.
Use the Exception Settings window to turn on all exceptions (if in doubt). Now the code will break on the exact line that is the problem.
Verify that you are Setting Authorization Header of HttpClient correctly as this may be part of the root cause of the exception.
Finally, if you continue after the Debug.Assert you will see the following text in your console which will confirm whether your Put method has had a chance to complete or not.
Hope these suggestions help you solve this problem and future ones!
// This workaround for C# versions below 7.1 attempts to
// mimic an `async Main` method.
static void Main(string[] args)
{
RunAsync();
Console.ReadKey();
}
private static async void RunAsync()
{
YourClient client = new YourClient();
// Put() should be awaited inside an async method
await client.Put();
}
Hello I have a wrapservice which calls sub services in the project. I am trying to add timeout value as a second but there is too many variables so it makes thing hard to implement. I am adding my code snippet and open to ideas thank you
public Stream Posnet(Stream request)
{
if (!Globals.IsConsumerAuthorizedForWasService)
{
throw new FaultException("consumer is not authorized", new FaultCode("3001"));
}
var streamReader = new StreamReader(request);
string streamString = streamReader.ReadToEnd();
streamReader.Close();
PosnetResponse resp = _merchantLegacyAPIWrapper.WrapService(streamString); // I want to add timeout here where I call WrapService;
// I want to add timeout here where I call WrapService
string responseXml = SerializeResponse(resp);
return GenerateStreamFromString(responseXml);
}
and I tried this code snippet below to implement but not succeed:
using System.Threading.Tasks;
var task = Task.Run(() => SomeMethod(input));
if (task.Wait(TimeSpan.FromSeconds(10)))
return task.Result;
else
throw new Exception("Timed out");
I've encountered a few dificulties trying to handle some errors in the best way possible. One of my cases for example is NullReferenceException.
To be more clear let me explain it in a few words. When I make a call to a server to receive some pieces of information, in some cases the server might have some problems and it will return of course null.
What I've done is I display an alert to let the user know that he can try later again. After this I try to send him in the previous page for example. And after all this my app still crushes.
What I'd like to do is to simply display the alert and then let the user stay in the same page without the application crushing.
These are a few pieces of my code:
tasks.cs
public async Task<List<Idea>> GetIdeaAsync(string accesToken)
{
List<Idea> ideas = null;
try
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesToken);
var json = await client.GetStringAsync("http://www.getdata.de/api/ideas/");
var ideas = JsonConvert.DeserializeObject<List<Idea>>(json);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Server Error", "There has been an server error. Please try later.", "OK");
if (ideas == null)
{
await Application.Current.MainPage.Navigation.PopAsync(); //actually I would like to stay in the same page
}
}
return ideas;
}
view.xaml.cs
private async void Button_Clicked(object sender, EventArgs e)
{
Tasks ts = new Tasks();
var ideas = await ts.GetIdeasAsync();
if (ideas == null)
{
Debug.WriteLine("hello");
//do nothing since the display alert is already shown
}
else
{
//code here
}
I would really appreciate if anyone can guide me to a "best-practice" approach. Thanks :)
You are declaring ideas in the try block, and then trying to access it in the catch block, where it is out of scope. (Visual Studio should give an Intellisense error)
Also, whenever manipulating the UI, you should always do it on the main thread. so move your DisplayAlert() code into
Device.BeginInvokeOnMainThread(async () =>
{
// await DisplayAlert(); move it into here
});
In addition, any PopAsync or PushAsync calls should also be done on the main UI thread. But calling PopAsync after an asynchronous call to an API not be a good idea, as the user may have already pressed the back button by the time the call returns.
As for the NullReferenceException, check to see if json is null before passing it to the DeserializeObject() function.
The problem it was pretty obvious actually since I after catch-ing the exception I would later continue with the code. So what I did was :
public async Task<List<Idea>> GetIdeaAsync(string accesToken)
{
List<Idea> ideas = null;
try
{
var client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accesToken);
var json = await client.GetStringAsync("http://www.getdata.de/api/ideas/");
var ideas = JsonConvert.DeserializeObject<List<Idea>>(json);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayAlert("Server Error", "There has been an server error. Please try later.", "OK");
if (ideas == null)
{
//actually I would like to stay in the same page
return null; //-- added this line
}
}
return ideas;
}
Maybe it's not the best idea but it's working for me. Any other approach would be highly appreciated. :)
I found that my Xamarin Android app is running slowly so I added some async/await code to improve the performance. I wanted to excluded my API calls from the UI thread. I thought this would be a perfect opportunity to use async/await. So, I added async to the signature of the function and wrapped Task around my return value type. Then I updated the RestSharp GET call with "await client.ExecuteTaskAsync." Once I did this I found I needed to update my call to the GetCustInfo function. I simply needed to add .Result to the end of the call and it showed no errors. The problem is it hangs on the call to GetCustInfo and just doesn't work.
What am I doing wrong here?
public async Task<List<CustInfo>> GetCustInfo(string strBranchNumber, string dblCurrentXCoordinate, string dblCurrentYCoordinate)
{
if (this.strBearerToken == string.Empty)
{
throw new ArgumentException("No Bearer Token Found");
}
try
{
var restUrl = this.strCustomerInfoAPIURL;
var uri = new Uri(string.Format(restUrl, string.Empty));
var client = new RestClient(uri);
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "bearer " + this.strBearerToken);
request.AddParameter("intBranchNumber", strBranchNumber);
request.AddParameter("intZipCode", this.strZipCode);
request.AddParameter("intCustomerType", this.strCustomerType);
request.AddParameter("intMinTotalAmount", this.strMinRevenue);
request.AddParameter("dblCurrentXCoordinate", dblCurrentXCoordinate);
request.AddParameter("dblCurrentYCoordinate", dblCurrentYCoordinate);
request.AddParameter("bolGetLocation", true);
var response = await client.ExecuteTaskAsync(request);
return JsonConvert.DeserializeObject<List<CustInfo>>(response.Content).OrderBy(x => x.ApproxDistance).ToList();
}
catch (Exception ex)
{
return null;
}
}
So what is happening is when I call the async/await function from my OnCreate it just stops when I try to call customer.GetCustomerInfo().
protected override void OnCreate(Bundle bundle)
{
....
this.tableItems = customer.GetCustInfo(
"xxxxxxx",
this.currentLocation.Latitude.ToString(),
this.currentLocation.Longitude.ToString()).Result;
this.listView.Adapter = new ListOfLocationAdapter(this, this.tableItems);
}
Change the call to
this.tableItems = await customer.GetCustInfo(..
and let us know..
In the next line you are using the result from the not-awaited call, it obviously would hangs, crash whatever:
this.listView.Adapter = new ListOfLocationAdapter(this, **this.tableItems**); //this.tableItems is just empty
I had a working code that was returning something from my CommonRestClient(which is simple wrapper for HttpClient):
public async Task<IActionResult> Index()
{
var uri = _baseUri.Concat(AvalancheServiceAdresses.NodeService);
using (var client = new CommonRestClient(uri))
{
var result = await client.GetAsync<List<NodeInfoContract>>(new Uri(NodeServiceConstant.NodesContractUrl, UriKind.Relative), null);
return View(result);
}
}
It worked fine and i was happy. Until I decide to move my code from view in another class, which should incapsulate entire REST logic and provide an OOP API.
So now my index looks like:
public async Task<IActionResult> Index()
{
var nodeInfoContracts = await _configManager.GetNodesList();
return View(nodeInfoContracts);
}
where GetNodesList is
public ConfiguredTaskAwaitable<List<NodeInfoContract>> GetNodesList()
{
var uri = _baseUri.Concat(AvalancheServiceAdresses.NodeService);
using (var client = new CommonRestClient(uri))
{
return client.GetAsync<List<NodeInfoContract>>(new Uri(NodeServiceConstant.NodesContractUrl, UriKind.Relative), null);
}
}
It's clear that provided codes are equal.
But now it always throws an exception when I try to get a result. In my GetAsync method it fails on following line with TaskCanceledException:
var response = await _client.GetAsync(url).ConfigureAwait(false);
But it's interestring: when I place a breakpoint on this line and step over its works fine. So here we have race condition or similar.
Why am I getting it? I tried to place CondigureAwait false/true, combining some code, but it always throws an error when breakpoints are off. I checked timeout which is several minutes, it can't cause this error.
In the second code snippet the client is disposed before the IO completed. Use the first form.