Async Execution - ThreadPools, BackgroundWorker??

Async Execution - ThreadPools, BackgroundWorker??

Old forum URL: forums.lhotka.net/forums/t/11988.aspx


NemisisJedi posted on Monday, May 20, 2013

Guys, hope eveyone is well, but need some advice.

I have a class, and that class has children.  Each child is going to connect to a database, calculate some values and return.  At the moment this run in sync, so i loop through each child, connect to database, get result and move on to the next one.

This works fine, but i think running the code in async mode would benefit performance.

I seen this on microsoft site http://msdn.microsoft.com/en-us/library/3dasc8as(v=vs.80).aspx describing how to use a ThreadPool to execute async tasks, and the code waits until all the tasks are finished.  This sounds exactly like what i want to do, but i understand the Prinical objects etc are not copied over into other threads? I am using asp.net 4.0.

I havent done much async processing, and none where i need to carry the current prinical object.

I have seen that Csla has a backgroundWorker which does pass on the prinicipal values etc.  Is there a limit on the number of BackgroundWorkers i can create?  How would i wait for all backgroundworkers to complete?

Sorry i this is basic, but thought i would ask here as maybe someone else has had this problem as well

JonnyBee replied on Monday, May 20, 2013

Hi,

I have created a CslaTaskFactory for internal usage (my company) that allows me to setup Tasks / chain Tasks and WaitAll. These tasks will automatically get the principal, UICulture, Culture, ApplicationContext.ClientContext and ApplicationContext.GlobalContext transferred to the background thread. 

This has to go into the CSLA assembly itself as the api to set the values is not publicly available. 

I will email Rocky to check if this may go into the Csla repository or you can send me a private message and I will share this class with you.

JonnyBee replied on Monday, May 20, 2013

Hi all, 

The CslaTaskFactory class will be added to Csla.Threading namespace.

NemisisJedi replied on Tuesday, May 21, 2013

Do you know when this will be added and when it will be released?

JonnyBee replied on Tuesday, May 21, 2013

Will be added to repository this week.

Not sure when next release is planned (or if we even have a date yet).

thaehn replied on Thursday, May 23, 2013

Caliburn has an action called a Coroutine.  You may be able to use this in the mean time:

http://caliburnmicro.codeplex.com/wikipage?title=IResult%20and%20Coroutines&referringTitle=Documentation

Todd

JonnyBee replied on Sunday, May 26, 2013

Changes is checked in and ready to be merged into CSLA Trunk. 

You can look at the changes here:
https://github.com/MarimerLLC/csla/pull/143  

and at the unit tests for usage sample. 

RockfordLhotka replied on Friday, May 31, 2013

I plan to do a beta release of this new code (along with support for Android with all 4.5 features) this weekend or early next week.

NemisisJedi replied on Tuesday, June 04, 2013

Can someone please send me the link to download the installer for the latest version as i havent got Visual Studio 2012, and really need this code please.

JonnyBee replied on Tuesday, June 04, 2013

Hi,

You can use NuGet in VS2010 too - just remember to check PreRelease in your search. 

NemisisJedi replied on Wednesday, June 05, 2013

Right i have downloaded NuGet in VS2010, got the Csla dll's etc that i need.  perfect.

But this code does not pass my userPrincipal.  Instead it has a generic principal populated, and a FormsIdentity in Csla.ApplicationContext.User.Identity, which is not right and causing me errors?

Is this code right to use Tasks?  I have never used them before

----------------------------------

Dim lReportId As Integer
Dim lTasks(lData.Count - 1) As System.Threading.Tasks.Task
Dim lTaskScheduler As New Csla.Threading.CslaTaskScheduler
Dim lTaskFactory As New System.Threading.Tasks.TaskFactory(lTaskScheduler)

lIndex = 0

' loop through and do work
While lIndex < lData.Count
    lReportId = lData.Keys(lIndex)

    ' add item to lDoneEvents
    lTasks(lIndex) = New System.Threading.Tasks.Task(Function(pReportId As Integer)
        Dim lReport As IBaseReport = Report.GetReportByID(pReportId)
        lData(pReportId) = lReport

        Return True
    End Function, lReportId)

    lTasks(lIndex).Start(lTaskScheduler)

    lIndex += 1

End While

System.Threading.Tasks.Task.WaitAll(lTasks, New TimeSpan(0, 0, 30).TotalMilliseconds)

NemisisJedi replied on Wednesday, June 05, 2013

Guys, i believe the code i wrote above is right.  I dont know what the problem is but it seems to be linked to vs 2010 / .NET 4.0?

I have managed to get a copy of VS 2012, and if i create a basic website with the code above, it works (using .NET 4.5 and .NET 4.0).  The prinicipal is passed to within the task.

If i create a basic website in vs 2010, same code,  the principal is not passed and you get a genericprinicipal/formsidentity in the task code.

Would love some more help with this please, maybe its a bug?  Or maybe i need to do something particular because i am using vs2010 / .net 4.0.

Any help would be much much much appreicated

 

Here is the test code i created and put on the default page

Public Class _Default

    Inherits System.Web.UI.Page

 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        Csla.ApplicationContext.User = Nothing

        Csla.ApplicationContext.User = New myPrincipal

 

        Dim lIndex As Integer = 0

        Dim lTasks(0) As System.Threading.Tasks.Task

        Dim lTaskScheduler As New Csla.Threading.CslaTaskScheduler

        Dim lTaskFactory As New System.Threading.Tasks.TaskFactory(lTaskScheduler)

 

        ' loop through and do work

        While lIndex < 1

            ' add item to lDoneEvents

            lTasks(lIndex) = New System.Threading.Tasks.Task(Function(pReportId As Integer)

                                                                 Dim a As String = pReportId.ToString

                                                                 Dim b As myPrincipal = TryCast(Csla.ApplicationContext.User, myPrincipal)

 

 

                                                                 Return True

                                                             End Function, 123)

            lTasks(lIndex).Start(lTaskScheduler)

            lIndex += 1

        End While

        System.Threading.Tasks.Task.WaitAll(lTasks, New TimeSpan(0, 0, 30).TotalMilliseconds)

        Csla.ApplicationContext.User = Nothing

    End Sub

End Class

Public Class myPrincipal

    Implements System.Security.Principal.IPrincipal

    Public ReadOnly Property Identity As System.Security.Principal.IIdentity Implements System.Security.Principal.IPrincipal.Identity

        Get

            Return New myIdentity

        End Get

    End Property

   Public Function IsInRole(role As String) As Boolean Implements System.Security.Principal.IPrincipal.IsInRole

        Return True

    End Function

End Class

Public Class myIdentity

    Implements System.Security.Principal.IIdentity

    Public ReadOnly Property AuthenticationType As String Implements System.Security.Principal.IIdentity.AuthenticationType

        Get

            Return "MINE"

        End Get

    End Property

    Public ReadOnly Property IsAuthenticated As Boolean Implements System.Security.Principal.IIdentity.IsAuthenticated

        Get

            Return True

        End Get

    End Property

    Public ReadOnly Property Name As String Implements System.Security.Principal.IIdentity.Name

        Get

            Return "MY NAME IS HERE"

        End Get

    End Property

End Class

JonnyBee replied on Wednesday, June 05, 2013

Hi,

In your VS2010 solution - do you have both Csla.Web.dll and Csla.Web.Mvc,dll in your bin.folder?

You must have Csla.Web.dll in your bin folder for ApplicationContext to use the Csla.Web.ApplcationContextManager that stores/retrieves the Principal object from HttpContext.Current.User 

When you move on to the background thread the HttpContext.Current will be null and Csla.ApplicationContext will revert to use the "default" Csla.ApplicationContext.ApplicationContextManager that stores/retrieves the Principal object from Thread.CurrentPrincipal 

I do not have VS2010 installed on my dev computer so unfortunately I am unable to dig more into it right now if it is a VS2010 issue.

NemisisJedi replied on Wednesday, June 05, 2013

JonnyBee

Hi,

In your VS2010 solution - do you have both Csla.Web.dll and Csla.Web.Mvc,dll in your bin.folder?

You must have Csla.Web.dll in your bin folder for ApplicationContext to use the Csla.Web.ApplcationContextManager that stores/retrieves the Principal object from HttpContext.Current.User 

When you move on to the background thread the HttpContext.Current will be null and Csla.ApplicationContext will revert to use the "default" Csla.ApplicationContext.ApplicationContextManager that stores/retrieves the Principal object from Thread.CurrentPrincipal 

I do not have VS2010 installed on my dev computer so unfortunately I am unable to dig more into it right now if it is a VS2010 issue.

In my VS2010 project I have Csla.dll and Csla.Web.dll referenced in my web project.  I do not have Csla.Web.Mvc.dll referenced.

I have just added a new web application using VS2012, and added Csla.dll only.  This works.

I have then added a new web application using VS 2010 and added Csla.dll only, and this seems to work.

So....i then create a new web application in VS 2010 AND VS 2012 and add Csla.ASP.NET, which includes Csla.dll and Csla.Web.dll, then it doesnt work.

It appears that Csla.Web.dll seems to be the problem....??

JonnyBee replied on Wednesday, June 05, 2013

Hi,

Then it seems that HttpContext.Current is part of the problem here. 

NemisisJedi replied on Wednesday, June 05, 2013

Any chance this can be looked at, and let me know the bug.  Love the new feature, just need csla.web too :)

 

Thanks for the help so far

NemisisJedi replied on Thursday, June 06, 2013

I can confirm that System.Web.HttpContext.Current.User is nothing upon entering the task.  I am guessing that this should contain the custom identity?

JonnyBee replied on Thursday, June 06, 2013

Yes,

assuming that you have a web application - you should store the "userprincipal" in HttpContext.Current.User

This is the containter that Csla.Web.ApplicationContextManager stores userprincipal and when you create the CslaTaskFactory object it makes a "snapshot" of the variables to pass on to the tasks for context values,

NemisisJedi replied on Thursday, June 06, 2013

In our web app, we store the user in Csla.ApplicationContext.User and also hold it in Session.

Then in the global.asax file we assign Csla.ApplicationContext.User equal to the Session variable.

I presume that setting Csla.ApplicationContext.User in a web app, sets HttpContext.Current.user automatically?

JonnyBee replied on Thursday, June 06, 2013

Please make sure you are not hit with this in ASP.NET MVC 4 

See this post: http://forums.lhotka.net/forums/p/11830/55521.aspx#55521

NemisisJedi replied on Monday, June 10, 2013

I have tried this and still get the same error...

NemisisJedi replied on Saturday, August 03, 2013

Any news on when the CslaFactory is going to be avilable for download via the website?  Have all the issues been solved yet?

JonnyBee replied on Saturday, August 03, 2013

Code is available here:

https://github.com/MarimerLLC/csla/tree/master/Source/Csla/Threading

As for issues with VS2010 my problem is that I no longer have a dev-computer with VS2010 and .NET 4.0.

So any help to identify/resolve issues is appreciated.

ajj3085 replied on Thursday, September 05, 2013

JonnyBee
Code is available here:

https://github.com/MarimerLLC/csla/tree/master/Source/Csla/Threading

As for issues with VS2010 my problem is that I no longer have a dev-computer with VS2010 and .NET 4.0.

So any help to identify/resolve issues is appreciated.

Hey Jonny, I think that since the new background thread doesn't get an HttpContext the normal thread rules apply.  The CslaTaskFactory should probably set the newly created thread's principal before starting to run it.  That should allow the impersonation to work correctly.

NemisisJedi replied on Friday, September 06, 2013

Andy

Hey Jonny, I think that since the new background thread doesn't get an HttpContext the normal thread rules apply.  The CslaTaskFactory should probably set the newly created thread's principal before starting to run it.  That should allow the impersonation to work correctly.

Yes that is probably why my web version doesnt work, but it works via windows forms...

Any know the code to recreate/copy the principal to the newly created thread?  I am happy to write the code into my version of csla and test it

 

JonnyBee replied on Saturday, September 07, 2013

@Andy: That's exactly what the CslaTaskFactory tries to do. 

When CslaTaskFactory is created it stores a "snapshot" of:

 

 

And sets these values values on the new thread before calling the actual task. 

So all the logic of HttpContext or not is handled by Csla.ApplicationContext (and there is 3 stereotypes of ApplicationContext in CSLA). 

NemisisJedi replied on Sunday, September 08, 2013

(and there is 3 stereotypes of ApplicationContext in CSLA).

 

And what does this mean? For me while using this via webpage current.httpcontext.user is nothing

JonnyBee replied on Sunday, September 08, 2013

It means that CSLA has 3 implementations of Csla.Core.IContextManager: a default ApplicationContextManager and 2 specialiced:

Default: Csla.ApplicationContext.ApplicationContextManager

Xaml: Csla.Xaml.ApplicationContextManager - specialized for Xaml applications with knowledge and use of System.Windows.Application.Current

Web: Csla.Web.ApplicationContextManager - specialized for Web applications with knowledge and use of System.Web.HttpContext.Current

The key issue for your code (I believe) is to find out why HttpContext.Current.User is null before you enter the async code. It should have a value.

RockfordLhotka replied on Sunday, September 08, 2013

The right word isn't 'stereotype', it is 'provider. Csla.ApplicationContext uses a provider model to load a different implementation depending on your application.

There are three standard providers (and you can create your own).

Also, things like HttpContext and System.Threading.Thread are owned by Microsoft, and we don't manage those values except in very limited circumstances. As a result, when writing code within a CSLA app you are best off using Csla.ApplicationContext instead of things like HttpContext, because HttpContext follows its own set of rules, and ApplicationContext provides some extra behaviors that are often useful. Not least of these is that ApplicationContext works in ASP.NET and _outside_ of ASP.NET (including on background threads).

The default provider stores its data in something called thread local storage, and so makes the values available to all code running on a thread. This is appropriate when not in ASP.NET or WPF.

The ASP.NET web provider stores its data in HttpContext, so as long as Microsoft flows HttpContext the values are available. We don't change how HttpContext works, we just use it for data storage.

The WPF provider (also used in SL and WinRT) stores its data in static fields. This isn't entirely ideal, but does make the values available even as WPF tries really hard to blank them, and also because SL/WinRT don't have the concept of thread local storage or HttpContext...

In a typical ASP.NET Web Forms or MVC app you'll be using the ASP.NET provider, which (on the primary thread) stores its values in HttpContext. But ASP.NET doesn't flow HttpContext onto background threads, and we don't alter that behavior because Microsoft owns HttpContext and it would be pretty dumb to try and alter their implementation. What Jonny has done is to provide some helpers in Csla.Threading that allow you to create or call background threads/tasks such that ApplicationContext flows the values from the primary thread onto the background thread.

Copyright (c) Marimer LLC