I am using CSLA in a VSTO Outlook add-in project. I am getting the following error:
Exception of type 'System.Runtime.Serialization.SerializationException'. ... 'Unable to find assembly 'CSLA, Version=2.0.0.0,. . .. '
I narrowed it down to a call to set the user on the app context with :
ApplicationContext.User = (IPrincipal) myCustomPrincipal.
I do have a custom principal object inherited from BusinessPrincipalBase.
I also noticed that when under VSTO the Thread.CurrentPrincipal is always GenericPrincipal unless I set the current principal to null first. Wondering if anyone else has used CSLA with VSTO and specifically the security.
Thanks,
David
Thanks to both Rocky and Andy. I have found the section in chapter 4 to which you refer. However, I'm at a bit of a loss as to where to place this workaround. Andy, where in your VSTO project did you end up placing this?
In the mean time I'll be experimenting with several places for the code.
Thanks much,
David
Andy: I've tried placing code similar to that found in the solution mentioned by Rocky in several places in my VSTO project and I'm not getting any solution.
First, I tried placing it in the ThisApplication_Startup - I made a call to SerializationWorkaround and from there it is identical to Rocky's solution with the exception that my code is not static.
Second, I tried the above but starting with the static constructor of ThisApplication and using static methods just like Rocky.
Third, I tried both 1 & 2 above but this time in my business object.
Regardless of where I place the code I still get the same error. Any further advice? Also, I placed breaks within the AssemblyResolve event handler and it is apparently never getting called.
Thanks much,
David
Andy: Here is my code from ThisApplication.cs
private void ThisApplication_Startup(object sender, System.EventArgs e)private void SerializationWorkaround()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler
(currentDomain_AssemblyResolve);
}
Assembly currentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
Assembly[] list = AppDomain.CurrentDomain.GetAssemblies();
foreach ( Assembly asm in list )
if ( asm.FullName == args.Name )
return asm;
return Assembly.Load(args.Name);
}
Some more info: When I step through my code I can execute the line where I set the ApplicationContext.User object to my custom principal without error. The error occurs on a line where I have the following:
frmMyCustomForm.ShowDialog()
Now, in the constructor of that form I am creating a new business object. In the constructor of the business object I am setting the ApplicationContext.User object. I am guessing this is where the problem is because I can comment out the simple set of Thread.CurrentPrincipal (from with in the Application.Context.User settor and all works fine (except I don't have a way of keeping the ApplicationContext.User in sync with the Thread.CurrentPrincipal.)
Maybe I don't need them to be in sync except that all of this has worked perfectly for a while now when doing ASP.Net or simple WinForms. This problem has only appeared now that I am doing some VSTO stuff.
Thanks again,
David
I'm not sure what was going on. I may have explained it wrong but I never got past the first time I set AppContext.User. In fact, I bypassed that and set Thread.CurrentPrincipal directly and that caused the exact same problem.
As for what dataportal I'm using, currently it would be the no network option as everything is currently local. Also, everything about data access is working. I am able to retrieve objects from the DB and insert/update objects to the DB no problem. In fact, that's what confused me most - to be told that it could not find the CSLA assembly eventhough it had just gotten through using that assembly.
Anyway, for now I am trying a custom property on the AppContext.CustomUser. Inside of this I am using the pattern from AppContext.GetClientContext (and it's sister SetClientContext). I'm placing my custom principal into the data slot. When I retrieve the user, if its null, I do a CustomPrincipal.Login() and that performs all of my custom login stuff.
So far it appears to be working. Problem is that I am not yet used to using the named data slots on a thread so I hope I not doing anything terribly wrong by placing my custom principal there.
Thanks,
David
Here's my code as I remember it (I've changed it since to what I wrote above):
In the business object's New factory method:
public static Application NewApplication()
{
Application app = new Application();
app._id = Guid.NewGuid();
... more property sets
WillisIdentity i = ApplicationContext.User.Identity as WillisIdentity
if ( i == null )
{
WillisPrincipal.Login();
i = (WillisIdentity)ApplicationContext.User.Identity;
}
app.userid = i.ADGuid.ToString();
return app;
}
The WillisPrincipal.Login (again, as I remember it)
public static bool Login()
{
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
if ( Thread.CurrentPrincipal is GenericPrincipal)
Thread.CurrentPrincipal = null;
WillisIdentity ident = WillisIdentity.GetIdentity(Thread.CurrentPrincipal.Identity.Name);
WillisPrincipal prin = new WillisPrincipal(ident);
ApplicationContext.User = prin;
return ident.IsAuthenticated;
}
The WillisIdentity.GetIdentity takes the username and does an AD lookup. If it finds the user in AD it populates certain fields on the identity object. Fields like, display name, ADGUID, email address, first and last name.
Not sure if all that helps.
Thanks for all of your help on this,
David
It almost sounds like a version mismatch problem; as you said, if your principal is based off of a Csla class, its kind of hard to understand why the assembly isn't being found.
This sounds reasonable to me. Unfortunatly, I don't think VSTO offers anything so clear. The work around could be to check that the assembly resolve event is handled each time your code runs.. perhaps not nice, but it should work.
I was having exactly the same problem with VSTO 2.0. Resetting the Principal to be a GenericPrincipal works. In the form's Close event I'd reset the Principal to be GenericPrincipal, and right after the ShowDialog call, set it back to CSLA principal.
I discovered a better solution though. Just drop a BackgroundWorker control on your form while in design mode. You don't necessarily need to do anything with it, just having it, makes the serialization exception go away.
I don't know why this takes care of the issue, if you do, please share.
I've just encountered this problem in a Word VSTO using .NET 4.5.1 and CSLA 4.5.501
The serialization workaround made no difference to me, but luckily I have come across this post by MikeGoatly:
http://forums.lhotka.net/forums/p/11545/55404.aspx#55404
This solved my issue - I had to force the ConfigurationManager to reinitialize BEFORE I set my Principal on the thread. Not entirely sure why but it works! If I don't call the ConfigurationManger to force it, I get a Serialization Exception regarding my custom Principal class.
Copyright (c) Marimer LLC