Sunday, January 06, 2008

Referencing different versions of an assembly - Part 3 (ILMerge)

(if you missed the first and the second parts...)

We have succeed build our solution using ILMerge with the flag /internalize.

But now lets go a step further:

image

A.dll + infra V1 => MergedA.dll (using /internalize)
B.dll + infra V2 => MergedB.dll (using /internalize)

App1 + MergedA.dll + MergedB.dll => MergedApp1.dll

 

Will it work?

At first look, the answer should be it won't.

Why? remember that the reason it worked before was because infra1 & infra2 were declared Internal.

But now they both on the same Assembly (MergedApp1) so we should get an error from ILMerge about the same type declared more than once...

 

But if you try it, you'll find out it works...

How?

A another look with reflector will reveal the secret:

image

What happened? Where come from those MergedA850 and MergerdB1071 ?

The magic sits inside ILMerge. it has noticed the conflict between the two types with the same name (which now inside the same assembly - so "Internal"won't help) and just made each of them a new name!

read the following section from ILMerge help file:

The normal behavior of ILMerge is to not allow there to be more than one public type with the same name. If such a duplicate is found, then an exception is thrown. However, ILMerge can just rename the type so that it no longer causes a conflict. For private types, this is not a problem since no outside client can see it anyway, so ILMerge just does the renaming by default.

So, because Infra1 & Infra2 weren't public - they just got new names.

(Actually, you can do it for public types as well - using the /allowDup flag).

 

Is it a good solution?

 

In my opinion (or better phrased: with my situation) it isn't.

  1. Renamed types can break your application:

    If you use reflection in your code you may plan getting a type by its name.
    But now it has a different name...
  2. Multiple copies of the same type is loaded into memory:

    guess what happens if you have a singleton class in the Infra.dll.
    You can end up with 3 instance of one singleton... (ouch).

 

So back to square one -
How to reference multiple versions of the same assembly?

We have left with the two original options:

  1. Put the two DLLs into different folders, and tell the application to probe those folders.
  2. Install the DLLs into the GAC.
    This way they won't be copied into the Bin at all.
  3. Add the DLL's version to their name (e.g. Infra-1.dll)

Which one? Let's continue next time.

Thursday, January 03, 2008

Referencing different versions of an assembly - Part 2 (ILMerge)

This is where we stopped in Part 1:

image28

We have ended up with two merged assemblies (MergedA & MergedB) which are referenced by App1.

Now let's complicate things a little:

image

All I wanted to do is to use infra.dll (the version isn't critical for this discussion) inside my main application (App1).

 

If you try to use any type from infra.dll in App1 code and build the solution, you'll get:

The type "infra.xyz" exists in both 'MergedA.dll' and 'MergeB.dll'

 

What is it all about?

When I used infra.xyz type, the compiler tries to find where is it declared, but find at least two places (actually there are three). So it can't decide which one you want...

I got a question about this in a comment on Part 1 from Kevin Berridge, and actually I have crashed into the same problem few hours before, too.

 

The solution - ILMerge with /internalize switch:

The problem was created because all types inside infra.dll were exposed both by MergedA & by MergedB.

If we can make the infra part in the merged assembly internal only, our main application wouldn't be able to see it.

And this is exactly what /internalize does.
image
Only the first dll file in the merge list is left public (in yellow), and all the rest assemblies are converted to be internal (in turquoise).

You can see it using .Net Reflector:

clip_image001

Originally, Class1 was public (inside Infra)

clip_image001[6]

After merging with /internalize it is now Internal (inside MergedA)

clip_image001[4]

 

Now App1 knows of only one infra.xyz, and the build succeed!

 

Question for the next part:

What will happen if you merge App1 too?

 

Next: Part 3

Thursday, December 27, 2007

Referencing different versions of an assembly - Part 1 (ILMerge)

Consider the following scenario:

  image

We have one huge monolithic Visual Studio solution.

It contains two applications (App1 & App2) which references lots of other projects (of which I have drawn three - A, B & C), which in turn reference Some other project - "Infra".

Our business requires that we'll develop a new version of App1 which will require a new version of Project A and a new version for Infra.

We could have update Infra, and then update Project A as well as Project B and C and actually release a new version for the whole line of products.

But this is not such a great idea - as it will require building, testing and deploying of App2 without gaining any business advantage.

(You could think that we can just leave the previous version of App2, but actually we need to update it in this scenario to be able to deploy hotfix in case of finding a bug in Infra for example)

So what we actually need is to manage branches and versions.
This will look like this:

image 

In this diagram we have made a branch for Infra project and have two versions for it. Project A will use the newer version (V1) while others will use the older version (V2).

We have, however, an implementation problem here - as you can't hold the same project twice in on Visual Studio solution.

We can fix it by breaking out Infra project from the solution into its own solution, and reference DLLs instead projects. This will look like this:

image 
(I have left App2 outside this diagram as it not needed for the explanation any more)

This way, each project will reference the version it needs (using "Specific Version").

But is referencing DLLs actually solve the problem?

Let's look at the Bin folder of our projects:

Project A --> Bin --> Infra.dll (version 2)
Project B --> Bin --> Infra.dll (version 1)

App1 --> Bin --> Infra.dll (which version ???)

You see, windows' folders can't contain the two files with the same name...
I don't know which of them we will end with - but it doesn't matter - we need both!

At first we have came with 3 options to solve this new problem:

  1. Put the two DLLs into different sub folders under Bin (via post build script), and tell the application to probe those folders.
  2. Install the DLLs into the GAC.
    This way they won't be copied into the Bin at all.
  3. Add the DLL's version to their name (e.g. Infra-1.dll)

Each option has its pros and cons, and I won't go deeper into it.
Why bother selecting the less bad option if you can find a good one? (Thanks Pavel!)

 

ILMerge

This application knows to merge multiple .NET assemblies into a single assembly.

How would that help? See:

image

With the ILMerge solution, you can keep every thing normal (not changing Assemblies names, without the need for the GAC and without using complicated sub folders).

The only thing you need is to put post build event to do ILMerge on Project A & B.
Then reference the Merged DLLs from App1. Simple - isn't it?
 

 

You can download ILMerge here

See those docs for description of the problem:

http://msdn2.microsoft.com/en-us/library/0z1t9z56(VS.80).aspx 
http://msdn2.microsoft.com/en-us/library/3b12we19(VS.80).aspx 

 

See next parts:

Part 2
Part 3

Monday, December 24, 2007

Was Never...

So in MSDN (How to: Add New Work Item Queries) it says you have an Operator called "Was Never":

image

But when you open the drop down list, you only see "Was Ever":

image

And if you try to write it by yourself, you get:

TF20032: The operator for row {0} is not recognized or missing

 

So, is it a bug, or am I missing something?

Sunday, December 23, 2007

A Tour in Jerusalem

We had travel to Jerusalem this week.
By "we" I mean the employees in the company I work for.

(Tower of David)

 

I'm not a stranger to Jerusalem. I have been there countless times.
Nevertheless, you always find new things in this city.

It can be a Fish Stand in Mahane Yehuda Market:

Or an old Synagogue with error in the order of the Ten Commandments:
(See if you can spot it)

A new Museum (The Generation Center, near the Western Wall Tunnels)

Or just an interesting window (but you need to understand the background)

 

So, what should I add?

go and visit (or revisit) Jerusalem - The Holy City.

Or at least visit my Jerusalem Album on Flickr...

Thursday, December 13, 2007

Problems that are fixed in the .NET Framework 2.0 Service Pack 1

At last!!!

Microsoft just published the so missed article (KB 945757):

Problems that are fixed in the .NET Framework 2.0 Service Pack 1

Thanks Memi for updating me on this.

 

If you compare it with the list I have supplied - you can see that are a lot more fixes in the SP1 than I have succeed to find (70 in my list vs. 161 in the SP1)

But there at least some hotfix in my list which haven't entered the SP1 (944100, 943598 and 943175 for example).

Probably those were fixed too late for entering Service Pack 1 - so if you need them fixed - ask for the specific hotfix.

 

So now - go read the full list - and decide if/when to deploy it.

Good luck.

Monday, December 03, 2007

Rosario: Business Objective, Feature and Requirement

Initial comment:

The following explanation is based on November Rosario CTP, and it is only my understanding of the product. Maybe I haven't got it right. Comments are welcome.

 

When you look at Rosario's CMMI work items, you meet some old and new types which used for Requirement Management:

  • Business objective (new)
  • Feature (new)
  • Requirement

Now,  as far as I could see, the CMMI project site hasn't been updated yet with descriptions for the new work item types, so I will try to describe their roles by myself.

 

A little bit about Relations

Rosario presents different types of relations between work items.

Parent - Child
Fulfilled by - Fulfills
Predecessor - Successor
Tested by - Tests
Related - Related

Some work items defines what type of relation they should be part of.
See below for details.

 

Business Objective

As I understand, it should represent a objective which can be achieved in multiple ways. it doesn't come to describe what should be done, it comes to describe what should be achieved.

Relations:

It's possible to have a tree of BO (Business Objective), but it seems Microsoft doesn't mean you use it in that way (you can see it by the lack of "parent-Child" in its UI).
Its main use is with Feature in "Fulfilled by - Fulfills" relation.

Feature

Feature, in contrast with BO, describe what should be done, in different levels of abstraction.

Relations:

This work item suggested to be used in tree like "Parent-child" Hierarchy of Features. It can also take part in relation of "Fulfilled by - Fulfills" with Business Objectives.

Requirement

Features and Requirement are really similar, and the only difference I could point out is that while Feature has the "Fulfilling" connection to other items (probably for use with BO) Requirement doesn't. in fact, it doesn't have a built in UI for a "Parent-Child" relation either, so it seems Microsoft wants us to use it as the most detailed and low level item in "Requirement Management" before Task level.

 

to be continued...