MarimerLLC / cslaforum

Discussion forum for CSLA .NET
https://cslanet.com
Other
31 stars 6 forks source link

No custom ApplicationContextManager for Csla-XamarinForms? #636

Open ajj7060 opened 5 years ago

ajj7060 commented 5 years ago

Question Is there a reason there's no custom ApplicationContextManagerwhen you install Csla-XamarinForms package into a UWP, Android, or iOS XF app?

I was surprised to find a bug in my app when using async/await via the Xamarin.Forms.Device.StartTimer callback, where the problem was that Csla.ApplicationContext.User was null.

I created a custom one that just stores the principal in a static field and that seems to work, but I haven't had a chance to really dig in and investigate if that's the right solution.

Version and Platform CSLA version: 4.7.200 OS: Windows, iOS, Android Platform: Xamarin Forms

rockfordlhotka commented 5 years ago

This issue is the reason: https://github.com/MarimerLLC/csla/issues/729

For .NET Standard (so basically all platforms now) this change allows standardization of behavior for managing context on a per-thread basis. Importantly, CSLA now conforms to the .NET standard approach.

I am still doing different things for WinForms/WPF and for legacy ASP.NET. But it looks like, going forward, I'll be able to follow this new standard approach provided by Microsoft.

ajj7060 commented 5 years ago

I think I'm not understanding something. It sounds like switching to AsyncLocal<T> (which was done in 4.7.100), when a new thread is created the creating thread's context will move to the new thread (via AsyncLocal<T>). But that's not what is happening; the UI thread has the correct User value, but it does not seem to be flowing to the thread the timer fires on (or any threads it creates).

What am I missing?

rockfordlhotka commented 5 years ago

It is true that for the User property we rely on the thread's CurrentPrincipal value, and that never flows from one thread to another.

In ASP.NET we override that to use HttpContext. In WinForms/WPF we override that to use a static.

Perhaps it makes sense to override it to a static in Xamarin as well, for the same reasons as WinForms/WPF - this is client-side code where it is expected that the user's identity is consistent for the entire app across all threads.

Anyone see a problem with doing that?

ajj7060 commented 5 years ago

I don't personally, and that's what I ended up doing. It seems to work, but I wanted to make sure there was a good reason not to have it work this way in Xamarin too.

I do think that in a client application context it does makes sense for all threads to use the same principal. I imagine only one user is going to be interacting with the UI (unlike in a console, Windows Service, or Asp.net).

rockfordlhotka commented 5 years ago

Would you be so kind as to write this up as a feature request in the csla repo? Include a link to this thread?

ajj7060 commented 5 years ago

Done. I'll take a stab at it since I'm not busy right now.

brinawebb commented 5 years ago

Do you think your fix for this will also fix issue https://github.com/MarimerLLC/cslaforum/issues/111? We've run into a problem in our unit tests, random failures, and just yesterday narrowed it down to the ApplicationContext disappearing... We're using .NET Core and Csla 4.8

rockfordlhotka commented 5 years ago

111 has to do with WPF right? That already stores the User value in a static. What we're doing here brings Xamarin in line with Windows Forms and WPF.

The ClientContext/LocalContext/GlobalContext dictionaries are handled differently. And from 2015 to now the entire way those are handled is very different, because they are now managed by the underlying AsyncLocal infrastructure Microsoft now provides.

Update: One thing to consider @brinawebb, is that the application context provider is loaded based on the environment in which CSLA is running. The unit test environment is typically considered to be the same as a console window, so the context provider loaded is NOT the same as the one for WPF.

Your unit tests need to manually set the provider to the WPF provider to get WPF-style behavior.