I have a simple method which is used to call a WebRequest as demonstrated in the following code. The callback always hits on NetworkError.WebRequestAlreadyFinished. How might I fix my code so that I can get the information from the callback?
private async void stkWebRequestConnInfo_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
HttpWebRequest request = WebRequest.CreateHttp("http://bing.com");
IAsyncResult result = (IAsyncResult)request.BeginGetResponse(new AsyncCallback(response_Callback), request);
}
private void response_Callback(IAsyncResult asyncResult)
{
HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState;
NetworkInterfaceInfo netInterfaceInfo = null;
try
{
netInterfaceInfo = request.GetCurrentNetworkInterface();
request.EndGetResponse(asyncResult);
}
catch (NetworkException e)
{
// Calling GetCurrentNetworkInterface will throw a NetworkException if the WebRequest has already completed.
// To make this call succeed, make a high latency web request call.
if (e.NetworkErrorCode == NetworkError.WebRequestAlreadyFinished)
{
DisplayMessage(AppResources.MainPage_Info_CannotCallWebRequest, AppResources.MainPage_Info_NetworkInterfaceInformation, MessageBoxButton.OK);
return;
}
else if (e.NetworkErrorCode == NetworkError.NetworkSelectionRequirementFailed)
{
DisplayMessage(AppResources.MainPage_Info_ConnectionRequirementFailed, AppResources.MainPage_Info_NetworkInterfaceInformation, MessageBoxButton.OK);
}
}
catch (WebException e)
{
DisplayMessage(AppResources.MainPage_Info_GeneralError, AppResources.MainPage_Info_WebRequestFailed, MessageBoxButton.OK);
}
// Use a StringBuilder to efficiently build up an information text about this
// NetworkInterfaceInfo.
StringBuilder sb = new StringBuilder();
sb.Append(AppResources.MainPage_Info_Name + " ");
sb.AppendLine(netInterfaceInfo.InterfaceName);
sb.Append(AppResources.MainPage_Info_Type + " ");
sb.AppendLine(GetInterfaceTypeString(netInterfaceInfo.InterfaceType));
DisplayMessage(sb.ToString(), AppResources.MainPage_Info_NetworkInterfaceInformation, MessageBoxButton.OK);
}
void DisplayMessage(string text, string caption, MessageBoxButton buttonConfiguration)
{
Dispatcher.BeginInvoke(() =>
{
MessageBox.Show(text, caption, buttonConfiguration);
});
}
GetCurrentNetworkInterface must be called from the UI thread. So wrap the call with Dispatcher.BeginInvoke();
Related
I have an async function which still freezes / lags the UI thread for me when I execute it. This is my function calling it.
private void TcpListenerLogic(object sender, string e)
{
Application.Current.Dispatcher.BeginInvoke((Action)async delegate {
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
// Get properties for new anchor
string testInformation = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + results.test_id);
}
}
catch (Exception exception)
{
// Writing some Trace.WriteLine()'s
}
});
}
And this is the async function that freezes my UI Thread
public static async Task<string> getJsonFromURL(string url)
{
try
{
string returnString = null;
using (System.Net.WebClient client = new System.Net.WebClient())
{
returnString = await client.DownloadStringTaskAsync(url);
}
return returnString;
}
catch (Exception ex)
{
Debug.WriteLine(ex.ToString());
return null;
}
}
I already tried to make everything in TcpListenerLogic run in a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
}).Start();
Which resulted in the whole UI completely freezing. And I tried to make TcpListenerLogic async and await the dispatcher, which also made everything freeze permanently. I also tried to make TcpListenerLogic async and leave the dispatcher. The dispatcher is only there because I normally have some UI code in there, which I left out for my tests.
I have ventured far through the internet, but no BackgroundWorker, ThreadPool or other methods helped me in my endeavour.
If anyone has help for this particular problem, or a resource that would improve my understanding of async functions in C#, I would much appreciate it.
Edit
As requested a deeper insight in how this event handler is called.
I have System.Net.Websocket, which is connected to the Backend API I am working with and triggers an event, everytime he receives new Data. To guarantee the socket listens as longs as it is open, there is a while loop which checks for the client state:
public event EventHandler<string> TcpReceived;
public async void StartListener(string ip, int port, string path)
{
try
{
using (client = new ClientWebSocket())
{
try
{ // Connect to backend
Uri serverUri = new Uri("ws://" + ip + ":" + port.ToString() + path );
await client.ConnectAsync(serverUri, CancellationToken.None);
}
catch (Exception ex)
{
BackendSettings.IsConnected = false;
Debug.WriteLine("Error connecting TCP Socket: " + ex.ToString());
}
state = client.State;
// Grab packages send in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
try
{
// **Just formatting the received data until here and writing it into the "message" variable**//
TcpReceived(this, message);
// Close connection on command
if (result.MessageType == WebSocketMessageType.Close)
{
Debug.WriteLine("Closing TCP Socket.");
shouldstayclosed = true;
await client.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
break;
}
state = client.State;
}
catch
{
BackendSettings.IsConnected = false;
state = client.State;
}
}
state = client.State;
}
}
catch (Exception ex)
{
// Some error messages and settings handling
}
}
The Event has a handler attached:
TcpReceived += TcpListener_TcpReceived;
And this is the Handler, which calls the previously seen "TcpListenereLogic".
private void TcpListener_TcpReceived(object sender, string e)
{
TcpListenerLogic(sender, e);
//App.Current.Dispatcher.BeginInvoke(new Action(() => {
// TcpListenerLogic(sender, e);
//}));
//new Thread(() =>
//{
// Thread.CurrentThread.IsBackground = true;
// TcpListenerLogic(sender, e);
//}).Start();
}
I previously had the "TcpListenereLogic" as the handler, but I wanted to try different methods to call it. I also left in the commented out part, to show how the call of "TcpListenereLogic" looked already. All my attempts were with all mentioned setups and sadly lead to nothing.
Thank you very much #TheodorZoulias for helping me to find the solution to my problem.
It turns out it wasn't the async function itself, but rather how often it gets called. It got called roughly ~120 times every second.
My solution starts by calling the Listener method over a new Thread:
new Thread(() =>
{
Thread.CurrentThread.IsBackground = true;
MainWindow.tcpListener.StartListener(ip, portNumber, "/api/");
}).Start();
To limit the amount of calls that happen every second I added a dispatcher timer, that resets a bool after it has been used for a call, by my Event.
readonly System.Windows.Threading.DispatcherTimer packageIntervallTimer =
new System.Windows.Threading.DispatcherTimer();
bool readyForNewPackage = true;
private void ReadyForPackage(object sender, EventArgs e)
{
readyForNewPackage = true;
}
public async void StartListener(string ip, int port, string path)
{
packageIntervallTimer.Interval = TimeSpan.FromMilliseconds(50);
packageIntervallTimer.Tick += (s, e) => { Task.Run(() => ReadyForPackage(s, e)); };
packageIntervallTimer.Start();
Then I wrapped everything inside the while loop into an if condition based on the bool, the most important part was to have my "event EventHandler TcpReceived" in there:
// Grab packages sent in backend
while (client.State == WebSocketState.Open || client.State == WebSocketState.CloseSent)
{
if (readyForNewPackage == true)
{
readyForNewPackage = false;
try
{
....
TcpReceived(this, message);
....
}
catch
{
...
}
}
}
I added my TcpListenerLogic to the Eventhandler:
TcpReceived += TcpListenerLogic;
And my TcpListenerLogic now looked like this (names have been changed):
private async void TcpListenerLogic(object sender, string e)
{
try
{
dynamic results = JsonConvert.DeserializeObject<dynamic>(e);
if (results.test_id != null)
{
string testID = "";
if (results.test_id is JValue jValueTestId)
{
testID = jValueTestId.Value.ToString();
}
else if (results.test_id is string)
{
testID = results.test_id;
}
// Get properties for new object
string information = await CommunicationCommands.getJsonFromURL(
"http://" + ServerIP + ":" + ServerPort + "/api/" + testID );
if (information != null)
{
await App.Current.Dispatcher.BeginInvoke(new Action(() =>
{
// Create object out of the json string
TestStatus testStatus = new TestStatus();
testStatus.Deserialize(information);
if (CommunicationCommands.isNameAlreadyInCollection(testStatus.name) == false)
{
// Add new object to the list
CommunicationCommands.allFoundTests.Add(testStatus);
}
}));
{
}
catch (Exception exception)
{
....
}
}
Adding a new Thread to execute any step results in problems, so keep in mind that all this uses the thread created at the beginning for "StartListener"
I was working on my windows form program, and i saw that the login function (linked to a simple button) freeze my application. I searched on internet and i found how to create a task, but i'm not sure about how it works ...
That's my login function, how can i correctly translate it into a task?
string sURL = url + "/login";
string result = null;
await Task.Run(() =>
{
try
{
result = Web_api.MakeRequest("POST", sURL); //return null if there is some error
}
catch(Exception ex)
{
Debug.WriteLine("[frmLogin] --> result: " + result);
}
});
if(result != null)
{
try
{
Login_response accepted = JsonConvert.DeserializeObject<Login_response>(result);
Debug.WriteLine("[frm_Login] --> accepted: " + accepted);
if (accepted.login)
{
//throw new Exception();
Debug.WriteLine("[frm_login]: result " + result);
frmMain frm = new frmMain(); //calling the new form
frm.Show(); //new form is show-up
this.Hide(); //log-in form hide
frm.FormClosed += Frm_FormClosed; //close the form
}
}
//if server is down, or the id or password is wrong
catch (Exception ex)
{
lblLoginError.Visible = true; //pop-up the error label
pbLogin.Visible = false; //hide the progress-bar
this.Style = MetroFramework.MetroColorStyle.Red; //changing the color of the form
Debug.WriteLine("Exception: " + ex);
}
}
else
{
lblLoginError.Visible = true; //pop-up the error label
pbLogin.Visible = false; //hide the progress-bar
this.Style = MetroFramework.MetroColorStyle.Red; //changing the color of the form
}
EDIT: i provided a real (and working) soluction and i followed all the suggestion in the comments ... do you think this could be acceptable?
Execute any potentially long-running code on a background thread using a Task:
private async void btnLogin_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtUser.Text.Trim()) || string.IsNullOrEmpty(txtPassword.Text.Trim()))
{
MessageBox.Show("You must insert a valid user/password format", "Login Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
//Progress bar start
pbLogin.Visible = true; // BUT THIS PROGRESS BAR I STACK DUE TO STATIC DEFINITON OF LOGIN
//Getting ID + Password
User.username = txtUser.Text;
User.password = txtPassword.Text;
string sURL = Web_api.url + "/login";
try
{
Login_response accepted = await Task.Run(() =>
{
//the following code gets executed on a background thread...
string result = Web_api.MakeRequest("POST", sURL);
Login_response accepted = JsonConvert.DeserializeObject<Login_response>(result);
Debug.WriteLine("[frm_Login] --> accepted: " + accepted);
return accepted;
});
//...and here you are back on the UI thread once the task has completed
if (accepted.login)
{
//throw new Exception();
Debug.WriteLine("[frm_login]: result " + result);
frmMain frm = new frmMain(); //calling the new form
frm.Show(); //new form is show-up
this.Hide(); //log-in form hide
frm.FormClosed += Frm_FormClosed; //close the form
}
}
//if server is down, or the id or password is wrong
catch (Exception ex)
{
lblLoginError.Visible = true; //pop-up the error label
pbLogin.Visible = false; //hide the progress-bar
this.Style = MetroFramework.MetroColorStyle.Red; //changing the color of the form
Debug.WriteLine("Exception: " + ex);
}
}
Event handlers always return void. They are an exception to the rule that says that an async method always should return a Task or a Task<T>.
You can create an async void method. It is actually the correct way to implement async callbacks for events such as button click.
First, let's make an asynchronous login method :
public async Task LoginAsync()
{
try
{
var stream = await _http.GetStreamAsync($"{baseUrl}/login");
var response = await JsonSerializer.DeserializeAsync<LoginResponse>(stream);
if (!response.login)
{
throw new BusinessException<LoginError>(LoginError.LoginDenied);
}
}
catch (HttpRequestException ex)
{
throw new BusinessException<LoginError>(LoginError.LoginFailed, ex);
}
}
Now we implement an asynchronous button callback:
private async void btnLogin_Click(object sender, EventArgs e)
{
try
{
await authentication.LoginAsync().ConfigureAwait(false);
// handle login success here
}
catch (BusinessException<LoginError> ex) when (ex.Error == LoginError.LoginDenied)
{
// handle login denied here
}
catch (BusinessException<LoginError> ex) when (ex.Error == LoginError.LoginFailed)
{
// handle connection failed here
}
}
If you want the LoginAsync() method to do some UI operations (for instance showing a form), you will need to use ConfigureAwait(true). Otherwise, there is a risk that part of the method is executed on a different thread and UI operations will fail.
I tested this code with placing a breakpoint in Monodevelop, running on a Raspbian. This app needs to communicate with a Windows, with a C# console application.
Although the timer1_Tick method prints the incoming message everytime (and it clearly prints the new message, because there I clear the message variable everytime after an incoming message), it seems to be that the OnNewData doesn't run everytime, when there's an incoming message.
I ask new incoming message with sending the "mes" out in the timer1_Tick.
I don't process the other kind of incoming messages in that method, but for the response for "mes", this place would be the best for processing. The reason is the "mes" creates answer types ("", " type answers), what I can get anytime.
I don't know what is the problem. Any idea? How could this happen, if the textbox is being refreshed nicely after each new incoming message?
public partial class Form0 : Form
{
public static string ReadCharactersIntoString(){
char c='c';
string outputString=String.Empty;
do{
c=(char)streamReader.Read();
outputString=outputString+c;
}while(c!='>');
return outputString;
}
async void OnNewData(object sender, EventArgs e){
message = Form0.ReadCharactersIntoString ();
//work with message variable works unreliable...
//sometimes this method runs, when there's an incoming message, sometimes it's not...
//although tick method prints the message everytime...
//why? how to solve this?
reseter.Set ();
}
public void AcceptMessages(){
while (true) {
try{
if (streamReader!=null && streamReader.Peek () > 0) {
newIncomingDataEvent.Invoke(this,EventArgs.Empty);
reseter.WaitOne ();
}
}catch{
}
}
}
public static async Task Waiting(){
while (message == null || message[message.Length-1]!='>') {
}
}
public static async Task<string> CollectingAnswer(){
await Waiting();
return message;
//when the answer is completely collected, it gives me back
}
public void ConnectionEstablisher()
{
while (true)
{
if (!activeConnection)
{
try
{
socketForServer = new TcpClient(ip, port);
networkStream = socketForServer.GetStream();
streamReader = new System.IO.StreamReader(networkStream);
streamWriter = new System.IO.StreamWriter(networkStream);
streamReader.BaseStream.ReadTimeout = 5000;
streamWriter.BaseStream.ReadTimeout = 5000;
activeConnection = true;
newIncomingDataEvent+=OnNewData;
reseter = new ManualResetEvent (true);
}
catch(Exception e)
{
activeConnection = false;
}
}
}
}
private async void timer1_Tick(object sender, EventArgs e)
{
if (this.Visible && activeConnection)
{
try
{
streamWriter.Write("mes");
streamWriter.Flush();
textBoxSending.AppendText("mes" + Environment.NewLine);
collectAnswer=CollectingAnswer();
outputString=await collectAnswer;
message=null;
textBoxAccepting.AppendText(outputString + Environment.NewLine);
//this always prints the incoming response message...
I have a WinForms application which uses a backgroundworker for downloading images from given urls. For the download I use a backgroundworker.
The application is running fine when started, and the download happens as planned, but when the worker is done and I click the downloadbutton again to start downloading from another url, the backgroundworker doesn't do anything.
I fixed that problem temporarily by calling application.restart() when the worker is done, which works but can't be here longer than it has to.
Worker-Code:
// initialization of worker is done in constructor of my class
downloadWorker.WorkerReportsProgress = true;
downloadWorker.WorkerSupportsCancellation = true;
downloadWorker.DoWork += new DoWorkEventHandler(worker_doWork);
downloadWorker.ProgressChanged += new ProgressChangedEventHandler(worker_progressChanged);
downloadWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_runWorkerCompleted);
// ...
private void worker_doWork(object sender, DoWorkEventArgs e)
{
WebClient downloadClient = new WebClient();
HttpWebRequest HttpReq = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response;
try
{
response = (HttpWebResponse)HttpReq.GetResponse();
}
catch (WebException ex)
{
response = (HttpWebResponse)ex.Response;
}
if (response.StatusCode == HttpStatusCode.NotFound)
MessageBox.Show("Website not found");
if (response.StatusCode == HttpStatusCode.OK)
{
for(int i=0; i<3;i++)
{
string image = getImageUrl(url,i);
downloadWorker.ReportProgress(i);
image = WebUtility.HtmlDecode(image);
string saveName = "img_"+i+".png";
try
{
downloadClient.DownloadFile(image, saveName);
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace);
}
}
}
}
private void worker_progressChanged(object sender, ProgressChangedEventArgs e)
{
rtxtStatus.AppendText("Downloade Image" + e.ProgressPercentage + " of 3");
}
private void worker_runWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
MessageBox.Show("Download completed");
}
edit:
if (e.Error != null)
{
MessageBox.Show(e.Error.ToString());
}
To avoid any misunderstandings: The backgroundWorker is definetely running at the second time, and it is not an error of the reportProgress-method, since I get the same thing when I dont report anything.
edit no. 2:
I found out where the error came from: at the second run, the for-loop is completely skipped. But that doesn't make any sense for me either... There can't be any other value still be in because I have a completely new instance of the class, can it? But anyway, if it just skipped the method the worker still should exit which it doesn't do. For testing, I added a MessageBox after the for-loop, which is not executed after the second run.
I'm running my program as a windows service and I'm trying to send a HTTP request everytime the time elapsed(i've set to 1 minute). What I'm trying to do at the server side is just writing a value that it gets from the query string. The writing to file works but i noticed there is some duplicate values being sent?
protected override void OnStart(string[] args)
{
try
{
eventLog1.WriteEntry("In OnStart, this is another new build 016");
timer1 = new System.Timers.Timer(5000D);
timer1.AutoReset = true;
timer1.Elapsed += new ElapsedEventHandler(timer_Elapsed);
timer1.Start();
eventLog1.WriteEntry("This is after calling start method");
}
catch (Exception exxx)
{
eventLog1.WriteEntry(exxx.Data.ToString());
}
}
protected override void OnStop()
{
eventLog1.WriteEntry("In onStop.");
}
private static void timer_Elapsed(object source, ElapsedEventArgs e)
{
timer1.Stop();
el.WriteEntry("The Elapsed event was raised at " + i);
i++;// i is initialized to 0
request = (System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create("http://www.example.com/Test.php?test=" + i);
request.Method = "GET";
request.Timeout = 5000;
try
{
request.BeginGetResponse(new AsyncCallback(FinishWebRequest), request);
}
catch (System.Net.WebException e1)
{
el.WriteEntry("Exception 1:" + e1.Message);
}
catch (System.Net.ProtocolViolationException e2)
{
el.WriteEntry("Exception 2:" + e2.Message);
}
catch (System.InvalidOperationException e3)
{
el.WriteEntry("Exception 3:" + e3.Message);
}
timer1.Start();
}
private static void FinishWebRequest(IAsyncResult result)
{
request.GetResponse().Close();
}
What i noticed in my file is something like 1,2,1,1,3,2,2,1,1. I don't see anything wrong with my code. Is it possible that the HttpWebRequest is sending duplicate request?
In my opinion code is correct.I think you are using i variable somewhere else also.
Try changing i to something else which is not so common
HttpWebRequest never sends same request duplicate request.
For an instance let us assume that HttpRequest are duplicated then output should be something like 1,1,1,1,2,2,2,3.....