Task doesn't run in GUI, but OK in console - asynchronous

I am using a third-party library. That library contains an object with an async method that returns Task<SomeStuff>. I am wrapping that object and others into my own class. My wrapper method is also async and has the same return. Calling the wrapper method works fine in my unit tests and a console app. However, it doesn't work in my WPF GUI app. I have tried different methods for invoking in my GUI but nothing works.
In my unit tests, I invoke with GetAwaiter().GetResult(). However, in my GUI this never returns.
I tried using Start() but that results in an error: "Start may not be called on a promise-style task."
What do I need to do to make this work in my GUI?
// Foo() returns Task<SomeStuff>
// this works fine in unit test as well as console app, but not in GUI (WPF)
SomeStuff stuff = myWrapper.Foo().GetAwaiter().GetResult();
// this results in error: "Start may not be called on a promise-style task."
Task<SomeStuff> myTask = myWrapper.Foo();
myTask.Start();
myTask.Wait();

There is a very good discussion of various approaches to my issue here: [https://stackoverflow.com/questions/5095183/how-would-i-run-an-async-taskt-method-synchronously?rq=1][1]
For the moment I resolved my issue as below. I shall re-read the post from the link and perhaps refine my approach.
Task<SomeStuff> task = Task.Run(() => myWrapper.Foo());
task.Wait();
SomeStuff stuff = task.Result;

Related

Can Xamarin UITest backdoors return a value on iOS?

I'm writing automated tests for a Xamarin Forms mobile app. Since it's difficult to directly interact with an embedded Google/Apple map, I wrote a few backdoor methods designed to get all the information the map would provide to a human. However, on iOS, the method I wrote doesn't provide a return value, despite my instructions to the contrary.
So far, I've done all manner of things, including reducing the method to nothing but a stub returning a dummy string. It still refuses to do it. Nowhere in Microsoft's documentation indicates that a value can't be returned on iOS.
[Export("GetUnits:")]
public NSString GetUnits(NSString val) // param unused
{
return new NSString("TEST"); // returns this value in the app, but it doesn't ever make it to the test harness
}
The above code should return "TEST" to the test harness, which would then be printed in my REPL after I call app.Invoke("GetUnits:", ""), which always produces
[
]
instead of
[
"TEST"
]
The method is named properly and called properly; error messages occur if I don't call it properly (e.g. wrong number of parameters, wrong method name) and test code inserted into the method executes fine, so I know it's executing. It's just not returning the value to the test harness. The equivalent Android version of this method works perfectly.
I found one person on the Xamarin forums with the same problem, but his topic hasn't been touched in two years. I've read every pertinent thing I can find on the web, all to no avail.
Edited for formatting. (Whoops.)
Here's what we're using in our own integration tests to make sure we don't break this functionality:
This line is how we're calling the backdoor:
_app.Invoke("backdoorWithString:", stringArg).ToString().ShouldEqual(stringArg);
And in the app, the backdoor we're referencing is defined in a native app, so it's hard to compare:
- (NSString *) backdoorWithString:(NSString *) value {
I would advise changing your Export to the correct casing:
[Export("getUnits:")]
Also please check that this method is in your AppDelegate.cs file.

Awaited async Task loses HttpContext.Current

I have a very bizarre situation regarding a Web Application that makes an asynchronous Http Post...
We have two branches in TFS. I merged code from one branch to another and then find that some Integration Tests in the new branch fail due to a System.NullReferenceException. I spend time ensuring that our code in both branches is identical, and all the referenced DLLs are identical too. Everything seems identical.
So, I decide to debug the test.
What our test does is to create a Mock IHttpClient object. We stub the Mock object in such a way that the clientMock.PostAsyncWithResponseMessage(x,y) returns a new HttpResponseMessage() object (on which we've set various properties).
So, the code looks like this:
using (var response = await client.PostAsyncWithResponseMessage(url, postData).ConfigureAwait(true))
{
if (response.IsSuccessStatusCode)
{
ret.Response = await response.Content.ReadAsStringAsync().ConfigureAwait(true);
ret.ContentType = response.Content.Headers.ContentType.ToString();
}
ret.StatusCode = response.StatusCode.ToInt();
}
Taking this a line at a time:
await client.PostAsyncWithResponseMessage(url, postData).ConfigureAwait(true))
This looks like it's an async method, but "client" is our Mock object so all it is doing is supporting the IHttpClient interface. If you inspect the Thread, the ID does not change when executing this line.
Later on, we have:
await response.Content.ReadAsStringAsync().ConfigureAwait(true);
Now, when this line executes, the HttpContext.Current is set to null - all our context is trashed. In this application, we do not call ConfigureAwait(false) anywhere, so as far as I'm aware there's no reason why we should lose the context.
If I change that line to:
response.Content.ReadAsStringAsync().Result;
Then this is of course blocking and we don't lose the context.
So two questions:
Why would the await method().ConfigureAwait(true) lose the context? [More marks will of course be awarded if one can also suggest why identical code from one TFS branch fails whilst working in a different branch, but I'm not expecting that]
I can see the obvious benefits of awaiting the .PostAsyncWithResponseMessage(url, postData) method since our thread would otherwise be blocked as the other server processed our request. However, having retrieved the data, what advantage is there in awaiting the ReadAsStringAsync()....in other words, is there a good reason not to use the .Result syntax?
thanks
If you inspect the Thread, the ID does not change when executing this line.
This does not necessarily mean that it ran synchronously. Most unit test frameworks provide a free-threaded context (SynchronizationContext.Current is null) and run their tests on a thread pool thread. It is entirely possible for the code to just happen to resume on the same thread (especially if you were only running one test).
Now, when this line executes, the HttpContext.Current is set to null - all our context is trashed. In this application, we do not call ConfigureAwait(false) anywhere, so as far as I'm aware there's no reason why we should lose the context.
I assume SynchronizationContext.Current is set to null, so there isn't actually a context. What's probably happening is that the test is setting HttpContext.Current (on some random thread pool thread), and after the first truly asynchronous operation, sometimes the test resumes on a thread where Current is set and sometimes it doesn't.
On ASP.NET, there's a request context (SynchronizationContext) that handles the propagation of HttpContext.Current. If you don't have something similar in your unit tests, then there's no context to preserve HttpContext.Current.
If you are looking for a quick fix, then you can probably use my AsyncContext type. This will provide a single-threaded context so that all your asynchronous code will resume on the same thread - not the same semantics as ASP.NET's context, but similar enough to be useful for some tests:
void TestMethod()
{
AsyncContext.Run(async () =>
{
// Test method body goes here.
});
}
On a side note, ConfigureAwait(true) is just noise; true is the default behavior.
is there a good reason not to use the .Result syntax?
It's not clear from your code that the server's response is actually read by the time PostAsyncWithResponseMessage completes. Based on the descriptions of your problem (and the fact that Result fixes it in your tests), it sounds like ReadAsStringAsync is in fact acting asynchronously.
If this is the case, then there are two good reasons not to block: 1) You're blocking a thread unnecessarily, and 2) You're opening yourself up to deadlock.

Using singleton WCSession delegate instead of instance methods

I'm experiencing a strange issue with WatchOS (but I suppose that this problem is similar with iOS and OSX).
I'm using a singleton to handle a WCSession delegate (The full code is by NatashaTheRobot, I paste here only a portion of her code, the full code is here ).
This class has a startSession function where the singleton is associated as delegate of the session:
func startSession() {
session?.delegate = self
session?.activateSession()
}
and all the delegate functions are defined inside the same class, like session:didReceiveMessage:replyHandler:
I'd like to be able to have the delegate called every time that the Watch app receives a message independently by the current InterfaceController.
I thought that a good place to achieve this goal might be the ExtensionDelegate class:
class ExtensionDelegate: NSObject, WKExtensionDelegate {
let session = WatchSessionManager.sharedManager // THE SINGLETON INSTANCE
func applicationDidFinishLaunching() {
session.startSession()
}
it seems that this code is not working and the delegate function are never called.
Then I decided to go for a less generic way and I started adding the reference to the singleton instance inside all the InterfaceController... but again it doesn't work and delegate methods are never been called.
Then, in my last attempt, I've implemented the session delegate protocol directly inside the InterfaceController code. In that case I receive the messages from the iOS app... it was working correctly (obviously only when the watch app is presenting that specific InterfaceController).
My question are: why implementing a generic singleton object doesn't work? Why I have to implement the delegate directly on the InterfaceController to make it work?
Try moving the startSession call from the ExtensionController's applicationDidFinishLaunching to its init method. The init gets called no matter which context (complication, app, glance, notification, etc) the extension is being loaded for.

UIImpersonator.addChild() doesn't dispatch the right events

I am running FlexUnit tests through Ant. The test test1 fails with the message "Timeout Occurred before expected event" but test2 passes. The only difference between the two tests is that one uses UIImpersonator.addChild() whereas the other uses FlexGlobals.topLevelApplication.addElement().
test1 fails even if I listen for "addedToStage" event. Listening for "added" event, however, makes test1 pass.
[Test(async, ui, description="Fails")]
public function test1():void
{
var c:UIComponent = new UIComponent;
Async.proceedOnEvent(this, c, FlexEvent.CREATION_COMPLETE);
UIImpersonator.addChild(c);
}
[Test(async, ui, description="Passes")]
public function test2():void
{
var c:UIComponent = new UIComponent;
Async.proceedOnEvent(this, c, FlexEvent.CREATION_COMPLETE);
FlexGlobals.topLevelApplication.addElement(c);
}
when adding a child, it will not initiate the flex component lifecycle, because displayobject is flash core element, not flex.
assuming Flex4/spark. addChild adds a MovieClip, not a Flex UIElement, it doesn't even know FlexEvent type as it is a flash.core object. It will only throw addedToStage or added events (Event.added), but in unit test, it is not added to stage, because UIImpersonator is not part of the stage
I ran into this same issue today using the new Apache FlexUnit 4.2.0 release.
When trying to run the sampleCIProject included in the binary distribution, none of the tests that used Async would succeed. The exception was exactly as described above.
After looking at the source code for a while, I noticed that the core FlexUnit libraries have two flavours: flexunit-4.2.0-20140410-as3_4.12.0.swc and flexunit-4.2.0-20140410-flex_4.12.0.swc.
The first of these is intended for pure AS3 projects, while the latter is intended for projects that use Flex. The sampleCIProject included both of these libraries in the library path, and I'm assuming that it was using the UIImpersonator class from the pure AS3 library rather than the Flex-supporting one. I removed flexunit-4.2.0-20140410-as3_4.12.0.swc from the project, and lo and behold, the Async tests started working again.
Probably a bit late for you, but I hope this helps someone else.

Access python function from javascript in QWebView

I am writing a Python/PyQt4 application that generates and displays a page in a QWebView widget. The page includes javascript code that I would like to be able to call functions returning data from the python application.
So far I can call functions that do not return data (using the pyqtSlot decorator), and call functions that do take parameters by exposing them as properties (using the pyqtProperty decorator). What I haven't worked out how to do is to call a python function with parameters, that returns data.
The question 9615194 explains how to do this from C++, but I cannot see how to transfer this to PyQt4.
I suspect you're not using the result= keyword to specify the return value in your pyqtSlot decorator?
#pyqtSlot(str, result=str)
def echo(self, phrase):
return self.parent().echo(phrase)
I ran afoul of this myself recently. No errors are generated if you omit result=, the method just silently returns nothing. Pretty maddening 'til I figured it out. See my answer to this question for a worked example.

Resources