question

CharlesMills-5302 avatar image
0 Votes"
CharlesMills-5302 asked ·

Can someone educate me a little on the status of Xamarin.UWP?

Level set: I am a very experienced developer but on my first Xamarin Forms app.

My app is working at an alpha level in Android. I have not yet jumped through all of the iOS hoops. I initially ignored UWP because it is semi-unsupported. I subsequently decided to see if I could not build it in UWP also and I have been 98% successful. The app builds and runs and the pages appear correctly.

I ran into one unexplained anomaly. Basically I have an instance of a user-defined class initialized statically. I do an await on SecureStorage.GetAsync() and when I come back from the await, my class instance -- not referenced by the GetAsync() -- has become null. I hacked around that with if (instance == null) instance = new MyClass(); Fortunately I was able to do that because there was no values in the instance that I "needed" at that point in the logic.

I am now hitting another unexplained anomaly. I have not fully investigated but I seem to have code again with await SecureStorage.GetAsync() that seems to fail normally but work if I step through it with the debugger -- which is pretty frustrating! (This is code that works without issue on Android.)

So ... can someone tell me if I am just looking for frustrations and banging my head against the wall trying to use Xamarin Forms UWP ... or if there is something specific different that I need to be aware of ... or ... ?

Thanks!

VS 2019 Community 16.9.4 on Windows Pro 64-bit. Nothing real special in the app. Using SecureStorage, System.Security.Cryptography and System.Linq. No Crypto calls yet at the point of the problems I describe above.

dotnet-xamarinformswindows-uwp
· 3
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

To be make sure you could get instance with GetAsync method, you need to call SetAsync before. it's better to detect the problem if you could provide the sample code above.

0 Votes 0 ·

@NicoZhu-MSFT not exactly certain what you mean but if you mean "am I trying to read data that I previously wrote with SetAsync(0 then yes, of course. (But even if not, I don't see how GetAsync() should make some unrelated variable magically go to null.)

I will attempt to post the code. This is my first post on this "new MSDN" and I am not certain how to edit my post.

0 Votes 0 ·

Also, @NicoZhu-MSFT I would appreciate help with the specific problem I posted, of course, but what I am really looking for is someone to say whether UWP is worth spending time on or whether I am just looking for ongoing headaches if I try to use UWP.

0 Votes 0 ·
CharlesMills-5302 avatar image
0 Votes"
CharlesMills-5302 answered ·

Here is the code. When I breakpoint on the GetAsync() CurrentSystem is an instance of Configuration as one would expect. After the GetAsync() completes it is null.

 public class Configuration
     {
         public const int SystemIndexUndefined = -1;
    
         public int SystemIndex = SystemIndexUndefined;
         /* etc. */
     };
    
     public static class State
     {
         public static Configuration CurrentSystem = new Configuration();
         /* snip */
         private static async Task<string> OurGetAsync(string key)
         {
             try
             {
                 return await SecureStorage.GetAsync(key);
             }
             catch (Exception ex)
             {
                  Logger.LogMsg($"Exception {ex} thrown by GetAsync({key})");
             }
             return null;
         }
    
         public static async void RestoreSystemIndex()
         {
             string s = await OurGetAsync("SystemIndex");
             if (s == null) CurrentSystem.SystemIndex = Configuration.SystemIndexUndefined;    // Not recorded
             else CurrentSystem.SystemIndex = Convert.ToInt32(s);
         }
         /* etc. */



· 2 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I have tested above code, unfortunately, we can't reproduce this problem, for your description, SecureStorage.GetAsync(key); was skipped. Actually, if you add await keyword before GetAsync method. it will wait the result. Please try to edit OurGetAsync like the following.



 private static async Task<string> OurGetAsync(string key)
 {
     var res = string.Empty;
     try
     {
         res =  await SecureStorage.GetAsync(key);
     }
     catch (Exception ex)
     {
    
     }
     return res;
 }


0 Votes 0 ·

I have an Await keyword before the GetAsync() -- take a look at the code I posted.

My question was and is not "can Microsoft reproduce some particular problem?" My question was "Is Xamarin Forms for UWP ready for production usage" and I am kind of hearing an answer of "no." Am I wrong?

By the way, I actually had already split the return Await GetAsync() into two statements so I could see exactly where the problem occurred. It occurs on the Await GetAsync(), not on the return.

I think the "improved" logic you suggest has the flaw that the return value can now be either null or Empty, as well as a valid string. It makes the caller's test for "not found" more complicated.

0 Votes 0 ·
CharlesMills-5302 avatar image
0 Votes"
CharlesMills-5302 answered ·

94122-before-await.jpg
94078-after-await.jpg



Here you go! In the first screen shot you can see the debugger stopped on the GetAsync() and in the Watch List CurrentSystem is populated. I hit F11, the debugger executes the Await GetAsync(), and you can see that CurrentSystem has gone to null.


before-await.jpg (90.4 KiB)
after-await.jpg (87.8 KiB)
· 1 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

You have not init CurrentSystem before, please refer your previous code that make a CurrentSystem instance when declared.


 public static class State
 {
     public static Configuration CurrentSystem = new Configuration();
     /* snip */
     private static async Task<string> OurGetAsync(string key)
     {
         var res = string.Empty;
         try
         {
             res =  await SecureStorage.GetAsync(key);
         }
         catch (Exception ex)
         {
    
         }
         return res;
     }
    
     public static async Task RestoreSystemIndex()
     {
         string s = await OurGetAsync("oauth_token");
         System.Diagnostics.Debug.WriteLine(s);
         if (s == null) CurrentSystem.SystemIndex = Configuration.SystemIndexUndefined;    // Not recorded
         else CurrentSystem.SystemIndex = Convert.ToInt32(s);
     }
 }



0 Votes 0 ·
CharlesMills-5302 avatar image
0 Votes"
CharlesMills-5302 answered ·

@NicoZhu-MSFT , does not public static Configuration CurrentSystem = new Configuration(); (line 3 above) constitute initializing CurrentSystem? That's a serious question? Is it wrong in some way?

Also please note my first screen shot that shows CurrentSystem pointing to an instance of Configuration.

· 4 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

You could initializing CurrentSystem with line 3 above, if you have init it previous, CurrentSystem will not be null, and you could also initializing CurrentSystem within RestoreSystemIndex like your screenshot, but it will get value after

94149-image.png

94150-image.png


0 Votes 0 ·
image.png (78.0 KiB)
image.png (66.2 KiB)

I am very sorry, @NicoZhu-MSFT, but I do not understand what you are saying. I apologize.

0 Votes 0 ·
NicoZhu-MSFT avatar image NicoZhu-MSFT CharlesMills-5302 ·

Sorry, guys, I have reload your thread again, your problem is CurrentSystem instance become null after await OurGetAsync() right?

0 Votes 0 ·
Show more comments
CharlesMills-5302 avatar image
0 Votes"
CharlesMills-5302 answered ·

I thought perhaps the problem was due to the way I constructed this Solution: build a mostly-working solution, and then shoe-horn a UDP project into it.

So I spent today starting over: I built a brand-new Xamarin.Forms Solution -- including a UDP project -- from scratch, and then added my existing source code to it.

Sad to say the CurrentSystem going to null problem still exists, or rather exists also in the new Solution, and the other problem that I cannot describe in a few sentences does also.

Mind you, this is all common code that works apparently flawlessly on Android. (Have not yet built for iOS.)

· 2 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I have only tested in xamarin UWP platform. unfortunately, we can't reproduce this problem, you could refer my screenshot above, CurrentSystem will not become null after async method. could you share blank sample that could repro this problem with us. I will tested base on that, and quickly detect the problem.

0 Votes 0 ·

I don't know what the magic is to reproduce it. I created a simple Flyout application and it does not reproduce the problem so far.

I added a Finalizer to the Configuration class and I can definitely see it getting called when the await GetAsync() is called.

I am seeing very odd things. There are two earlier calls in the app to methods in State that call OurGetAsync(). When I breakpoint on one of them and step through it with F11 I suddenly "jump" to someplace else in the code, not the next sequential instruction (nor the catch). Should await behave that way? Shouldn't I be able to use Debug Step Into even on an await? Something is making my code behave very, very strangely and I have no idea what it is.

0 Votes 0 ·
CharlesMills-5302 avatar image
1 Vote"
CharlesMills-5302 answered ·

I think I solved it.

Is not any async void method that sets global variables such as my RestoreSystemIndex() an invitation to trouble?

I can't explain exactly how it would lead to CurrentSystem becoming null but I made all of my async void methods instead async Task and all of the mysterious problems went away, including the CurrentSystem problem.

I had to move the call to RestoreSystemIndex() from the AppShell constructor to app.OnStart() because (apparently) constructors cannot make await calls.

I got going down this async void road because this is my first Xamarin project and it worked perfectly on Android.

· 1 ·
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

If you solve the problem, you could click "Accept Answer" to convenient people who visit this thread later.

0 Votes 0 ·