I'm working on a really big project developed by two teams, one (mainly) for the database, and one (where I am) mainly for the GUI and helper classes as an interface between GUI and DB.
Obviously, there are errors in communication, and - of course - we can't assume 100Mbit bandwidth & super-fast server computer.
Language is C# .NET, target "framework" is WPF and Silverlight.
When a user clicks a button, the GUI asks the DB (through helper classes) for information. Let's say... pizza types. The server should answer "{Funghi,Frutti di mare,Prosciutto}". When DB sends his answer, we receive a "database.Ready" event and fill our datagrid.
BUT if the user clicks the button while we haven't received the answer yet, the GUI sends an another request to the database. And the whole system tries to serve the user.
But it can't, because when the second request is sent, the first is disposed when we want to read it. So NullReferenceExceptions occur.
I've solved this by implementing kind of a semaphore which closes when user input occurs and opens when the Ready event (the functions it calls) finishes working.
Problem:
If I don't receive the Ready event, no user input is allowed, but this is wrong.
Question:
Is there a common (or at least, working) solution to stop waiting for the Ready event and...
1) re-sending the request a few times, hoping we receive our pizza types?
AND/OR
2) Dropping the request, tell the user that database failed to send the answer, and re-open the semaphore?
I can't post code here as this code is the property of a corporation, I'd rather like to have theoretical solutions, which are okay for professionals too.
Sorry for the long post, and thank you for your answers!
I assume that you are already using a background thread to dispatch the query to the database and wait for it's response. You can use the Task API that was introduced in .NET 4.0 to cancel such a request. For that, you pass in a CancellationToken that signals the status to the executing task. You can obtain a CancellationToken via a CancellationTokenSource as shown in the following code:
public partial class MainWindow : Window
{
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
public MainWindow()
{
InitializeComponent();
}
private void Button_CallDatabase(object sender, RoutedEventArgs e)
{
Task.Factory.StartNew(CallDatabase, _cancellationTokenSource.Token);
}
private void Button_OnNavigate(object sender, RoutedEventArgs e)
{
// If you navigate, you can cancel the background task and thus
// it will not execute any further
_cancellationTokenSource.Cancel();
}
private void CallDatabase()
{
// This simulates a DB call
for (var i = 0; i < 50; i++)
{
Thread.Sleep(100);
}
// Check if cancellation was requested
if (_cancellationTokenSource.Token.IsCancellationRequested)
{
Debug.WriteLine("Request cancelled");
return;
}
Debug.WriteLine("Update Controls with DB infos.");
}
}
Note that this example is simplified, you can and should use this in another component (e.g. view model).
If you still want to use the Ready event, you could also just unregister from it when you navigate away, so that no further actions will be performed when it is raised.
Related
I am creating a Form when a certain event occurs. I put this created Form into a static member of the class where it is created. I debugged the code and everything works fine but the Form stays blocked and the user can't do anything in this window. It just appears with a loading animation (see picture). So nothing in the opened window is clickable, you can't even close it.
class CallManagementObserver : CallObserver
{
private static FrmIncomingCall frmCurrentCall;
public CallManagementObserver()
{
}
public void callChangedEvent(CallEv[] events)
{
foreach (CallEv currentEvent in events)
{
switch (currentEvent.getID())
{
case TermConnRingingEv.ID:
// Incoming call
frmCurrentCall = new FrmIncomingCall(currentEvent);
frmCurrentCall.Show();
frmCurrentCall.Update();
break;
case CiscoCallInfoChangedEv.ID:
// User accepted external call on terminal
frmCurrentCall.Close();
break;
case TermConnActiveEv.ID:
// User is in call
frmCurrentCall.Close();
break;
case ConnDisconnectedEv.ID:
// Caller has hung up
frmCurrentCall.Close();
break;
default:
break;
}
}
}
}
}
As you can see above I wrote my own Form class whose code is here:
public partial class FrmIncomingCall : Form
{
Call incomingCall;
CallEv currentEvent;
public FrmIncomingCall(CallEv currentEvent)
{
InitializeComponent();
this.currentEvent = currentEvent;
this.incomingCall = currentEvent.getCall();
}
private void initGui()
{
Connection[] callConnections = incomingCall.getConnections();
Address caller = callConnections[1].getAddress();
lblIncomingCallSource.Text = caller.getName();
}
private void btnAcceptCall_Click(object sender, System.EventArgs e)
{
TermConnEv termConnEv = (TermConnEv)currentEvent;
TerminalConnection termConn = termConnEv.getTerminalConnection();
termConn.answer();
}
private void frmIncomingCall_Load(object sender, System.EventArgs e)
{
initGui();
}
}
When I show the Form via ShowDialog() it is usable but the program stops (since this is what dialogs are made for I guess).
Any ideas what I'm doing wrong? Nothing freezes, the program is running correctly.
Well, your application is poorly designed... It seems that you have no idea of what multithreading is and why you should use it.
If the application hangs forever, then either there is a deadlock (something like the dialog wait on the calling system and the calling system wait on the dialog).
As I have no idea what CallEv is and how it is intended to be used.
Well, if the calling system works and the UI is never updated, then obviously, you never let the UI have time to be updated because your UI thread is 100% of the time using the calling system or waiting on it.
That means that the calling system should probably be used from another thread and that you should have some communication between both threads...
It might also be possible that the calling system might be used in many different ways (as it would be the case for serial port and TCP communication) where one could use what fit most with his application.
Another problem with your code is that when you close a dialog, as far as I know it cannot be used anymore without recreating the dialog as the dialog would be disposed... So you would need to set the formCurrentCall to null and update any affected code. Alternatively, you might hide the form instead and show it again when required.
In any case, it is hard to help you because we don't have any idea of what is CallEv and other classes or events in your code. Also, we have no idea which code is executing when the UI is not responding (or updated). So the question do not have enough informations. In fact, such problem are way easier to debug using a debugger as it is far easier to see what code is run and which line of code take time to execute or even to see which code is not executed.
I'm trying to build a file download actor, using Akka.net. It should send messages on download completion but also report download progress.
In .NET there are classes supporting asynchronous operations using more than one event. For example WebClient.DownloadFileAsync has two events: DownloadProgressChanged and DownloadFileCompleted.
Preferably, one would use the task based async version and use the .PipeTo extension method. But, I can't see how that would work with an async method exposing two events. As is the case with WebClient.DownloadFileAsync. Even with WebClient.DownloadFileTaskAsync you still need to handle DownloadProgressChanged using an event handler.
The only way I found to use this was to hook up two event handlers upon creation of my actor. Then in the handlers, I messages to Self and the Sender. For this, I must refer to some private fields of the actor from inside the event handlers. This feels wrong to me, but I cannot see another way out.
Is there a safer way to use multiple event handlers in an Actor?
Currently, my solution looks like this (_client is a WebClient instance created in the constructor of the actor):
public void HandleStartDownload(StartDownload message)
{
_self = Self;
_downloadRequestor = Sender;
_uri = message.Uri;
_guid = message.Guid;
_tempPath = Path.GetTempFileName();
_client.DownloadFileAsync(_uri, _tempPath);
}
private void Client_DownloadFileCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
var completedMessage = new DownloadCompletedInternal(_guid, _tempPath);
_downloadRequestor.Tell(completedMessage);
_self.Tell(completedMessage);
}
private void Client_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
{
var progressedMessage = new DownloadProgressed(_guid, e.ProgressPercentage);
_downloadRequestor.Tell(progressedMessage);
_self.Tell(progressedMessage);
}
So when the download starts, some fields are set. Additionally, I make sure I Become a state where further StartDownload messages are stashed, until the DownloadCompleted message is received by Self:
public void Ready()
{
Receive<StartDownload>(message => {
HandleStartDownload(message);
Become(Downloading);
});
}
public void Downloading()
{
Receive<StartDownload>(message => {
Stash.Stash();
});
Receive<DownloadCompleted>(message => {
Become(Ready);
Stash.UnstashAll();
});
}
For reference, here's the entire Actor, but I think the important stuff is in this post directly: https://gist.github.com/AaronLenoir/4ce5480ecea580d5d283c5d08e8e71b5
I must refer to some private fields of the actor from inside the event
handlers. This feels wrong to me, but I cannot see another way out.
Is there a safer way to use multiple event handlers in an Actor?
There's nothing inherently wrong with an actor having internal state, and members that are part of that state raising events which are handled within the actor. No more wrong than this would be if taking an OO approach.
The only real concern is if that internal state gets mixed between multiple file download requests, but I think your current code is sound.
A possibly more palatable approach may be to look at the FileDownloadActor as a single use actor, fire it up, download the file, tell the result to the sender and then kill the actor. Starting up actors is a cheap operation, and this completely sidesteps the possibility of sharing the internal state between multiple download requests.
Unless of course you specifically need to queue downloads to run sequentially as your current code does - but the queue could be managed by another actor altogether and still treat the download actors as temporary.
I don't know if that is your case, but I see people treating Actors as micro services when they are simply objects. Remember Actors have internal state.
Now think about scalability, you can't scale messages to one Actor in a distributed Actor System. The messages you're sending to one Actor will be executed in the node executing that Actor.
If you want to execute download operations in parallel (for example), you do as Patrick said and create one Actor per download operation and that Actor can be executed in any available node.
We have an application that has a primary window, it can launch multiple other windows, in new browsers. We are using a silverlight application as a coordinating server in the primary window to close all windows that are part of the app, regardless of the way they are opened (we can't guarantee it was via window.open so don't always have a handle to the window in javascript).
On log out, we want to signal all the other windows to perform an auto-save, if necessary, then close down.
So all windows have a silverlight app, they coordinate using localmessagesenders. However, these are asynchronous:
private void ProcessAutosave()
{
foreach (string s in _windows)
{
SendMessage(s, "notify-logout");
}
// code here quoted later...
}
// sendasynch doesn't send until the method terminates, so have to do it in it's own function.
private void SendMessage(string to, string message)
{
var lms = new LocalMessageSender(to);
lms.SendCompleted += new EventHandler<SendCompletedEventArgs>(SenderSendCompleted);
lms.SendAsync(message);
}
Since the ProcessAutosave is called from a javascript onunload event which can't be cancelled, we need this to be synchronous and not complete before we have a response processed from each sub-window so the session state will still be valid etc.
In the SenderSendCompleted we remove items from _windows when they have said they're done.
So I added a loop on the end:
while(_windows.Count > 0) {
Thread.Sleep(1)
}
However, that never terminates, unless I put an iteration counter on it.
Am I the victim of a compiler optimisation meaning the changes in SenderSendCompleted do not affect that while loop, or, have I fundamentally misunderstood something? Or missed something obvious that's staring me in the face?
It sounds like a subtle verson of a race situation due to going sync/async. Couldn't the process in queston also receive notifications from the windows that they have received the message and are shutting down? Once all of the counter messages have been received, then the main app could shut down without the busy wait at the end(?).
I have found a way to work round. However, this does not really "solve" the problem generally, just in my case, which is also only supporting internet explorer.
function WindowCloseEventHandler()
{
var app = // get silverlight app handle...
app.doAutoSave();
var params = 'whatever you need';
var args = new Object();
args.hwnd = window;
window.showModalDialog('blocker.aspx',args,params);
}
function checkAutoSave()
{
var app = // get silverlight app handle...
return app.autosavecomplete();
}
Then in blocker.aspx we display a static "performing logout handlers" type message and do:
function timerTick()
{
if(window.dialogArguments.hwnd.checkAutoSave()) {
window.close();
} else {
setTimeout(timerTick, 500);
}
}
And start the timer on window load.
The child window's silverlight apps are notified to start an autosave, then they notify the parent when they are done. We then poll the parent's status from a modal dialog, which blocks the termination of the WindowCloseEventHandler() which we have wired up to the onclose event of the body.
It's hacky and horrible, but it means silverlight stays asynchronous and we're using a javascript timer so the javascript isn't loading the system.
Of course if the user closes the modal dialogue, there is a potential for issue.
I have a Server class which it basically waits for connections from a client. Inside that class I create an NetworkStream object in order to be able to receive bytes from a client. Because the NetworkStream.Read() method is not asynchronous (meaning that it will wait until it reads bytes from a client in order to proceed executing code similar to the messagebox method), I have to read for bytes in a separate thread so that the user using the program can still interact with the program if the program happens to be waiting to read for data.
anyways a lot of objects are owned by that thread. One example is that I have a List called log in that class. I use that list to know the status of the server. Maybe it is listening for a connection or perhaps it's status is "connected" or "disconnected".
So if I do something like:
Server myServer = new Server("192.168.0.120","1300"...\\ I pass the appropite parameters in order to instantiate it
//...
.. then I am able to latter look at the log as
string foo = myServer.Log[0] for example.
because I want to know when the log is updated, on the server class I have created an event as:
public delegate void onUpdateHandler(string newStatus);
public event onUpdateHandler onUpdate = delegate { };
I then fire events on the Server class as:
onUpdate("waitingForConnection");
and I receive those events with the method:
but if I try to do something with newStatus I get the error stating:
System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it.
so how can I pass an object with an event?
Edit
so I also notice that if I do:
I also get an error!
but when I do the same thing calling that from a button as:
// SERVER IS RUNNING BEFORE CALLING THIS METHOD
private void button3_Click(object sender, RoutedEventArgs e)
{
listView1.Items.Add("my own string");
}
I do NOT get an error!
why is it that I get an error with the event and I do not get an error when calling it with a regular button.
The problem is that the thread tries to access the ListView which is a DependencyObject which has thread affinity, use the Dispatcher to execute methods like this on the UI-thread, e.g.:
Application.Current.Dispatcher.Invoke((Action)(() =>
{
listView1.Items.Add(newStatus);
}));
Also see the threading model reference for additional info.
The problem is not that you try to do something with the value that you sent to the method, the problem is what you are trying to do with it.
The event handler is still running in your background thread, and from there you can't use any UI controls as they belong to the main thread.
The usual way of handling that is to use the CheckAccess method to check if you need to switch treads, and the Invoke method to hand off the work to the main thread:
void server_onUpdate(string newStatus) {
if (!listView1.Dispatcher.CheckAccess()) {
listView1.Dispatcher.Invoke(server_onUpdate, newStatus)
} else {
listView1.Items.Add(newStatus);
}
}
So I have this interface that is just one big GO button that syncs a bunch of data from one tool to another. The problem is it takes a really long freaking time and some users are left wondering whats the deal. So I am wondering if there is a way that I can put something in my loop so that every so many entries it sends something back to the page to update them on the progress.
Currently it is just an .aspx page with an aspx.cs behind it. The Go button fires off the whole process and it calls Response.Write a ton of times (as well as writing the same thing to a log file I made) but the Responses don't show until the entire thing is done.
Please advise.
You could design a class which will be stored in the session and which will represent the current state of the operation:
public class OperationState
{
public object Result { get; set; }
public int Progress { get; set; }
public string Error { get; set; }
}
An instance of this class could be created when you start the operation and store it in the user session. Then at each step of the operation you could retrieve it from session and update the progress property. Once the operation terminates you could set the Result property or the Error property in case an exception occurs. In the meantime you could design a PageMethod which will be accessible from client script. This method will simply return the State instance from the session. You will then invoke it periodically and asynchronously from javascript to check the progress and update the DOM to notify the user.
I am assuming you are calling another class to do the work. Lets call this the WorkerClass
You can have the WorkerClass have an event hooked up to it, that the .aspx page hooks up too and will write a message when the event is triggered.
// Overload EventArgs to send messageas back up
public delegate void UpdateMethod(object sender, EventArgs e);
public class WorkerClass
{
public event UpdateMethod UpdateMethod;
}
WorkerClass worker = new WorkerClass();
worker.UpdateMethod += new UpdateMethod(worker_UpdateMethod);
EDIT based on Comment it is on there page
If you don't want to refactor to another class doing the work (which I suggest). You can post the messages this way.
protected override void Render(HtmlTextWriter writer)
{
base.Render(writer);
this.ProcessMassiveWorkLoad();
}
private void ProcessMassiveWorkLoad()
{
for(int i = 0; i < 100000; i++)
{
// Do some work
// Write the fact you have work
Response.Write(string.Format("Done {0} of 100000", i);
}
}
The simplest way to resolve your issue is to call Response.Flush() after each Response.Write.
This will flush the current response buffer back to the client, enabling them to see the current state of the page.
Even David's method would need this to get the responses out to the user in a timely manner.
The better solution would be along the lines of Darin's solution, which would involve some client side scripting of (say) an update panel, that you refresh with a JavaScript timer to get the latest state, but that may introduce other issues for you (needing JavaScript turned on, rewriting the long running method as something you can fire off asynchronously, etc).
If it's any consolation, I've done both in the past, and would use either again.