Monodroid WebRequest bombs application - webrequest

I have tried this code in a normal C# app and it works fine. In monodroid, it completely bugs out (in other words, not even the try-catch works) when I try to READ from the stream (or the base stream) in ANY way. Please help:
try
{
WebRequest request = WebRequest.Create(string.Format("http://maps.google.com/maps/geo?q={0},{1}&output=xml&sensor=false", "35.245619","-98.276369"));
WebResponse wresponse = request.GetResponse();
using (StreamReader sr = new StreamReader(wresponse.GetResponseStream()))
{
RunOnUiThread(() => _debug.Text = (sr.ReadToEnd()).ToString());
}
wresponse.Close();
}
catch (Exception ex)
{
RunOnUiThread(() => _debug.Text = string.Format("Exception: ", ex.Message));
}
_debug is a TextView object on my UI.

How about this way?
try
{
WebRequest request = WebRequest.Create(string.Format("http://maps.google.com/maps/geo?q={0},{1}&output=xml&sensor=false", "35.245619","-98.276369"));
WebResponse wresponse = request.GetResponse();
var resp=string.Empty;
using (StreamReader sr = new StreamReader(wresponse.GetResponseStream()))
{
resp=sr.ReadToEnd().ToString();
}
wresponse.Close();
RunOnUiThread(() => _debug.Text = resp);
}
catch (Exception ex)
{
RunOnUiThread(() => _debug.Text = string.Format("Exception: ", ex.Message));
}

Sound has provided the answer. That should work. I'll just explain the reason a bit.
From your code, it seems like you are doing the HTTP request on a background thread. That's why you need to do the RunOnUiThread. This is a very good approach.
However, RunOnUiThread does not guarantee that the code will be executed immediately on the UI thread. It merely posts a message to the UI thread run loop. And when the UI thread gets a chance, it will execute it.
What this essentially means is that "wresponse.close()" will probably run before "resp=sr.ReadToEnd().ToString()". Since the response is closed, any attempt to read from it will cause an error. But the error happens on the UI thread since the read attempt will be on UI thread. Thats why your try/catch block doesn't function.
In Sound's code, this problem is eliminated. As a side note, this code is also much better performing since the actual reading of bytes is offloaded to the worker thread, so your UI thread will be much more responsive.

Related

No errors are being raised when unsuccessfully writing to Azure service bus

When writing a message to the Azure Service Bus (using Microsoft.Azure.ServiceBus standard library, not the .Net Framework version) it works fine. However, when switching networks to a network that blocks that traffic and running it again I would expect an error being raised by SendAsync yet no error is thrown, therefor the function considers the send successful even though it is not.
Am I missing some logic to make sure that errors do get raised and trapped, it seems to be inline with all the examples I have seen.
I have tried this possible solution ..
Trouble catching exception on Azure Service Bus SendAsync method
.ContinueWith(t =>
{
Console.WriteLine(t.Status + "," + t.IsFaulted + "," + t.Exception.InnerException);
}, TaskContinuationOptions.OnlyOnFaulted);
.. and at no point does ContinueWith get hit.
[HttpPost]
[Consumes("application/json")]
[Produces("application/json")]
public ActionResult<Boolean> Post(Contract<T> contract)
{
Task.Run(() => SendMessage(contract));
// Other stuff
}
private async Task<ActionResult<Boolean>> SendMessage(Contract<T> contract)
{
JObject json = JObject.FromObject(contract);
Message message = new Message();
message.MessageId = Guid.NewGuid().ToString();
message.ContentType = ObjectType;
message.PartitionKey = ObjectType;
message.Body = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(contract));
foreach (KeyValuePair<String, String> route in DataRouting)
{
JToken jToken = json.SelectToken(route.Value);
if (jToken != null)
{
message.UserProperties[route.Key] = jToken.Value<String>();
}
else
{
String routeError = $"Could not find routing information in request for: {route.Key} in {route.Value}";
Logger.LogError(routeError);
return new UnprocessableEntityObjectResult(routeError);
}
}
// Send the message
try
{
await topicClient.SendAsync(message);
}
catch(Exception ex)
{
return new UnprocessableEntityObjectResult($"'Could not transmit message to service bus - {ex.Message}'");
}
return new OkObjectResult(true);
}
I expect that the error trap would be hit if the SendAsync fails to send the message. However it essentially fire and forgets, the message send is blocked by the firewall but is never reported to the caller by throwing an error.
Ok, found the answer, but I will leave this out there in case anyone else does this to themselves. It was down to my general muppetry when putting the MVC Controller together. Set async on the Post action and configure the await on the send. Obvious really but I missed it.
public virtual async Task<ActionResult<Boolean>> Post(Contract<T> contract){}
...
// Send the message
try
{
await topicClient.SendAsync(message).ConfigureAwait(false);
return new OkObjectResult(true); // Success if we got here
}
catch(Exception ex)
{
return new UnprocessableEntityObjectResult($"'Could not transmit message to service bus - {ex.Message}'");
}

Error in Xamarin Android with a progress dialog “Only the original thread that created a view hierarchy can touch its views”

I'm trying to use a progress dialog, while filling a datagrid, but I get the following error: "Only the original thread that created a view hierarchy can touch its views", this is my code, i hope they can help me
public async void RelacionClientesREST()
{
try
{
var dlg = ProgressDialog.Show(this, "Loading", "Cargando relación de usuarios");
ThreadPool.QueueUserWorkItem(d => {
RestClient client = new RestClient("http://portalclientewa.azurewebsites.net/api/RelacionClientes/");
var request = new RestRequest("GetData", Method.GET);
request.Timeout = 1500000;
request.RequestFormat = DataFormat.Json;
request.AddParameter("idP", Idp);
var temp = client.Execute(request).Content;
var parsedJson = JsonConvert.DeserializeObject(temp).ToString();
var lst = JsonConvert.DeserializeObject<List<ClientesProp>>(parsedJson).ToList();
dataGrid.ItemsSource = lst;
RunOnUiThread(() => {
dlg.Dismiss();
});
});
}
catch (Exception ex)
{
Toast.MakeText(this, "No hay datos registrados", ToastLength.Short).Show();
}
}
The error is telling you the app's UI must be handled by the main thread. In your code, you are running some code on a background thread (ThreadPool.QueueUserWorkItem) that needs to be run on the UI thread (RunOnUiThread) instead.
you cannot use dlg.Dismiss(); inside ThreadPool.QueueUserWorkItem, move it before try close sign
why not use Task instead?
Task.Run(() => doStuff("hello world"));
It doesn't really seem a lot better, but at least it doesn't have an unused identifier.
Note: Task.Run() is .Net 4.5 or later. If you're using .Net 4 you have to do:
Task.Factory.StartNew(() => doStuff("hello world"));
Both of the above do use the thread pool.
Only the original thread that created a view hierarchy can touch its views
As #CaPorter said, the app's UI must be handled by the main thread. There are any number of ways to get code to execute on the UI thread, you could try using Looper.MainLooper with Handler.Post().
Modify your code like this :
ThreadPool.QueueUserWorkItem(d => {
...
Handler handler = new Handler(Looper.MainLooper);
Action action = () =>
{
dataGrid.ItemsSource = lst;
dlg.Dismiss();
};
handler.Post(action);
});

C# - Xamarin - HttpClient - Operation is not valid due to the current state of the object - iOS

I'm working on a cross platform library that makes HTTP requests. It's working fine on Android, but when I try to use it on iOS I'm getting an exception and I can't figure out how to fix it.
Here is my code:
// method from cross platform library
Task.Factory.StartNew(delegate
{
try
{
var client = new HttpClient();
// some other setup stuff
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.post, "http://myurl.com...");
var task = client.SendAsync(request);
task.Wait(); // Exception thrown on this line
var response = task.Result;
var responseString = response.Content.ReadAsStringAsync().Result;
}
catch (Exception e)
{
}
}
On task.Wait(); I get a System.AggregateException with an inner exception of System.InvalidOperationException that says Operation is invalid due to the current state of the object.
Trying to find some solutions, I found that the issue could be cause by calling this on the UI thread. But that's the whole point of wrapping this all in Task.Factory.StartNew.
I've tried everything I know to do and have yet to solve the issue. Any help would be very appreciated.
Edit:
I decided to try my solution on an iPhone simulator. It's an iPhone 6 simulator running iOS 10. My physical device is the same. It works on the simulator, but not the physical device for some reason... very strange.
Edit 2:
Thanks to #YuriS for finding a solution.
From: https://forums.xamarin.com/discussion/36713/issue-with-microsoft-http-net-library-operation-is-not-valid-due-to-the-current-state-of-the-objec
What you can do is:
1) Go to References of ios Project
2) Edit References
3) Check 'System.Net.Http'
Behaviour for android is the same.
There can be few problems described here:
https://forums.xamarin.com/discussion/36713/issue-with-microsoft-http-net-library-operation-is-not-valid-due-to-the-current-state-of-the-objec
https://bugzilla.xamarin.com/show_bug.cgi?id=17936
"Operation is not valid" error at Xamarin.iOS project with HttpClient
http://motzcod.es/post/78863496592/portable-class-libraries-httpclient-so-happy
Seems all post pointing on System.Net.Http
Regardless of the problem there is a better ways doing this.One of them:
public static async Task PostRequest()
{
try
{
HttpClient client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "https://myuri");
//request.Headers.Add("", "");
var response = await client.SendAsync(request);
var responseString = await response.Content.ReadAsStringAsync();
}
catch (Exception ex)
{
}
}
If you want to wait till function completes you call
await PostRequest();
If you don't need to wait then just omit "await" in the call or use
PostRequest.ContinueWith((t)=>
{
});
Also you need to handle an exception within the function, so probably returning just Task is not the best. I was just basing my answer on original function signature

Wait while request is running

Here is a problem. When I ran these code:
String responseText = null;
HttpRequest.getString(url).then((resp) {
responseText = resp;
print(responseText);
});
print(responseText);
In console:
{"meta":{"code":200},"data":{"username":"kevin","bio":"CEO \u0026 Co-founder of Instagram","website":"","profile_picture":"http:\/\/images.ak.instagram.com\/profiles\/profile_3_75sq_1325536697.jpg","full_name":"Kevin Systrom","counts":{"media":1349,"followed_by":1110365,"follows":555},"id":"3"}}
null
It running asynchronously. Is there JAVA way with synchronized method? That will be await while request is done?
I found only one tricky way to do it and its funny -- wait for three seconds:
handleTimeout() {
print(responseText);
}
const TIMEOUT = const Duration(seconds: 3);
new Timer(TIMEOUT, handleTimeout);
And of course it works with bugs. So any suggestions?
MattB way work well:
var req = new HttpRequest();
req.onLoad.listen((e) {
responseText = req.responseText;
print(responseText);
});
req.open('GET', url, async: false);
req.send();
First, I'm assuming you're using this as a client-side script and not server-side. Using HttpRequest.getString will strictly return a Future (async method).
If you absolutely must have a synchronous request, you can construct a new HttpRequest object and call the open method passing the named parameter: async: false
var req = new HttpRequest();
req.onLoad.listen((e) => print(req.responseText));
req.open('GET', url, async: false);
req.send();
However it is highly recommended that you use async methods for accessing network resources as a synchronous call like above will cause the script to block and can potentially make it appear as though your page/script has stopped responding on poor network connections.

Blackberry: Make a iterative HTTP GET petition using Comms API

I want to store position coords (latitude, longitude) in a table in my MySQL DB querying a url in a way similar to this one: http://locationstore.com/postlocation.php?latitude=var1&longitude=var2 every ten seconds. PHP script works like a charm. Getting the coords in the device ain't no problem either. But making the request to the server is being a hard one. My code goes like this:
public class LocationHTTPSender extends Thread {
for (;;) {
try {
//fetch latest coordinates
coords = this.coords();
//reset url
this.url="http://locationstore.com/postlocation.php";
// create uri
uri = URI.create(this.url);
FireAndForgetDestination ffd = null;
ffd = (FireAndForgetDestination) DestinationFactory.getSenderDestination
("MyContext", uri);
if(ffd == null)
{
ffd = DestinationFactory.createFireAndForgetDestination
(new Context("MyContext"), uri);
}
ByteMessage myMsg = ffd.createByteMessage();
myMsg.setStringPayload("doesnt matter");
((HttpMessage) myMsg).setMethod(HttpMessage.POST);
((HttpMessage) myMsg).setQueryParam("latitude", coords[0]);
((HttpMessage) myMsg).setQueryParam("longitude", coords[1]);
((HttpMessage) myMsg).setQueryParam("user", "1");
int i = ffd.sendNoResponse(myMsg);
ffd.destroy();
System.out.println("Lets sleep for a while..");
Thread.sleep(10000);
System.out.println("woke up");
} catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("Exception message: " + e.toString());
e.printStackTrace();
}
}
I haven't run this code to test it, but I would be suspicious of this call:
ffd.destroy();
According to the API docs:
Closes the destination. This method cancels all outstanding messages,
discards all responses to those messages (if any), suspends delivery
of all incoming messages, and blocks any future receipt of messages
for this Destination. This method also destroys any persistable
outbound and inbound queues. If Destination uses the Push API, this
method will unregister associated push subscriptions. This method
should be called only during the removal of an application.
So, if you're seeing the first request succeed (at least sometimes), and subsequent requests fail, I would try removing that call to destroy().
See the BlackBerry docs example for this here
Ok so I finally got it running cheerfully. The problem was with the transport selection; even though this example delivered WAP2 (among others) as an available transport in my device, running the network diagnostics tool showed only BIS as available. It also gave me the connection parameters that I needed to append at the end of the URL (;deviceside=false;ConnectionUID=GPMDSEU01;ConnectionType=mds-public). The code ended up like this:
for (;;) {
try {
coords.refreshCoordinates();
this.defaultUrl();
this.setUrl(stringFuncs.replaceAll(this.getUrl(), "%latitude%", coords.getLatitude() + ""));
this.setUrl(stringFuncs.replaceAll(this.getUrl(), "%longitude%", coords.getLongitude() + ""));
cd = cf.getConnection(this.getUrl());
if (cd != null) {
try {
HttpConnection hc = (HttpConnection)cd.getConnection();
final int i = hc.getResponseCode();
hc.close();
} catch (Exception e) {
}
}
//dormir
Thread.sleep(15000);
} catch (Exception e) {
} finally {
//cerrar conexiones
//poner objetos a null
}
Thanks for your help #Nate, it's been very much appreciated.

Resources