BackKey not working when a Thread is running. Why? - windows-phone-7

PageA Navigated to PageB
There is a thread is running for HttpWebRequest.
Back Key is invalid when the Thread is running.
PageB Code:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
Debug.WriteLine("OnNavigatedTo");
//base.OnNavigatedTo(e);
DoWork();
}
void DoWork()
{
t = new Thread(new ThreadStart(() =>
{
request = WebRequest.Create("http://www.google.com") as HttpWebRequest;
request.BeginGetResponse(new AsyncCallback(AsyncBack), request);
}));
t.IsBackground = true;
t.Start();
}
void AsyncBack(IAsyncResult ias)
{
HttpWebRequest req = (HttpWebRequest)ias.AsyncState;
using (HttpWebResponse res = req.EndGetResponse(ias) as HttpWebResponse)
{
this.Dispatcher.BeginInvoke(() =>
{
this.PageTitle.Text = res.ContentLength.ToString();
long length = res.ContentLength;
for (long i = 0; i < length; i++)
{
//here imitate a long time for working
Debug.WriteLine(i);
if (i == length)
{
break;
}
}
Debug.WriteLine(res.ContentLength);
});
}
}
the Back Key is invalid until Method AsyncBack() is done.
'Back Key is invalid' Is that the app is not back to PageA when you touch the Back Key until Method AsyncBack() Done.
Why? Help me?

Why the bloody hell are you wrapping a async request in a custom thread? That doesn't even remotely make sense.
Then again, your question doesn't make much sense either, but most likely the error is related to the request is attempting to invoke a operation, via. the dispatcher, on the wrong page.

In your code you block UI thread for a long time, so you can't navigate page back, because it happens also on UI thread, put into Dispatcher only code that can't be executed not on UI.
void DoWork()
{
HttpWebRequest request = WebRequest.Create("http://www.googl.com") as HttpWebRequest;
request.BeginGetResponse(new AsyncCallback(AsyncBack), request);
}
void AsyncBack(IAsyncResult ias)
{
HttpWebRequest req = (HttpWebRequest)ias.AsyncState;
using (HttpWebResponse res = req.EndGetResponse(ias) as HttpWebResponse)
{
this.Dispatcher.BeginInvoke(() =>
{
this.PageTitle.Text = res.ContentLength.ToString();
});
long length = res.ContentLength;
for (long i = 0; i < length; i++)
{
long i_ = i;
//here imitate a long time for working
Thread.Sleep(10);
this.Dispatcher.BeginInvoke(() =>
{
this.PageTitle.Text = i_.ToString();
});
if (i == length)
{
break;
}
}
Debug.WriteLine(res.ContentLength);
}
}

Related

Calling an async api from a xamarin application

I am working on a xamarin mobile application, upon making an async call to the exposed api, i do not get any error, however when i execute the .Result on the task the call never proceeds and it stuck forever.
Click here to see stringResourceResponse details
The same .Result call from a separate project (windows service) in the same solution works.
Any idea if .NET standard is causing limitation in executing async tasks, any advice would be helpful, thanks
Code added below:
//This is code from app.xaml.cs
var stringResourceApi = new StringResourceApiTask();
Task.Run(() =>
{
a = controller.CallStringResourceApi(stringResourceApi);
}).Wait();
public class MobileController
{
public string CallStringResourceApi(StringResourceApiTask stringResourceApiTask)
{
return stringResourceApiTask.Start(StringResourceUrl);
}
}
public override string Start(string URL)
{
var stringResourceResponse = SendRequest(url, "", HttpMethod.Get);
var result = stringResourceResponse.Result;
return result;
}
protected async Task < string > SendRequest(string url, string uri, HttpMethod method, int attempt = 1, int maxAttempts = 5)
{
return await SendRequest(
url, uri, Key, Secret, method, string.Empty, attempt, maxAttempts)
.ConfigureAwait(false);
}
protected async Task<string> SendRequest(string url, string uri, string key, string secret, HttpMethod method,
string requestBody = "", int attempt = 1, int maxAttempts = 5)
{
if (attempt > maxAttempts)
{
return null;
}
var client = InitialiseHttpClient(key, secret);
var request = new HttpRequestMessage
{
RequestUri = string.IsNullOrEmpty(url) ? new Uri(uri) : new Uri(url),
Method = method,
};
if (!string.IsNullOrWhiteSpace(requestBody))
{
request.Content = new StringContent(requestBody, Encoding.UTF8, "application/json");
}
SetOutputText($"Attempting to communicate with {uri}...{Environment.NewLine}");
using (var response = await client.SendAsync(request).ConfigureAwait(false))
{
using (var content = response.Content)
{
try
{
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException ex)
{
if (attempt > maxAttempts)
{
SetOutputText(errorMessage);
}
return await SendRequest(url, uri, key, secret, method, requestBody, attempt + 1).ConfigureAwait(false);
}
var responseBody = await content.ReadAsStringAsync().ConfigureAwait(false);
var isSuccessResponseButEmptyBody = response.IsSuccessStatusCode &&
(string.IsNullOrEmpty(responseBody) ||
string.IsNullOrWhiteSpace(responseBody));
if (!isSuccessResponseButEmptyBody)
{
return responseBody;
}
if (attempt > maxAttempts)
{
SetOutputText(errorMessage);
}
return await SendRequest(url, uri, key, secret, method, requestBody, attempt + 1).ConfigureAwait(false);
}
}
}
when i execute the .Result on the task the call never proceeds and it stuck forever.
Yes. This is a common deadlock situation. When code running on the UI thread blocks on asynchronous code, a deadlock usually occurs.
The same .Result call from a separate project (windows service) in the same solution works.
It works because the Win32 service code does not run on a UI thread.
The proper solution is to remove the blocking code; use await instead. This in turn will cause the calling methods to become async (e.g., StringResourceApiTask.Start), and they should also be awaited, etc. The usage of async and await should "grow" through your code; this is natural.
Alternatively, you can block in a thread pool thread, e.g., Task.Run(() => a = controller.CallStringResourceApi(stringResourceApi)).GetAwaiter().GetResult();. This is a bit of a hack (consuming an unnecessary thread), but it's a quick way to remove the deadlock. Note that this hack is not appropriate for ASP.NET apps; it's acceptable here since this is a UI app.

How To Fix Indy TIdTCPServer Freezing When Sending Text To TIdTCPClient?

Cannot send text from TIdTCPServer To TIdTCPClient, the server hanging (Not Responding), it just freezes when trying to send text to the client.
I Started Recently using Indy TIdTCPClient and TIdTCPServer, i have the client application working well when sending and receiving response from the server form,
then issue is from the server it doesn't send data, and when i try to send data like Indy creators provided in their Doc, it just freezes and then stops responding (crashes) :(, the weird thing is that the server sends back the response on Execute Event, and not sending data with my send function, so here is my code that i use:
Server Execute Event:
void __fastcall TServerMain::IdTCPServer1Execute(TIdContext *AContext)
{
UnicodeString uMessage;
uMessage = AContext->Connection->IOHandler->ReadLn();
MessageDisplay1->Lines->Add(uMessage);
AContext->Connection->IOHandler->WriteLn("Response OK!"); // i can receive the response from the client
}
Server Send Function:
void TServerMain::itsSendMessage(TIdTCPServer *itsName, UnicodeString uMessage) {
TIdContextList *Clients;
TIdContext *icContext;
if ( uMessage.Length() != 0 && itsName->Active ) {
Clients = itsName->Contexts->LockList();
for (int i = 0; i < Clients->Count; i++) {
icContext = (TIdContext*)Clients->Items[i];
icContext->Connection->IOHandler->WriteLn(uMessage);
}
itsName->Contexts->UnlockList();
}
} // this function doesn't send text to the clients however, it just hangs the application for ever.
Additional Note: The TIdTCPServer stops sending text even from it's OnExecute event when a client is disconnects!
UPDATE:
void __fastcall TMyContext::AddToQueue(TStream *AStream)
{
TStringList *queue = this->FQueue->Lock();
try {
queue->AddObject("", AStream);
this->FMessageInQueue = true;
}
__finally
{
this->FQueue->Unlock();
}
}
void __fastcall TMyContext::CheckQueue()
{
if ( !this->FMessageInQueue )
return;
std::unique_ptr<TStringList> temp(new TStringList);
TStringList *queue = this->FQueue->Lock();
try {
temp->OwnsObjects = true;
temp->Assign(queue);
queue->Clear();
this->FMessageInQueue = false;
}
__finally
{
this->FQueue->Unlock();
}
for (int i = 0; i < temp->Count; i++) {
this->Connection->IOHandler->Write( static_cast<TStream*>(temp->Objects[i]), static_cast<TStream*>(temp->Objects[i])->Size, true );
}
}
Server Send Function:
void __fastcall TServerMain::IdSendMessage(TIdTCPServer *IdTCPServer, TStream *AStream)
{
if ( !IdTCPServer->Active )
return;
TIdContextList *Clients = IdTCPServer->Contexts->LockList();
try {
for (int i = 0; i < Clients->Count; i++) {
static_cast<TMyContext*>(static_cast<TIdContext*>(Clients->Items[i]))->AddToQueue(AStream);
}
}
__finally
{
IdTCPServer->Contexts->UnlockList();
}
}
Client Receive Function:
void __fastcall TReadingThread::Receive() {
TMemoryStream * ms = new TMemoryStream();
this->IdTCPClient1->IOHandler->ReadStream(ms);
ms->Position = 0;
ClientMain->Image1->Picture->Bitmap->LoadFromStream(ms);
delete ms;
}
This function is Synchronized in a TThread.
This is how i send a TBitmap using TMemoryStream:
void __fastcall TServerMain::CaptureDesktop()
{
// Capture Desktop Canvas
HDC hdcDesktop;
TBitmap *bmpCapture = new TBitmap();
TMemoryStream *Stream = new TMemoryStream();
try {
bmpCapture->Width = Screen->Width;
bmpCapture->Height = Screen->Height;
hdcDesktop = GetDC(GetDesktopWindow());
BitBlt(bmpCapture->Canvas->Handle, 0,0,Screen->Width, Screen->Height, hdcDesktop, 0,0, SRCCOPY);
bmpCapture->SaveToStream(Stream);
Stream->Position = 0;
IdSendMessage(IdTCPServer1, Stream);
}
__finally
{
ReleaseDC(GetDesktopWindow(), hdcDesktop);
delete bmpCapture;
delete Stream;
}
}
TIdTCPServer is a multi-threaded component, which you are not accounting for propery.
The server's various events are fired in the context of internal worker threads, not in the context the main UI thread. Your OnExecute code is not syncing with the main UI thread when accessing MessageDisplay1, which can cause all kinds of problems, including but not limited to deadlocks. You MUST sync with the main UI thread, such as with TThread::Synchronize() or TThread::Queue(). For example:
void __fastcall TServerMain::IdTCPServer1Execute(TIdContext *AContext)
{
String Message = AContext->Connection->IOHandler->ReadLn();
// see http://docwiki.embarcadero.com/RADStudio/en/How_to_Handle_Delphi_Anonymous_Methods_in_C%2B%2B
TThread::Queue(nullptr, [](){ MessageDisplay1->Lines->Add(Message); });
AContext->Connection->IOHandler->WriteLn(_D("Response OK!"));
}
Also, you have 2 threads (whichever thread is calling itsSendMessage(), and the OnExecute thread) that are not syncing with each other, so they can potentially write text to the same client at the same time, overlapping each other's text and thus corrupting your communications. When sending unsolicited messages from the server to a client, I usually recommend (depending on circumstances) that you queue the messages and let the client thread's OnExecute code decide when it is safe to send the queue. Another reason to do this is to avoid deadlocks if one client becomes blocked, you don't want to block access to other clients. Do as much per-client work in the client's own OnExecute event as you can. For example:
class TMyContext : public TIdServerContext
{
private:
TIdThreadSafeStringList *FQueue;
bool FMsgInQueue;
public:
__fastcall TMyContext(TIdTCPConnection *AConnection, TIdYarn *AYarn, TIdContextThreadList *AList = nullptr)
: TIdServerContext(AConnection, AYarn, AList)
{
FQueue = new TIdThreadSafeStringList;
}
__fastcall ~TMyContext()
{
delete FQueue;
}
void AddToQueue(const String &Message)
{
TStringList *queue = FQueue->Lock();
try
{
queue->Add(Message);
FMsgInQueue = true;
}
__finally
{
FQueue->Unlock();
}
}
void CheckQueue()
{
if (!FMsgInQueue)
return;
std::unique_ptr<TStringList> temp(new TStringList);
TStringList *queue = FQueue->Lock();
try
{
temp->Assign(queue);
queue->Clear();
FMsgInQueue = false;
}
__finally
{
FQueue->Unlock();
}
Connection->IOHandler->Write(temp.get());
}
bool HasPendingData()
{
TIdIOHandler *io = Connection->IOHandler;
bool empty = io->InputBufferIsEmpty();
if (empty)
{
io->CheckForDataOnSource(100);
io->CheckForDisconnect();
empty = io->InputBufferIsEmpty();
}
return !empty;
}
};
__fastcall TServerMain::TServerMain(...)
{
IdTCPServer1->ContextClass = __classid(TMyContext);
...
}
void __fastcall TServerMain::IdTCPServer1Execute(TIdContext *AContext)
{
TMyContext *ctx = static_cast<TMyContext*>(AContext);
ctx->CheckQueue();
if (!ctx->HasPendingData())
return;
String Message = AContext->Connection->IOHandler->ReadLn();
TThread::Queue(nullptr, [](){ MessageDisplay1->Lines->Add(Message); });
AContext->Connection->IOHandler->WriteLn(_D("Response OK!"));
}
void TServerMain::itsSendMessage(TIdTCPServer *itsName, const String &Message)
{
if ( Message.IsEmpty() || !itsName->Active )
return;
TIdContextList *Clients = itsName->Contexts->LockList();
try
{
for (int i = 0; i < Clients->Count; ++i)
{
static_cast<TMyContext*>(static_cast<TIdContext*>(Clients->Items[i]))->AddToQueue(Message);
}
}
__finally
{
itsName->Contexts->UnlockList();
}
}

Prove OrganizationServiceProxy is not Thread Safe

I want to prove that re-using instances of OrganizationServiceProxy between threads will cause problems.
This console app does not have a problem re-using the same instance of OrganizationServiceProxy between threads:
class Program
{
private static OrganizationServiceProxy Service { get; set; }
static void Main(string[] args)
{
Connect(); // Initializes Service
for (int i = 0; i < 100; i++)
{
int index = i;
Task.Run(() =>
{
for (int i2 = 0; i2 < 10; i2++)
{
try
{
Console.WriteLine("Creating" + index);
Entity record = new Entity("account");
record.Id = new Guid("4986e130-45f7-e411-9454-00155d91de01");
record["name"] = index + " - " + i2;
Service.Update(record);
Console.WriteLine("Created" + index);
}
catch (Exception e)
{ }
}
});
}
Console.ReadLine(); // the name of the record ends up as 99 - 9, which is right
}
/* Initialize Service */
private static bool Connect()
{
try
{
ClientCredentials cred = new ClientCredentials();
cred.UserName.UserName = #"r";
cred.UserName.Password = #"";
IServiceManagement<IOrganizationService> serviceManagement = ServiceConfigurationFactory.CreateManagement<IOrganizationService>(new Uri(#"/XRMServices/2011/Organization.svc"));
Service = new OrganizationServiceProxy(serviceManagement, cred);
var who = new Microsoft.Crm.Sdk.Messages.WhoAmIRequest(); // used to test the connection
var whoResponse = (Microsoft.Crm.Sdk.Messages.WhoAmIResponse)Service.Execute(who); // this fails if not connected
}
catch (Exception e)
{
Console.WriteLine("Connecting to CRM.\n" + e.Message + ((e.InnerException != null) ? "\n" + e.InnerException.Message : ""));
return false;
}
return true;
}
}
The SDK states that any instance members of OrganizationServiceProxy are not guaranteed to be thread safe.
How can I cause a problem with an OrganizationServiceProxy shared between threads?
What kinds of problem are to be expected?
I'm not sure I know the specific answer to your question, but something that is marked as not guaranteed of being thread-safe just means exactly that: It may be safe, but the author has not tested for it or specifically written any thread-safe code for those classes, and thus cannot guarantee thread safety.
I do know that thread-safety definitely comes into play with Plugins on the server. This is why you are not supposed to use local fields in a Plugin class. The Plugin engine re-uses the instances of your Plugin class instead of re-instantiating them for each execution. This means it is possible that your Plugin could execute with "old data" in those local fields that was used by the last thread, which could obviously cause all kinds of problems.

Windows Phone 7 - wait for Webclient to complete

I'm developing an app and have run into a problem with asynchronous calls... Here's what i'm trying to do.
The app consumes a JSON API, and, when run, fills the ListBox within a panorama item with the necessary values (i.e. a single news article). When a user selects a ListBox item, the SelectionChanged event is fired - it picks up the articleID from the selected item, and passes it to an Update method to download the JSON response for the article, deserialize it with JSON.NET, and taking the user to the WebBrowser control which renders a html page from the response received.
The problem with this is that I have to wait for the response before I start the NavigationService, but I'm not sure how to do that properly. This way, the code runs "too fast" and I don't get my response in time to render the page.
The event code:
private void lstNews_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (lstNews.SelectedIndex == -1)
{
return;
}
ShowArticle _article = new ShowArticle();
ListBox lb = (ListBox)sender;
GetArticles item = (GetArticles)lb.SelectedItem;
string passId = ApiRepository.ApiEndpoints.GetArticleResponseByID(item.Id);
App.Current.JsonModel.JsonUri = passId;
App.Current.JsonModel.Update();
lstNews.SelectedIndex = -1;
NavigationService.Navigate(new Uri("/View.xaml?id=" + item.Id, UriKind.Relative));
}
OnNavigatedTo method in the View:
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
long sentString = long.Parse(NavigationContext.QueryString["id"]);
string articleUri = ApiRepository.ApiEndpoints.GetArticleResponseByID(Convert.ToInt32(sentString));
//this throws an error, runs "too fast"
_article = App.Current.JsonModel.ArticleItems[0];
}
The update method:
public void Update()
{
ShowArticle article = new ShowArticle();
try
{
webClient.DownloadStringCompleted += (p, q) =>
{
if (q.Error == null)
{
var deserialized = JsonConvert.DeserializeObject<ShowArticle>(q.Result);
_articleItems.Clear();
_articleItems.Add(deserialized);
}
};
}
catch (Exception ex)
{
//ignore this
}
webClient.DownloadStringAsync(new Uri(jsonUri));
}
async callback pattern:
public void Update(Action callback, Action<Exception> error)
{
webClient.DownloadStringCompleted += (p, q) =>
{
if (q.Error == null)
{
// do something
callback();
}
else
{
error(q.Error);
}
};
webClient.DownloadStringAsync(new Uri(jsonUri));
}
call:
App.Current.JsonModel.Update(() =>
{
// executes after async completion
NavigationService.Navigate(new Uri("/View.xaml?id=" + item.Id, UriKind.Relative));
},
(error) =>
{
// error handling
});
// executes just after async call above

Populating a WP7 List from a webservice causes 'Invalid cross-thread access.'

Sorry if this is a easy question but I am totally new to WP7.
I have a rest service that I am trying to consume however I get an error 'Invalid cross-thread access.'
This is my code
public ObservableCollection<TransactionViewModel> Transactions { get;private set; }
public MainViewModel()
{
this.Transactions = new ObservableCollection<TransactionViewModel>();
}
public void LoadTransactions(string id)
{
var req = (HttpWebRequest)WebRequest.Create(string.Format("http://domain.com/Transactions?Id={0}", id));
req.Method = "POST";
req.ContentType = "application/json; charset=utf-8";
// call async
req.BeginGetResponse(new AsyncCallback(jsonGetRequestStreamCallback), req);
this.IsDataLoaded = true;
}
void jsonGetRequestStreamCallback(IAsyncResult asynchronousResult)
{
WebResponse response = ((HttpWebRequest)asynchronousResult.AsyncState).EndGetResponse(asynchronousResult);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string responseString = reader.ReadToEnd();
reader.Close();
var s = JsonConvert.DeserializeObject<List<TransactionViewModel>>(responseString);
foreach (var t in s)
{
Transactions.Add(new TransactionViewModel()
{
.........
}
}
Have I done something really stupid here?
When you come back from the request you are no longer on the UI thread. So you need to switch control back to the UI thread before performing any actions that will affect the UI.
You are updating an ObservableCollection, which will be bound on the UI and therefore the update is going to affect the UI.
There are a number of approaches, the simplest for you purposes will be
Deployment.Current.Dispatcher.BeginInvoke(()=> {
foreach (var t in s) {
Transactions.Add(new TransactionViewModel());
}
});
Edit: Also if you want to read a little more about this, I have a blog post about it here http://csainty.blogspot.com/2010/10/windows-phone-7asynchronous-programming.html it starts from code like yours that looks reasonable and should work, explains a few of the gotchas and how to get it working.

Resources