CSLA Unit Testing & Visual Studio 2008

CSLA Unit Testing & Visual Studio 2008

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


Marjon1 posted on Tuesday, August 26, 2008

Hey,

I'm hoping for some insight from the experts on the forum, we are starting to write some unit tests again and are using the VS2008 testing environment and are experiencing a few problems. The most basic exception being thrown is a SerializationException and I looked through the forums and read all about NUnit and AppDomains and while I could get my head around most of it, the issue is pretty deep into my code and occuring well before the testing environment app domain crossing should occur.

Here is a line of code from my application (do validate license file, done as part of Principal.Login)

    Private Function ValidateHash(ByVal XmlData As String) As Boolean
     return Cryptographer.CompareHash(Licensing.Constants.LicenseHashProvider, ExtractPlainLicenseKey(XmlData), ExtractLicenseHashKey(XmlData))
    End Function


The Cryptographer.CompareHash is part of the EnterpriseLibrary Cryptography Library and as soon as this line of code is executed, I get the serializer exception to do with Principal. This code works fine outside of the testing environment FYI!

If I change the code (based on a forum post (http://forums.lhotka.net/forums/thread/3807.aspx) to do the following:

    Private Function ValidateHash(ByVal XmlData As String) As Boolean
      Dim bll As Boolean
      Dim tmpPrincipal As System.Security.Principal.IPrincipal = Threading.Thread.CurrentPrincipal
      Threading.Thread.CurrentPrincipal = Nothing
      bll = Cryptographer.CompareHash(Licensing.Constants.LicenseHashProvider, ExtractPlainLicenseKey(XmlData), ExtractLicenseHashKey(XmlData))
      Threading.Thread.CurrentPrincipal = tmpPrincipal
      Return bll
    End Function


It works fine, what I don't understand why I have to reset the principal to nothing when performing unit tests. This is outside the scope of CSLA itself, but insight as to why this code works and is necessiary would be greatly appreciated.

Thanks

guest replied on Tuesday, August 26, 2008

hey,

I am having the same problem. Please let me know, if you will find the solution. I have few test cases. If i am trying to execute test project, it gives me an error as follows.

Unit Test Adapter threw exception: Unable to find assembly 'AssemblyName'..

Code is working fine in development environment, without any issue.

I tried debug the code and i came to know that there is some error in following code.

Private Sub SetCurrentPrincipal()

'******************** Create New Thread Principle Process Authentication ********************

'Get the current Application Domain. Each AppDom has a security policy controlling how any

'Thread in the Dom gets its Principal object. Were implementing custom security, so we want

'the policy to avoid doing any custome Authe. So set the value to an UnAuthenticated principal.

Dim currentdomain As AppDomain = Thread.GetDomain

currentdomain.SetPrincipalPolicy(PrincipalPolicy.UnauthenticatedPrincipal)

'Store the Current principal, before setting the newly UnAuthenticated one.

'All code running on this thread relies on business principal to provide security info

'about users identity and roles.

Dim OldPrincipal As IPrincipal = Thread.CurrentPrincipal

Thread.CurrentPrincipal = Me

'The current thread has been set to use the new principal object. However, its possible that

'other threads will be created in this application domain. This code ensures they get the same

'Business Principal obejct automatically when they are created.

Try

If Not TypeOf OldPrincipal Is BusinessPrincipal Then

currentdomain.SetThreadPrincipal(Me)

End If

Catch

'Failed, but we don't care because there's nothing we can do in this case!

End Try

'********************************************************************************************

End Sub

 

please let me know if anyone have any idea about it.

trives replied on Tuesday, August 26, 2008

Hi Marjon,

We use the same unit test environment (VS2008), and your problem sounds very similar to a problem we had.  I don't remember exactly what the cause was, but it had something to do with each unit test executing in its own AppDomain (or something like that).

Anyway, here is something you can try.  Assuming VS2008 is installed on your development computer in "C:\Program Files\Microsoft Visual Studio 9.0", create the folder "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\UnitTestAssemblies".  Copy Csla.dll to that new folder.  We use a custom Principal object that extends BusinessPrincipalBase.  If you do the same, then you should copy the assembly defining the custom Principal type to the new folder also.  Basically, copy any assemblies that define types having to do with the Principal object into this new folder.

Next, you need to edit the file "C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\VSTestHost.exe.config".  There should be a line that looks like:

<probing privatePath="PrivateAssemblies;PublicAssemblies"/>

Change it to:

<probing privatePath="PrivateAssemblies;PublicAssemblies;UnitTestAssemblies"/>

Restart VS2008 and run your unit tests again.

Always keep the assemblies in UnitTestAssemblies up-to-date.  If you build a new Csla.dll, then copy it to UnitTestAssemblies before trying to execute your unit tests.

Hope this helps.

 

ajj3085 replied on Tuesday, August 26, 2008

I think this was a problem as well in NUnit.  I have helper code that, prior to calling the logon for my principal, I record whatever the current principal for the current thread is in a static variable.  Then I have another helper method that, after calling the logout on my principal, resets the thread's principal back to the stored values.

So... maybe that will help.

trives replied on Tuesday, August 26, 2008

Marjon,

Since you seem curious as to why this happens, I dug up this explanation from this thread http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2658259&SiteID=1:

Thank you for your detailed repro steps.  We have recently become aware of this issue; it has been reported to us by a number of different customers now.  We understand what is causing this problem, and have every intention of fixing it, but cannot yet commit to a timeframe for doing so.

Here is a brief explanation of the problem.  Each test method executes in its own AppDomain.  This domain is able to resolve assemblies in the deployment "Out" directory, which holds test assemblies, assemblies under test, and anything explicitly deployed by the test code.  When a test method completes, the executing thread returns to the default domain for the VSTestHost process, which unfortunately now (in VS2008) is ignorant of the "Out" directory.  In this transition back to the default domain, the .NET remoting infrastructure attempts to deserialize the object set on Thread.CurrentPrincipal, but can't resolve the assembly that houses its type - hence the exception.  The same would apply to any objects set, for example, on System.Runtime.Remoting.Messaging.CallContext.

Unfortunately, I do not have a good, general workaround to recommend.  You could try something ugly like altering the probing path for VSTestHost.exe to include the path to your assembly under test, but of course that only works if you are an admin on the box.

Regards,

Neal Fowler

VSTS Team Test

Copyright (c) Marimer LLC