I have an unmanaged DLL which I'm trying to create a .NET wrapper library for but am getting different behavior when I try and run a NUnit(v3) test over it compared to if it is just run from a button click off a WinForm app.
Background: During startup of the DLL I call its Connect() method, which ultimately causes the DLL to make a TCP connection. When the TCP connection is established I then get notified by wiring up a handler to its "Connected" event.
Once connected I then call other commands on the DLL.
In a simple test Winforms app, I have 1 button which instantiates the "DLL" and then calls the Connect() method. When the thread completes, the app sits idle for about 2 seconds, and then the "connected" event handler fires as expected. The event does not return anything.
But because the connect() is an expensive operation, and because my library is destined for a larger application, I created a ConnectAsync() method in my library and made use of the async and await keywords, and a AutoResetEvent. The ConnectAsync() method returns an instance of the "instantiated" DLL after it gets notified that the TCP connection is up from the event.
A bit of refactoring to the test WinForms app, and it works as expected.
Next step was to make an integration test using NUnit. However when the ConnectAsync() method is called from an async test, I can see the TCP connection establish on the remote application, but the event handler never fires. A day's worth of testing, searching and trial and error could not turn up why the ConnectAsync() works perfect off a simple Winforms button but not from a UnitTest.
Here is the test code
[Test()]
public async Task Test1()
{
var conn = await GetConnection();
//assert some commands on the conn
}
private async Task<TCPConnector> GetConnection()
{
return await Task.Run(() =>
{
var mre = new AutoResetEvent(false);
var ctrl = new TCPConnector();
ctrl.serverName = server;
ctrl.serverPort = serverPort;
ctrl.onConnected += () => { mre.Set(); };
ctrl.Connect();
mre.WaitOne();
return ctrl;
});
}
I know this is not strictly a question, but I'm stumped and looking for ideas to try. Or pointers as to what is different between a button click event and a NUnit test execution.
In case it means something to somebody, the dll I'm calling is an unmanaged ActveX
Update1:
If use MSTest it works! So it has something to do with NUnit's startup environment.
Update2:
Through investigations in this SO post, I by chance replicated the same behaviour without any unit testing frameworks, but instead via reg free COM. So I'm now thinking it is something to do with how the COM is activated and consumed ?
Resolution
Finally found the answer.
Credit to Chris for his answer on this question. All I had to do was add a <comInterfaceExternalProxyStub /> section to the manifest as outlined, and bingo
UPDATE 4
Ignore the last updates and the resolution. They contain misdirection and false positives, and some lack of understanding of my behalf as I worked through the whole world of COM, Regfree COM, Interop, and COM Events. The problem is still unresolved.
The key issue remains that when the COM is run under the context of a unit test the COM events do not fire. When run in a plain .exe they work just fine
My guess, without knowing what exactly the unmanaged DLL is doing, is that it is an single threaded apartment (STA) COM dll. In this threading model, COM interop will marshall all calls to the DLL to the thread that creates the object (which in your unit test is blocked waiting on the auto reset event, thus nothing happens).
The event pattern works in the Winforms app because the main UI thread is an STA thread (check the attribute on your main method) and it is pumping messages, so callbacks are allowed and locks are superseded by COM message pumping.
If this is the case, the only way to test the wrapper would be to create an STA thread, run a message pump on it, then pass a message to the thread to trigger the creation of the COM object and the connection (in other words, it's a huge pain). What's worse is that the object will behave this way in a client application as well, so unless you create an STA thread in your wrapper and marshall all calls to it, you will not be able to use it asynchronously.
As Chris mentioned, it's because specific of working with COM Interop objects in STA threads. It happens because interop objects created in STA thread could be accessed (also event call) only from that thread.
All you need is to wrap the creation of any COM Interop in a separate thread.
Something like that that:
private async Task<TCPConnector> GetConnection()
{
return await Task.Run(() =>
{
var mre = new AutoResetEvent(false);
Create(mre);
mre.WaitOne();
return ctrl;
});
}
private TCPConnector ctrl;
private void Create(AutoResetEvent mre)
{
ThreadPool.QueueUserWorkItem(o =>
{
ctrl = new TCPConnector();
ctrl.serverName = server;
ctrl.serverPort = serverPort;
ctrl.onConnected += () => { mre.Set(); };
ctrl.Connect();
});
}
Related
I'm new to background work (and generally in Task usage) and have a doubts about my implementation.
(Note: If you think it's too long, let me know by comment and I'll shorten it)
Assume a WCF service which returns currencys rates:
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Single)]
public class RatesServiceSvc : IGetRatesService
The RatesServiceSvc depends on IRatesService(singelton).
IRatesService depens on IRatesQueueDispatcher.
holds ratesCache dictionary. and in its constructor calls to RunDispatcher(_ratesQueue, _dispatcherCancellationTokenSource);
The internal implementation of the IRatesService is like this: The service instantiate a third party queue which gets from the network the current rates and pushes them as events to the queue (endlessly). In order to fetch the events I need to invoke the IRatesQueueDispatcher.Run(...) that runs backgroun loop:
The IRatesService implementation:
private void RunDispatcher(Queue queue, CancellationTokenSource dispatcherCancellationTokenSource)
{
Task<TaskCompletionCause> dispatcher = Task.Run(() => _queueDispatcher.Run(queue, dispatcherCancellationTokenSource.Token));
dispatcher.ContinueWith((dispatcherTask) =>
{
HandleRunningTaskTermination(dispatcherTask.Result);
});
}
IRatesQueueDispatcher.Run() Imlementation:
while (!cancellationToken.IsCancellationRequested && IsRatesQueueOk(eventsCount))
{
eventsCount = ratesQueueToDispatch.Dispatch();
if (eventsCount < 0)
{
Thread.Sleep(_sleepTimeWhenReutersQueueEmpty);
}
}
The queue.Dispach() call, leads to invoke (in the same thread) to the implementation of EventClient.ProcessEvent(event) (which registered in the initialization phase). The data fetched from the events inserted to the rateCache (in this case it's a ConcurrentDictionary)
The application needs:
The background loop will run endlessly.
If background loop fails for some reason I need to know it immediately.
If application has another issue I need to kill the background task.
The question:
Do my solution of running the backgroun work by Task.Run(...).ContinueWith(...) is Ok? I read in some palces about "Fire and Forget" Dangers (here
and here) also I know .NET 4.5.2 suggests the HostingEnvironment.QueueBackgroundWorkItem
but I'm not sure if it's the appropriate solution for me. Because:
I need to know if the worker failed from its internal reason.
It seems to me that the main purpose of the HostingEnvironment.QueueBackgroundWorkItem is to promise the finish of the running task before application_end. For my needs There isn't meaning of running the background work when application ends, and also vice versa - If background failed there is no meaning of the application to run without it. For that reason I implemented the HandleRunningTaskTermination() to recycle the application by invoke System.Web.HttpRuntime.UnloadAppDomain();.
After all, I'm worried about my implemetation and I'm looking for a better solution. There is better??
So I've achieved localhost WCF Named Pipes communication between client EXE and server EXE. I can call class methods on the server over localhost. So, it's like an IPC/RPC. However, if the server's class method takes a long time to execute, then it's best for me to throw that into a thread so that the server class method finishes and runs this thread in the background. Okay, fine, but then when the thread is finished its long task, I want to alert the client without having to use a timer on the client that would check that class method. A timer hitting a class method is a lot more inefficient than a raised event. It's like I need to raise an event on the client from the server. Is there an easy way to do this or to at least simulate it, without a lot of confusing work?
This is an answer formulated from my comment to the OP's question
You could make your WCF methods asynchonous then it's a simple matter of async/await or do away with WCF completely and use built-in async with NamedPipeClientStream (which is still await compatible). Not to mention a speed boost in the latter when doing away with verbose XML SOAP encoding
OP:
#MickyD You were right on the async/await thing now that I have studied that and implemented a test that works. That allows me to almost simulate a callback on a long running task and with minimal lines of code
e.g. to build upon the OP's answer but to use async/await correctly:
Client code
private async void button1_Click(object sender, EventArgs e) // <-- note async
{
label1.Text = await client.GetDataAsync(textBox1.Text); // <-- note await. New method
}
Now you could be tempted to use Task.Run but doing so is bad because:
Task.Run is best suited for compute-bound operations which we aren't.
Task.Run will at the most use an expensive thread-pool thread
We're performing an I/O operation and as such can benefit from I/O Completion Ports and "there is no thread" philosphy of IOCP present in Task I/O bound operations. As such when we make the server call via GetDataAsync, we don't waste a thread waiting for a result.
WCF Server
Here we simulate a lengthy operation by waiting, but instead of using Sleep which isn't Task-aware, we use Task.Delay which is an awaitable operation.
Task<string> async GetDataAsync (string text)
{
await Task.Delay (Timespan.FromSeconds(5));
return text + " processed";
}
So, let's say you have a button click in your UI that does a WCF synchronous method call on the WCF service, and that synchronous method takes a long time to run. Obviously, you don't want to block the UI from updating while that long running task executes. Naturally, you might be thinking about a callback. As in, you make the call to the server, and the class method on the server spawns a thread and runs that task, and when it's done, it returns back to the client a result via a callback.
To set that all up on WCF involves many complex, confusing, poorly documented steps, actually. But there's a much easier way, and it doesn't involve WCF code at all, and doesn't involve you changing anything on the WCF service, nor editing any WCF configurations. The trick is introduced in .NET 4.5 and greater. It's called async and await. Here is an example of a button click that calls a WCF service method that takes a long time to run and then returns the result when it's finished, and yet the GUI doesn't lock up and can handle other events.
1. First, to simulate a slow task, edit your WCF service project's shared class method and add this line in before the return result so that you can simulate a 5 second pause:
Thread.Sleep(5000); // requires using System.Threading;
In my case, I put that in my GetData() method.
2. Now switch to your WCF client project. You may have a button click handler that looks like this, as an example:
private void button1_Click(object sender, EventArgs e)
{
string returnString = client.GetData(textBox1.Text));
label1.Text = returnString;
}
So, switch that with three minor changes:
a. Add using System.Threading.Tasks;.
b. Change private void... to private async void... on your button click handler.
c. Utilize await Task.Run(...) with your slow method call.
Thus, the code would look like so:
private async void button1_Click(object sender, EventArgs e)
{
// Task.Run() requires "using System.Threading.Tasks;"
string returnString = await Task.Run(() => client.GetData(textBox1.Text));
label1.Text = returnString;
}
The end result is that when you click the button in the WCF client project, the GetData() class method is called on the WCF service project in a background thread, and, when finished, it comes back to that await statement and returns the result to the variable assignment. In my case, I clicked the button and nothing happened for 5 seconds -- the label with the result string didn't change. However, the GUI wasn't locked up -- I could drag the window around, type in other fields, click other form buttons, and so on. So, it's almost like a callback event handler, but not exactly. Still, it serves the same functionality and can be used in place of a callback event handler in most cases. And it involves far less code.
I'm trying to write a console application (C# .NET) that makes use of un-managed code in a 3rd party DLL.
The external assembly makes extensive use of callbacks. The sample application I have uses Windows Forms.
The sample code (Windows Forms) makes use of ThreadPool.QueueUserWorkItem
ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectToControlPanel));
It would seem that with windows forms there is a message pump that handles the callbacks. This is not the case with a console app so I need to construct my own.
I've tried adding a reset event
private static ManualResetEvent resetEvent = new ManualResetEvent(false);
static void main()
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ConnectToControlPanel));
resetEvent.WaitOne();
}
private void ConnectToControlPanel()
{
//Call external function from unmanaged DLL
resetEvent.Set();
}
That doesn't work.
My problem seems to be very much like this one but there is no real solution other than using Win.Forms and calling Application.DoEvents()
Edit
I modified my code thus:
Task task = Task.Factory.StartNew(() => ConnectToControlPanel());
while (task.Status != TaskStatus.RanToCompletion)
{
Application.DoEvents();
Thread.Sleep(500);
}
This works, the callbacks get called on progress and the result is successful rather than a timeout.
It doesn't feel right though to have to run that ugly loop every time I make an external call.
I've also tried spinning up another thread that constantly calls Application.DoEvents() but that didn't work, so I'm assuming it's got something to do with running in the same thread that made the call.
In my WPF application, I have to communicate to a datastor over the serial port. I want to separate this communication into a class library for simplicity.
In my DLL, I will be issuing a command to the datastor and wait for 10 seconds to receive the response back. Once I get the response from the datastor, I compile the data to meaningful info and pass to the main application.
My question is how to make the main application to pause for a while to get the data from the external dll and then continue the processing with the data from the dll?
I use .net 4.0
Consider calling the DLL method in a new thread
Thread dllExecthread = new Thread(dllMethodToExecute);
and providing a callback from the main program to the dll which can be executed when complete (This prevents locking on the GUI).
edit: Or for simplicities sake if you just want the main program to wait for the DLL to finish execution subsequently call:
dllExecthread.Join();
Maybe you could go with TPL:
//this will call your method in background
var task = Task.Factory.StartNew(() => yourDll.YourMethodThatDoesCommunication());
//setup delegate to invoke when the background task completes
task.ContinueWith(t =>
{
//this will execute when the background task has completed
if (t.IsFaulted)
{
//somehow handle exception in t.Exception
return;
}
var result = t.Result;
//process result
});
Don't ever pause your main thread because it blocks the GUI. Instead you need to act on an event that the background communication fires. You could use the BackgroundWorker class - simply provide the result in RunWorkerCompleted.
I am using API that originally was written with native code and wrapped with .net interops. The API is work asynchronic way when each operation raises event when it finished.
All my logic is synchronic so I want to synchronizing the operations. I doing it with EventWaitHandle. here the code
Stock stock;
private System.Threading.EventWaitHandle _signal = null;
public void Sync()
{
_signal = new System.Threading.EventWaitHandle(false,
System.Threading.EventResetMode.AutoReset);
MBTradingProvider.Instance.FinnishGetStoch += new
EventHandler(Instance_FinnishGetStoch);
MBTradingProvider.Instance.GetStockAsync("IBM");
_signal.WaitOne();
}
void Instance_FinnishGetStoch(object sender, EventArgs e)
{
stock = MBTradingProvider.Instance.CurrentWorkongStock;
if (_signal != null)
_signal.Set();
}
This code stuck in the _signal.WaitOne() line, the current thread is freezes and nothing to be happened.
I worked the same pattern on some other async operation and I work fine. The only difference that I can think about is that under the hood works com objects, as I said the effect that I get is that the code not responding after the WaitOne line
Anyone have an idea what can be wrong?
One issue with this code is the assignment of the _signal variable. This variable is atomically set but it is not necessarily visible between all threads involved. You need to use a method like Interlocked.Exchange to ensure the set is visible at the same time in all threads.
System.Threading.EventWaitHandle temp = new System.Threading.EventWaitHandle(false,
System.Threading.EventResetMode.AutoReset);
Interolocked.Exchange(ref _signal, temp);
Also, why are you not using an AutoReset event directly?
Your code seems to be fine to me.
I am assuming the following:
Sync() is executed in ThreadA
Calling GetStockAsync() will create ThreadB, which will perform some task to get stock info
Upon completing to get the stock info, ThreadB, not ThreadA, will execute the event handler, Instance_FinnishGetStoch(),
My rough guess is that the assumption#3 may not be true for your async framework.
You may want to try your code asynchronously and check which thread executes GetStockAsyc() and which thread executes Instance_FinishGetStock() event handler.
If only one thread does both GetStockAsync() and Instance_FinishGetStock(), your code above will be stuck on _signal.WaitOne().
For example, in a winform, if Form.BeginInoke(MyDelegate) is called in the UI thread, MyDelegate will be executed in the same UI thread, yet still asynchronously.