# Wednesday, August 24, 2005

I mentioned earlier that a customer question started off this thread. This is the post that most closely aligns with their question. You can likely see why I've waited until now to answer it, since the earlier posts have all provided information on how the GACs work, either separately or in tandem.

This post isn't exclusive to the GAC, but we'll keep it in the same theme since we're on a roll here and since it does apply w/o too much of a stretch.

Ship both Everett and Whidbey Versions
This is the approach that will make your customers most happy. Everett customers have a library that they can code against. At this point, there are way more Everett customers out there than Whidbey ones, so providing an Everett version likely makes business sense in the short-term. At the same time, you recognize that Whidbey customers have different requirements. Folks who have been playing (or more than playing with our Beta 2 "Go Live" license) with Whidbey for a number of months now (or longer) have gotten used to the Whidbey way of doing things. A bunch of them probably now say "of T" at the end of all their sentences, even at home. Kinda like how I always say "eh" ;) In the same way that you want to keep existing customers on Everett happy, you want to ride the Whidbey adoption curve, picking up sales (if that's the kind of business you are in) from folks coding exclusively in VS2005 with a Whidbey version of your product.

This post isn't intended to cover exactly how you produce these two separate version. I should consider a post on this topic at a later time. The two basic approaches are: (A) have two separate source trees, or (B) a single one with lots of conditional code. There are advantages and disadvantages to both and you need to decide which path you will go down.

Versioning The Everett and Whidbey Versions
Finally, we're at the core of the customer question. Now that you've decided to ship the two versions in tandem, what do you do about version numbers and that sort of thing. Hmmm.

Scenario 1 - The Whidbey version is the same code as the Everett version, just compiled with a Whidbey compiler
- For starters, this is not a super-high-value proposition for class libraries. You definitely are doing your due diligence to avoid breaking changes, but that's it. Also, you can run your Everett code through the Whidbey compilers to do compatibility testing as part of your general testing.
- This is a high-value-proposition for applications (you get an .exe from the compiler). By compiling an Everett app with a Whidbey compiler, you enable running natively on a 64-bit machine. Everett apps always run under WoW64 on 64-bit machines. This post isn't about applications though, but class libraries.
- Anyway, if you decide to go this route, I would keep the version numbers of the Everett and Whidbey components exactly the same, but give the binaries different names (i.e. FooWidgetE.dll, FooWidgetW.dll). Since they are compiled against different CLRs, the code will end up in different GACs, which will further separate them.

Scenario 2 - The Whidbey and Everett versions are mostly the same code, compiled out of the same codebase with pre-processor directives
- First, I would only do this if the differences between the Everett and Whidbey versions -- which will directly affect the number of pre-processor directives you have in your code -- is not dramatic
- I'm assuming that the Everett and Whidbey versions have the same general object models, with a few members and types being specific to Whidbey
- I would do the same thing as Scenario 1 above with differently named assemblies
- If they are on radically different ship cycles, I might start to lean towards scenario 3

Scenario 3 -- The Whidbey and Everett versions are different code
- This approach will be the best one if you intend to move your object model in a different direction in the Whidbey codebase
- I would name the assemblies differently, more differently than in scenario 1 above
- I would not make any effort to keep the version numbers in sync. They might stay in sync, however, if you always ship the two versions on the same schedule
- I would probably change the namespace names too, to make it clear that this is a new thing. This is debatable though since it makes migration harder. The thing that this does do though is make it clear when a customer moves to the Whidbey version that they have more than just a re-compile on their hands

Your code may not fall perfectly into the above buckets, but you'll at least get the idea of some possible directions to take. As always, you need to come up with a plan that makes sense for your product, not just blindly follow a plan outlines on some blog, particularly one that is called "hoser".

Wednesday, August 24, 2005 2:38:10 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
# Tuesday, August 23, 2005

In my two (one and two) earlier "Wonders of the Whidbey GAC" posts, I talked about processor architecture and interop with the Everett GAC. I left out one piece of interesting data because it wouldn't make as much sense until you had read the earlier posts. This data point is the binding order among the GACs. Naturally, you cannot look at them all at once, so we defined an order of probing the GACs that we always adhere to and tends to make sense.

Here is is:

  1. Bitness GAC
    • "gac_32" when running on a 32-bit machine or under WoW64 on a 64-bit machine
    • "gac_64" when running natively (not WoW64) on a 64-bit machine (this is the normal case for Whidbey apps on a 64-bit machine)
  2. Bitness agnostic GAC
    • "gac_msil" on all machines
    • assemblies in this GAC run equally well everywhere (X64, X86, IA64)
  3. Legacy v1.x GAC
    • "gac" on all machines
    • this is where v1.0 and everett assemblies go

You can read this same information on Junfeng's blog too, as he implemented all of this. I just slow him down ;)

Junfeng referes to MSIL assemblies as "portable". I use the term "agnostic". It is the same thing.

If you write managed code in your favourite language (i.e. c#, vb) and don't do anything special, your assemblies will fall into this category. You can do the same thing with MC++ code too, if you compile it as /clrpure; otherwise, mc++ code is by design "bit-specific". Oh, there's another term, but I'm sure you can figure that one out.

If you are unsure of which of the three GAC buckets above your assembly will fall into, and your assembly is strong-name signed, install it into the GAC with gacutil /i from the Whidbey SDK. Gacutil will install the assembly into the correct GAC and then you'll know for sure. You can also open up the assembly (not required to be strong-name signed) in ildasm. That will also tell you the same answer.

Tuesday, August 23, 2005 3:47:45 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Monday, August 22, 2005

I received a question from a customer a few days ago about assembly versioning. I receive questions quite often, of which >90% surprisingly enough come via Brad. I can only imagine what his inbox looks like every morning! Anyway, the question touched on the focus for this post which is the relationship between the Everett and Whidbey GACs. Before I go any further, I’m happy to report that the relationship is sensible and easy to understand. Too often, things don’t make a lot of sense and that always bugs me.

 

The customer’s question was actually about assembly versioning in the case that you want to support Everett and Whidbey, which I hope to cover tomorrow, since that’s when I told them I’d give them an answer ;)

 

First things first, on the surface it seems like interop between the GACs is what is wanted. In actual fact, it is the behaviour of the CLR loader and gacutil.exe that is really the interesting part. The GACs themselves are passive and don’t do anything other than act as a quite compelling directory structure for holding code w/o any naming conflicts.

 

Migrating the Everett GAC to the Whidbey GAC

We don’t do anything like this. This would have been the wrong direction for multiple reasons. Just thought I’d take care of this one up-front.

 

Hard linking assemblies between the Everett and Whidbey GACs as a Perfomance Enhancement

I’m glad that we didn’t do anything like this either. Ouch. OK, now onto the real answers.

 

Whidbey CLR Loader GAC Probing

The Whidbey CLR loader – Fusion in this case – probes for assemblies in the Everett and Whidbey GACs when an assembly request comes through the system. I’ll skip the exact algorithm and any optimizations that we might do. The high-order bit here is that we do indeed look in both GACs, so there is no need to stop using the Everett GAC for Everett assemblies since we look there. In fact, as you’ll find out below, you cannot stop using the Everett GAC.

 

Gacutil.exe, the Fusion APIs and installation via MSI (installers)

There are several ways that you can get assemblies installed into the GAC, with the last one being the recommended option. The big thing I wanted to know when I asked the question is what the expected behaviour was when I added an assembly to the GAC via these different methods.

 

Question:

Do the Whidbey tools put Everett assemblies into the Everett GAC?

 

Given:

Everett and Whidbey .NET Frameworks are installed on the machine

 

Assemblies:

1) 1 assembly compiled against Everett csc.exe (csharp compiler)

2) 1 assembly compiled against Whidbey vbc.exe (vb compiler)

Note: the compilers (vb, csharp) don’t matter for the assemblies above. I’m just trying to mix it up a little. It is the .Net Framework versions that matter.

 

Tools:

A) Everett Gacutil

B) Everett Fusion APIs

C) Whidbey Gacutil

D) Whidbey Fusion APIs

E) MSI installation

 

Scenarios + expected outcome:

1. (1) + (A) -- Everett GAC

2. (1) + (B) -- Everett GAC

3. (1) + (C) -- Everett GAC

4. (1) + (D) -- Everett GAC

5. (1) + (E) -- Everett GAC

6. (2) + (A) -- failure

7. (2) + (B) -- failure

8. (2) + (C) -- Whidbey GAC

9. (2) + (D) -- Whidbey GAC

10. (2) + (E) -- Whidbey GAC

 

Scenarions 6 and 7 fail since Whidbey-compiled assemblies are not loadable via the Everett CLR. Also, since processor architecture is a major part of Whidbey, it would be difficult to store Whidbey assemblies in the Everett GAC in a reasonable manner.

 

Why does Whidbey put Everett assemblies into the Everett GAC?

We continue putting Everett assemblies into the Everett GAC for two reasons:

 

-          Everett apps still require those assemblies and will only be able to use them if they are in the Everett GAC since the Everett CLR loader knows nothing about the Whidbey GAC. It is much easier and smarter for the Whidbey loader to look in the Everett GAC.

-          Everett assemblies didn’t have the concept of processor architecture, which the Whidbey GAC is heavily based on, so it doesn’t make sense to store Everett assemblies in that new structure.

-          Everett is going to live for a long time. Let’s not mess with a good thing ;)

 

That was actually 3 reasons, if you count the last one.

 

Is there an Everett GAC if there is no Everett .NET Framework on the Machine, but only Whidbey?

Yes. The Everett GAC is created as needed when Everett is not on machine. This means that the Everett GAC structure is auto-created when the first Everett-era assembly is added to the Whidbey-only machine. If Everett was also on this machine, the Everett GAC would have been created at the point that the Everett .NET Framework was installed.

 

Monday, August 22, 2005 5:39:12 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
# Saturday, August 20, 2005

The GAC -- Global Assembly Cache -- is a popular topic among managed code developers. It serves two main purposes: (A) as a catalogue of the globally publicly available assemblies available on the system, indexed by strong name, and (B) the location of those same files. It is not my intent to describe the GAC, however; look here for more info. My intent is to describe some interesting changes that have been made to the GAC for Whidbey and to promote some good practices. This is part I and is dedicated to processor architecture; we'll see how far we get with the series ;)

Whidbey is the first CLR release in which we support 64-bit execution. The CLR team has been working on porting the CLR to 64-bit for several years now and is now releasing it to the world with Whidbey. Woohoo! Not surprisingly, 64-bit has required a lot of changes all over the CLR, as it imports a bunch of new concepts onto us. My favourite is the general concept of processor architecture, of which there are four that we now support: X86, X64, IA64 and MSIL. We always supported the first and the last, but there was never a strong reason to differentiate them considerably as we only ran on a 32-bit system.

With respect to the v1.x GAC (v1.0 and Everett share the same GAC), you can see pretty clearly that processor architecture was not a design point.

V1.x GAC location
C:\Windows\assembly\GAC

V1.x System.dll location
C:\WINDOWS\assembly\GAC\System\1.0.5000.0__b77a5c561934e089\System.dll

Where would you have tagged the processor architecture? Nowhere that I can see. As a result, we changed the GAC structure in Whidbey to accommodate processor architecture, which is now an incredible important aspect of the GAC.

V2.0 GAC locations on an x86 machine
C:\Windows\assembly\GAC_MSIL
C:\Windows\assembly\GAC_32

V2.0 System.dll and mscorlib.dll locations on an x86 machine
C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll
C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll

V2.0 GAC locations on an x64 or IA64 machine
C:\Windows\assembly\GAC_MSIL
C:\Windows\assembly\GAC_32
C:\Windows\assembly\GAC_64

V2.0 System.dll and mscorlib.dll locations on an x64 machine
C:\WINDOWS\assembly\GAC_MSIL\System\2.0.0.0__b77a5c561934e089\System.dll
C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll
C:\WINDOWS\assembly\GAC_64\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll

You can now see that it is easy to tag assemblies with processor architecture. We’ve created three GACs to do just that! As you can see, the GAC_64 directory only shows up on 64-bit machines, which is hopefully quite intuitive.

I’ve run out of time to get any further in this post, but hopefully it gives you a good idea of how and why the GAC changed, at least with respect to processor architecture in Whidbey. I also hope I left you with the opinion that these changes were a good idea ;)

A question to ponder: If you call System.Reflection.Assembly.Load(“System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089”) and there is both a copy in the bit-specific GAC and another in the bit-agnostic (MSIL) GAC, which do you get?

Saturday, August 20, 2005 6:02:47 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [5]  | 
# Tuesday, August 16, 2005

I was recently reading the "remarks" section for the AppDomain.Unload() method @ http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemAppDomainClassUnloadTopic.asp. I was doing a review of the documenation available to determine if we needed more around the CannotUnloadAppDomainException exception. I decided that we were in an OK spot for the most part, but that I would post a little more information on this exception for the small percentage of .NET programmers out there who need it. At least, I certainly hope that most .NET programmers don't need this information ;)

Note: Please mail me if this information proves particularly useful for you -- I'd like to better understand your scenario.

Upon calling the AppDomain.Unload() method, the CLR will request that all threads in the unloading domain abort. Threads do not abort instantly, so getting n threads to abort will take some time. As a result, the CLR checks after 10ms* to determine if there are any threads still running. If there are not any threads still running, then the CLR will proceed with domain shutdown. If there are threads still running, then the CLR repeats this process -- wait 10ms and check -- up to 1000* times. In the general case, it is very unlikely to need to repeat this process 1000 times (or anything close to it); eventually, all threads will be aborted and domain shutdown will occur. The purpose of this repeating "wait and see" behaviour is to avoid a deadlock due to a thread that will not abort for some reason.

If the 1000th check fails, meaning that threads are still running (not yet aborted), the CLR will throw a "CannotUnloadAppDomainException" exception. If the application, after the exception has been thrown, can do something to prevent this situation from occuring again (i.e. cleanup or manually aborting threads) then the application should perform that cleanup and call AppDomain.Unload() again. It is not expected, however, that the app should attempt to try repeat this process -- catching the "CannotUnloadAppdomainException" exception and calling AppDomain.Unload() -- an indeterminant number of times until it "works". The best approach is to remove the case where the exception is thrown at all, which means ensuring that all threads in a domain can be aborted in a timely manner. If the application, after the exception has been thrown, cannot do anything to prevent this situation from occuring again, it should not call AppDomain.Unload() again, but terminate the application or leak the domain.

* please consider these numbers (10ms and 1000 times) as implementation details. You absolutely should not take a dependency on them, for two reasons: (A) they are subject to change in a later release w/o notice, and (B) the number of running threads, processes and CPUs (+ multi-core) can very significantly change the time it takes to hit the 1000th iteration of the check due to the amount of CPU time that the unload check is given.

Tuesday, August 16, 2005 3:03:38 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 
# Wednesday, July 20, 2005

After logging in, be sure to visit all the options under Configuration in the Admin Menu Bar above. There are 26 themes to choose from, and you can also create your own.

 

Wednesday, July 20, 2005 8:00:00 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Friday, May 27, 2005

Our Product Unit Manager is hiring! Jason's post is about interns, but he has a link to regular jobs too at the end of the post. The CLR team is the best team that I've worked for at Microsoft. If you want proof, read this blog entry.

We are currently closing up Whidbey and doing some initial planning for Orcas. By the time you get here, we'll likely be prototyping ideas for Orcas. In fact, I have an executive review in just over a week with Jim Allchin on the managed code versioning work we are planning for Orcas. We'll see what he thinks. If you join the team, you'll find out ;)

Friday, May 27, 2005 4:23:16 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, May 25, 2005

Yes. Please send mail to netfxcmp@microsoft.com to get signed up for this free program.

We're trying to do the right thing and get as many apps/controls/add-ins as possible to ensure that Whidbey is a compatible release. We have a bunch of apps already in our lab and have tested them extensively looking for any compatibility issues. We use these applications to establish a baseline of behavior and we’d like to add your app to the mix to ensure we haven’t missed anything. If we add your application to our appcompat tests, we are not just going to use them for testing compatibility with .NetFX 2.0, but we’ll add them to our regression suites and test them against the SP’s and future FX releases as well.

Take a read at this eWeek article, just published today. The article is a little dire in spots (including the title), but the basic idea is that we have a compatibility program and are ramping it up before we ship, now that the product is stabalizing in preparation for shipping. Most apps do "just work".

This blog, a dasBlog blog, is an example of "just works" on Whidbey. The dasBlog blog engine is an Everett ASP.Net web app, written for the 32-bit Everett (v1.1) CLR. My instance of dasBlog is running on top of the 64-bit Whidbey (v2.0) Beta 2 CLR. It "just works", as you can see.

Please do send in your app to add it to our mix of apps tested in our compat lab. You can also do compatibility testing yourself. See the Compatibility Testing Scenarios doc on MSDN for detailed instructions on how to do your own compatibility testing.

Here is a blog entry from JasonZ, our Product Unit Manager, on your compat and project upgrade experience. And an MSDN article on Whidbey compatibility. I encourage you to read these articles.

Caveat: This "free program" isn't long-term. We need a bunch more apps in the short term to beef up the sample size of apps in our compat lab. At the point we believe we have enough apps in our lab, we'll no longer need this program.

Wednesday, May 25, 2005 8:06:39 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [2]  | 
# Tuesday, May 24, 2005

I need to post on the assembly version number for Whidbey again, for two reasons: (A) I never posted what it actually was, and (B) I posted some inaccurate data that I'd like to correct.

(A) is easy. The assembly version number for Beta 2 and RTM is: 2.0.0.0. This may seem to make sense for a version number, however for Everett it was 1.0.5000.0 -- not sure why that was chosen. 

(B) is slightly more complicated. I said in an earlier post that apps built on top of Whidbey Beta 1 (or earlier) would need to be recompiled. That is not true. They will work fine on Whidbey RTM without re-compilation. What will not work is Whidbey RTM apps running on the Whidbey beta 1 runtime -- which is presumably not a scenario for anyone.

(B) is true due to framework unification, which only applies to .NET Framework assemblies (i.e. System.Web.dll). The assembly binder basically does a quick test to determine if the version of a framework assembly is higher or lower than the one that ships with a given runtime -- meaning the runtime currently being run in the process. If it is higher, the load is rejected; if it is lower or equal, the referenced version number is ignored and the version that shipped with that runtime is loaded instead. We go through this algorithm to prevent Everett System.Web.dll running on Whidbey with Whidbey System.dll. Those configurations are not supported, so we prevent them from occuring.

Tuesday, May 24, 2005 12:05:18 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  |