Monday, January 7, 2008

Versions Followup

In the previous post, Two Versions of the Same Shared Assembly I outlined a problem as well as many solutions, suggesting the solution I thought was the best choice. Since then I have run into one very serious problem, and one slight concern.

Lets start with the serious problem. I implemented the solution of putting the version number in the assembly name. This worked great at run time, but the Visual Studio designer started bombing out. The weird part is it worked great in one project, but not at all in another. What's the difference between the two projects? I have no idea. They are both referencing the same project which has the SharedAsm built as a dll w/ a version number in the name as follows:

App1 -> Comp1 -> Comp1Utils -> SharedAsm.
App1 -> SharedAsm.
App2 -> Comp1 -> Comp1Utils -> SharedAsm.
App2 -> SharedAsm.

App1 doesn't work, App2 does work. I thought it might have something to do with the alphabetical ordering of the project names affecting what assembly VS used, so we renamed App1 to be the same as App2 relative to SharedAsm. That didn't change anything, it still worked.

I can't explain what is going on here yet, but it seems like the VS Designer is arbitrarily picking one of the two versions of SharedAsm in the AppDomain when it creates an instance of a type from that assembly. In the one project, it picks the wrong version, in the other project it picks the right version. Ultimately this results in the designer bombing out because of some code which tries to cast an object to a known type, but in this case the versions on the type don't match... boom.

Here's an example:
private SharedAsmType var = new SharedAsmType();
var.TypeOfInterest = typeof( Form1 );

Inside SharedAsmType the TypeOfInterest is constructed using the Activator class. This is then casted to a known type in the SharedAsm assembly. It is this cast that fails.

The reason for this is that SharedAsmType is coming from SharedAsm. but the TypeOfInterest inherits from a type in SharedAsm. Thus the activator returns a SharedAsm type different from the type that we're executing in at that point, and the cast fails:
SharedAsmType2 t2 = (SharedAsmType2)Activator.CreateInstance(t);

What should happen is SharedAsmType should come from SharedAsm. It doesn't make any sense to me at all why it's coming from It really looks like the VS designer is just picking a SharedAsm assembly, ignoring which one is actually referenced by App1.

If any one can shed any light on this one, I'd absolutely love to hear about it.

The other problem is one I haven't directly tested but which I imagine would be an issue. If your existing code base had any code in it which used reflection to reference the SharedAsm assembly by name, you wouldn't know which version you were going to end up with. I don't know if .NET would just pick a version, or if it would bomb out... This one is just a problem of having two versions of a shared assembly loaded in the AppDomain at the same time and using reflection. The only one of our solutions which wouldn't suffer from this would be the ILMerge /iternalize solution. And again, the memory usage side effects of that just aren't acceptable.

So, unfortunately, this seems to bring me back to square one again... I'll post any information that may come up as I continue to fight with this problem and I'd really love to get some insight from the vast world of .NET developers out there. Surely there are more .NET programming shops running into the need to create "packages" that contain shared assemblies!

1 comment:

  1. I just finished retesting this strange Visual Studio designer behavior in VS2008. It still breaks the same way. In fact, it still breaks only in the one project and not the other...

    Also, the reflection problem still stands.