UnauthorizedAccessException: Invalid cross-thread access in Silverlight application (XAML/C#) - c#

Relatively new to C# and wanted to try playing around with some third party web service API's with it.
Here is the XAML code
<Grid x:Name="ContentGrid" Grid.Row="1">
<StackPanel>
<Button Content="Load Data" Click="Button_Click" />
<TextBlock x:Name="TwitterPost" Text="Here I am"/>
</StackPanel>
</Grid>
and here is the C# code
private void Button_Click(object sender, RoutedEventArgs e)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://api.twitter.com/1/users/show/keykoo.xml");
request.Method = "GET";
request.BeginGetResponse(new AsyncCallback(twitterCallback), request);
}
private void twitterCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
TextReader reader = new StreamReader(response.GetResponseStream());
string strResponse = reader.ReadToEnd();
Console.WriteLine("I am done here");
TwitterPost.Text = "hello there";
}
I'm guessing that this is caused by the fact that the callback executes on a separate thread than the UI? What is the normal flow to deal with these types of interactions in C#?
Thanks.

A useful way to get easy cross thread access with the CheckAccess call is to wrap up a utility method in a static class - e.g.
public static class UIThread
{
private static readonly Dispatcher Dispatcher;
static UIThread()
{
// Store a reference to the current Dispatcher once per application
Dispatcher = Deployment.Current.Dispatcher;
}
/// <summary>
/// Invokes the given action on the UI thread - if the current thread is the UI thread this will just invoke the action directly on
/// the current thread so it can be safely called without the calling method being aware of which thread it is on.
/// </summary>
public static void Invoke(Action action)
{
if (Dispatcher.CheckAccess())
action.Invoke();
else
Dispatcher.BeginInvoke(action);
}
}
then you can wrap any calls that update the UI where you may be on a background thread like so:
private void twitterCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
TextReader reader = new StreamReader(response.GetResponseStream());
string strResponse = reader.ReadToEnd();
UIThread.Invoke(() => TwitterPost.Text = "hello there");
}
This way you don't have to know whether you are on a background thread or not and it avoids the overhead of adding methods to every control to check this.

Another way to do this is to use the this.Dispatcher.CheckAccess() function. It is the same as what you get in WPF but it doesn't show up in your intellisense so you may not have seen it. What you do is check if you have access to the UI thread, and if you don't you recursively call yourself back on the UI thread.
private void twitterCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(result);
TextReader reader = new StreamReader(response.GetResponseStream());
string strResponse = reader.ReadToEnd();
Console.WriteLine("I am done here");
////TwitterPost.Text = "hello there";
postMyMessage(TwitterPost.Text);
}
private void postMyMessage(string text)
{
if (this.Dispatcher.CheckAccess())
TwitterPost.Text = text;
else
this.Dispatcher.BeginInvoke(new Action<string>(postMyMessage), text);
}
This is just a very simple example and can get unmanageable once you have more than a few controls. For some WPF/Silverlight stuff i have used a generic function which also takes the UI control to be updated as well as the update itself, that way i don't have one of these functions for every control on the page that may need updating from the results of a background thread.

As you guessed, silverlight executes all web request asynchronously on a separated thread to avoid freezing the UI.
To dispatch messages to the UI thread you can use the Deployment.Current.Dispatcher.BeginInvoke(delegate, object[]) method.

Related

Which to use, WebClient.OpenRead, OpenReadAsync or OpenReadTaskAsync

I'm trying to understand the differences among WebClient.OpenRead, WebClient.OpenReadAsync and WebClient.OpenReadTaskAsync.
It looks like these have differences regarding blocking a thread, but I don't understand it well.
Could you please explain the differences? It would be great if you could give me some example (examples don't have to be sample code, but would be great if you could provide)
As you said, the difference is in thread blocking behavior. First one (OpenRead()) is thread blocking operation, other two - not. For example, let assume, that your network latency to reach google.com is 300ms. When you do var stream = webClient.OpenRead(#"https://www.google.com"); your application is "paused" for this 300ms, so code next to this line is not executed until your webClient return a stream to stream variable. This is calling Thread blocking.
When you do this in UI-thread (in example: in a button click handler) - your application become freezing and not responding to user actions. This is bad user experience, so never-ever call a thread blocking stuff in your UI. Here is example for console application:
var address = #"https://www.google.com/";
Console.WriteLine($"Opening stream from {address}");
using (var stream = webClient.OpenRead(address)) // this will block for 300ms
{
Console.WriteLine("Stream is open!");
// some other code
}
Second method (OpenReadAsync()) is asynchronous and return nothing immediately after a call, so your thread is not blocked. After awhile (300ms) OpenReadCompleted event will be raised by your webClient and all attached listeners will handle opened stream one-by-one. Here is an example:
public partial class MainForm : Form
{
private WebClient _client = new WebClient();
public MainForm()
{
InitializeComponents();
_client.OpenReadCompleted += OpenReadCompletedHandler;
}
private void ButtonClickHandler(object sender, EventArgs e)
{
_client.OpenReadAsync(#"https://www.google.com/");
}
private void OpenReadCompletedHandler(object sender, OpenReadCompletedEventArgs e)
{
// this event will be raiesed 300ms after 'Button' click
var stream = e.Result; // <- here is your stream
// some other code
}
}
The last one (OpenReadTaskAsync()) is all about TPL (Task Parallel Library) and async/await keywords. It runs all stuff in a Task which is returned by this method. Here is an example:
public partial class MainForm : Form
{
private WebClient _client = new WebClient();
public MainForm()
{
InitializeComponents();
}
private async void ButtonClickHandler(object sender, EventArgs e)
{
// after 'await' keyword, execution will be returned from this method immediately
// meanwhile, actual acquiring of 'stream' is running in a background thread
using (var stream = await _client.OpenReadTaskAsync(#"https://www.google.com/"))
{
// after 300ms, this code will be continued in UI thread
// result will be automaticly unpacked to 'stream' variable
// some other code
}
}
}
Hope this helps.
I'd suggest WebClient is more or less obsolete now, HttpClient is more appropriate for anything targeting .NET framework 4.5+ or .NET core. Just watch out that the latter does not automatically throw exceptions on HTTP error codes (400+).

WebRequest hangs user interface

I'm doing simple request with WebRequest and the app just hangs until the response comes back. How do I fix this?
I have read a lot of topics and they all say to use threads. I don't know how to use them; can anyone provide an example of the following that doesn't hang the user interface?
private string SimpleRequest(String url)
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
stream.Dispose();
reader.Dispose();
return result;
}
private void button1_Click(object sender, EventArgs e)
{
String googleHtml = simpleRequest("https://facebook.com");
}
Thanks!
If you are using c# 5.0 it is too easy
public async void Test1()
{
WebClient wc = new WebClient();
richTextBox1.Text = await wc.DownloadStringTaskAsync("https://facebook.com");
}
You can convert your method to awaitable also
private Task<string> simpleRequest(String url)
{
return Task.Factory.StartNew(() =>
{
WebRequest request = WebRequest.Create(url);
WebResponse response = request.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader reader = new StreamReader(stream);
string result = reader.ReadToEnd();
stream.Dispose();
reader.Dispose();
return result;
});
}
and call as
public async void Test2()
{
richTextBox1.Text = await simpleRequest("https://facebook.com");
}
For lower versions of C#, See other answers.
You can use a BackgroundWorker in order to use another thread than UI thread. Here is a sample.
You can also cancel or display progress:
public partial class fmMain : Form
{
private void btnrunBackgroundWorker_Click( object sender, EventArgs e )
{
// Create a background worker
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler( bw_DoWork );
// run in another thread
bw.RunWorkerAsync();
}
private void bw_DoWork( object sender, DoWorkEventArgs e )
{
String facebookHtml = simpleRequest("https://facebook.com");
}
}
You're doing network access on the main UI thread. The UI has a main thread which loops and updates the UI. If you do network access on that thread, the UI will not update and it will appear hung until your method returns and the loop can continue.
Consider doing your work on a background thread. One easy way to do that in .net is the BackgroundWorker class.
The official documentation has a nice example of it's usage:
http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx
The BackgroundWorker class allows you to run an operation on a
separate, dedicated thread. Time-consuming operations like downloads
and database transactions can cause your user interface (UI) to seem
as though it has stopped responding while they are running. When you
want a responsive UI and you are faced with long delays associated
with such operations, the BackgroundWorker class provides a convenient
solution.
You should use a BackgroundWorker so your main UI thread does not hang!
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync("https://facebook.com"); // start async operation
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
e.Result = simpleRequest(e.Argument.ToString()); // set result in async operation
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Error == null)
{
// show result here
// or access/manage result here
MessageBox.Show(e.Result.ToString());
}
else
{
// manage/show error
MessageBox.Show(e.Error.Message);
}
}
private String simpleRequest(String url)
{
// your code goes here
}
You could implement backgroundWorker1_ProgressChanged too, so that the user can see progress of loading webSite. (sideNote: see this question for details on ProgressChanged and Context)

Windows Phone BackgroundWorker for WebClient?

Now the WebClient issue is fixed and can return on a background thread i'd like to start using it in this way.
After much searching I've come up with this code that appears to work fine, is this all there is to it?
BackgroundWorker bw = new BackgroundWorker();
bw.DoWork += (s,e) =>
{
WebClient wc = new WebClient();
wc.DownloadStringCompleted += DownloadStringCompleted;
wc.DownloadStringAsync(url);
};
bw.RunWorkerAsync();
In DownloadStringCompleted I send the result back to the UI thread.
Have I missed anything important or is it really this simple?
I don't get why you would want to run the WebClient on a background thread in the first place, since the WebClient is already creating a thread for the downloading part.
The difference is that the WebClient is running it's DownloadStringCompleted event on the UI thread. Which it still would do in your code.
I would suggest you use WebRequest class instead. The use of the WebRequest class can be greatly simplified with a simple extension method, that makes it behave like the WebClient.
public static class WebRequestEx
{
public static void DownloadStringAsync(this WebRequest request, Action<string> callback)
{
if (request == null)
throw new ArgumentNullException("request");
if (callback == null)
throw new ArgumentNullException("callback");
request.BeginGetResponse((IAsyncResult result) =>
{
try
{
var response = request.EndGetResponse(result);
using (var reader = new StreamReader(response.GetResponseStream()))
{
callback(reader.ReadToEnd());
}
}
catch (WebException e)
{
// Don't perform a callback, as this error is mostly due to
// there being no internet connection available.
System.Diagnostics.Debug.WriteLine(e.Message);
}
}, request);
}
}
The issue I referred to was that in 7.0 WebClient always returned on the UI thread regardless of where it was created, potentially making the UI unresponsive.
In the WP SDK 7.1 WebClient will return on the thread it was created from, so if it is created from a background thread DownloadStringCompleted will now return on a background thread.
If you test my example without marshalling the response you will see an Invalid Cross Thread Exception.
It seems to me unless you have a reason not to, why not use WebClient now?
Seems that easy.
Check only if everything which can be disposed get's disposed.

WebRequest.BeginGetResponse does not work asynchronously

I have C# code and have a problem with webRequest.begingetresponse.
When I try to used it for asynchronous call, the working thread is blocked and waits for the callback to be called. But, as I read in documentation, the current thread should continue to run and the callback method should be invoked by a different thread once the response is back from the server.
[UPDATE] Actually getting the response back from the server is where the current thread is blocked, and when I check the thread IDs, the thread which calls the callback is the same thread who sent the request.
Any idea what I might be missing?
Here's a snippet of the code:
public class MyRequestState
{
public WebRequest Request;
public WebResponse Response;
public ManualResetEvent allDone = new ManualResetEvent(false);
public MyRequestState()
{
Request = null;
Response = null;
}
}
public class SendRequest
{
private void ResponseCallback(IAsyncResult result)
{
//do sth ...
state.Response = (HttpWebResponse)request.EndGetResponse(result);
//do sth ...
state.allDone.Set();
}
public void MakeWebRequestAsync(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "GET";
request.Proxy = null;
state state = new MyRequestState();
state.Request = request;
IAsyncResult result = request.BeginGetResponse(new System.AsyncCallback(ResponseCallback), state);
state.allDone.WaitOne();
}
}
WebRequest.BeginGetResponse wait for connection synchronously and then receive data asynchronously. If the connection takes some times, it will freeze the calling thread for a while.
You are waiting on your ManualResetEvent right after starting the request. That's why your thread blocks. The thread isn't being signaled to continue until your completed callback is called.

Accessing controls through threads

I use WebBrowser Control in c# to check a couple search engine results but sometime for no reason it gets stuck. My first thought was to make each searching function as a thread and use thread.abort() from a timer but I just couldn't handle with the UI Controls (including the WebBrowser) no matter what I've tried.
Anyone has a solution for me? an example would be great cause I already tried so many things and I keep getting all these exceptions.
I believe you can use WebRequest in a Background worker & avoid the difficulties of dealing with the COM threading model. You can use WebRequest.Timeout to handle anything you think is taking too long.
Try something like this:
static void Main(string[] args)
{
BackgroundWorker bg = new BackgroundWorker();
bg.DoWork += backgroundWorker_DoWork;
bg.RunWorkerAsync(new List<object> { "http://download.thinkbroadband.com/512MB.zip" });
while (true) {}
}
private static void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("Starting operation.");
BackgroundWorker bw = sender as BackgroundWorker;
List<object> args = (List<object>)e.Argument;
var url = (string)args[0];
WebRequest request = WebRequest.Create(url);
request.Timeout = 300;
try
{
WebResponse response = request.GetResponse();
Console.WriteLine("Request successful.");
}
catch (Exception ex)
{
Console.WriteLine("Request timed out.");
}
}
WebBrowser is a component you should use when you want to embed an instance of IE into your presentation layer. Unless you need this, you can use something more lightwweight.
Use the control's .Invoke() method: http://msdn.microsoft.com/en-us/library/zyzhdc6b.aspx
There are other methods you can use too: .BeginInvoke and .EndInvoke for asynchronous invokes.
if(control.InvokeRequired)
{
control.Invoke(control.delegate);
}

Categories

Resources