CSLA .NET

Vibrant discussion about CSLA .NET and using the framework to build great business applications.

Forum has moved

New location: CSLA .NET forum


CSLA .NET Resources:
  • CSLA .NET forum
  • CSLA .NET home page
  • WinForms - ApplicationContext.User principal being lost

    rated by 0 users
    Answered (Verified) This post has 1 verified answer | 9 Replies | 1 Follower

    Top 500 Contributor
    23 Posts
    andrew123 posted on Mon, Nov 18 2013 3:06 AM

    I've recently taken on a legacy project which involves using CSLA with WinForms as a thick client (i.e. CSLA Client and Server within same application).

    It's currently running CSLA 4.0.1 - I have tried upgrading to 4.3.14, but my issue is still not resolved (I can't upgrade to 4.5.x yet as I will need to convert about 500 overrides of Save to SaveAsync!)

    The issue is regarding the custom Principal which is being lost.  This is using custom authentication.

    During login, the custom principal is set using ApplicationContext.User.  The custom principal derives from Csla.Security.CslaPrincipal.  The identity on the custom principal derives from ReadOnlyBase<T>.

    Whilst everything "works", I have noticed that at times that the ApplicationContext.User has reverted to a GenericPrincipal object.  This is on the same thread that the login took place (in this case the UI thread).  I cannot find any places where we are setting the Thread.CurrentPrincipal or ApplicationContext.User directly (except post-login).

    The previous developers seem to have been aware of this because they have "solved" the issue with this piece of code.  But of course if you want to get the Principal without running a data operation you cannot trust it to be set.

    Csla.DataPortal.DataPortalInitInvoke += DataPortal_DataPortalInitInvoke;

    void DataPortal_DataPortalInitInvoke(object obj)

    {

       if (!ReferenceEquals(Csla.ApplicationContext.User, s_CurrentPrincipal))

          Csla.ApplicationContext.User = s_CurrentPrincipal;

    }

    Where s_CurrentPrincipal is a static field which I can confirm DOES keep the current principal.  I have put a trace on this and found that this handler does not set the principal to the GenericPrincipal so I don't believe this is the problem (this is the "solution"!)

    The app.config I have ensure has the following:

       <add key="CslaAuthentication" value="Custom" />

     

    But the Principal is still being lost.  

    Is there anything I am missing?  Would there be any reason that the Thread.Principal is being lost after it has been set?  This is pure WinForms, so HttpContext should not be involved.

    Answered (Verified) Verified Answer

    Top 500 Contributor
    23 Posts
    Verified by andrew123

    This turned out to be an issue with where the initial principal was being set.  The application was loading a Login Form from the Shown event of the main form.  This Login Form then set the principal upon successfully logging in.  

    However, I discovered that once the Shown event had completed, it was at this point that the principal was reverting back to the Generic Principal. 

    Moving everything to the Load event , rather than the Shown, fixed my issue.  

    I don't know why this was (they are DevEx Forms too if it is specific to this) though!

    All Replies

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Mon, Nov 18 2013 10:01 AM

    Hi, 

    Is Csla.Xaml.dll or Csla.Web.dll present in your applications bin folder?  If so - make sure to remove these assemblies as they contain other specialized application contexts.

    Csla.ApplicationContext.User should give this implementation in WindowsForms: 

          public void SetUser(IPrincipal principal)
          {
            Thread.CurrentPrincipal = principal;
          }
    And presumably - this should set the CurrentPrincipal on the UI thread of the Windows Forms application. 

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    23 Posts

    Hello

    No, I just have the Csla.dll assembly in my output folder.

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Mon, Nov 18 2013 10:45 AM

    Another reason for losing the principal is that your code uses the builtin BackgroundWorker or otherwise starts new threads.

    There is a separate Csla.Threading.BackgroundWorker in CSLA that makes sure to move the "CurrentPrincipal" to a new thread.

    So - to investigate this further:

    1. Make sure that the Csla.ApplicationContext.User is set on the UI Thread.

    2. Make sure to use the Csla.Threading.BackgroundWorker (if you use BackgroundWorker) to get the User transferred to background thread.

    Does your code uses Task or Task Parallell Library?

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 10 Contributor
    2,279 Posts
    JonnyBee replied on Mon, Nov 18 2013 10:46 AM

    And if it still fails - are you able to provide us a sample that recreates this behavior?

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    23 Posts

    Hi - thanks for your help.

    Yes, the principal is being set on the UI thread by setting the ApplicationContext.User.  I can confirm that directly after setting this, the Thread.CurrentPrincipal is set with the correct Principal.

    No, there are no BackgroundWorkers being used.  However, the first place that I can reproduce the lost principal is the firing of a Windows.Forms.Timer - is there a similar pattern that needs to be followed by these?

    Yes, I have begun to use the Task Parallel Library (as opposed to the Background Worker - i.e. using the TaskScheduler.FromCurrentSynchronizationContext) but these are new and I believe the issue was still there before this.

    I can have a go at isolating out the behaviour, but it may take me a little while....

    Thanks again.

    Top 10 Contributor
    2,279 Posts
    Answered (Not Verified) JonnyBee replied on Mon, Nov 18 2013 12:35 PM
    Suggested by JonnyBee

    That makes more sense though. It means that the Windows.Forms.Timer executes it's action on a new thread that has the default GenericIdentity. 

    And even though you can check that the principal is set on the "current thread" is doesn't necessarily mean that the current thread is the UI thread!! 

    Read this article:

    http://msdn.microsoft.com/en-us/library/system.appdomain.setthreadprincipal(v=vs.110).aspx

    And this question on StackOverflow:

    http://stackoverflow.com/questions/4592692/set-currentprincipal-in-winforms-for-all-threads

    There is also a new Csla.Threading.CslaTaskScheduler that you can use with TaskFactory that ensures the user and application context is transferred to the background thread.

     

     

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    23 Posts

    Hmmm. I though that once you set the Thread.CurrentPrincipal, all subsequent threads took on that principal?  I may need to read up some more :)

    The Timer executes its fired event on the UI thread - I can see the Thread.CurrentThread.ManagedThreadId is the same, so its not clear why that thread does not have the correct Principal.

    I will try using the AppDomain.SetThreadPrincipal at the point of login and see if it fixes my issue - but I think you can only call this once per app domain so it doesn't allow me to switch to a different user in the same process (unless I get into AppDomains).

    Top 10 Contributor
    2,279 Posts

    andrew123:

    Hmmm. I though that once you set the Thread.CurrentPrincipal, all subsequent threads took on that principal?  I may need to read up some more :)

    That is certainly not true. You only set the principal on the current thread (or the threads ExecutionContext?). 

    About login - remember also that you may have a number of threads running already under a certain users context.You can use reflection to change the default principal for new threads - but there is no guaranteed way of changing the CurrentPrincipal on ALL RUNNING threads.

     

     

    Jonny Bekkum, Norway CslaContrib Coordinator

    Top 500 Contributor
    23 Posts
    Verified by andrew123

    This turned out to be an issue with where the initial principal was being set.  The application was loading a Login Form from the Shown event of the main form.  This Login Form then set the principal upon successfully logging in.  

    However, I discovered that once the Shown event had completed, it was at this point that the principal was reverting back to the Generic Principal. 

    Moving everything to the Load event , rather than the Shown, fixed my issue.  

    I don't know why this was (they are DevEx Forms too if it is specific to this) though!

    Page 1 of 1 (10 items) | RSS

    Copyright (c) 2006-2014 Marimer LLC. All rights reserved.
    Email admin@lhotka.net for support.
    Powered by Community Server (Non-Commercial Edition), by Telligent Systems