# Tuesday, December 05, 2006

We often talk about the loaded assemblies list over here. This is the list of assemblies currently loaded in the app domain. Big surprise. There isn't anything incredible special about this list. It is pretty easy to access and use. At the minimum, you can print out the list of assemblies. Beyond that, you can load and instantiate any of the types within those assemblies. That's where reflection comes in.

Here's some code that prints out the list of loaded assemblies:

using System;
using System.Reflection;

namespace GetLoadedAssemblies
{
class Program
{
static void Main(string[] args)
{
Assembly[] asms;

asms = AppDomain.CurrentDomain.GetAssemblies();

Console.WriteLine("There are {0} assemblies loaded:", asms.Length);
foreach (Assembly asm in asms)
{
Console.WriteLine(asm.FullName);
}

Console.WriteLine();
Console.WriteLine("The currently executing assembly is:");
Console.WriteLine(Assembly.GetExecutingAssembly().FullName);

}
}
}
Tuesday, December 05, 2006 11:51:00 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, November 29, 2006

I took another look at the FileVersion sample. I wish the API was actually a little different. The API actually makes sense as a general use API, but it isn't as user-friendly as I would like. I wish that there were an instance method on the Assembly class called "GetFileVersion" or something like that it took nothing and returned a Version class.

Here is more of less what it would look like, except that the GetFileVersion wouldn't be static, it wouldn't take anything and would be on the assembly class.

If you look @ the FileVersion class, there is a lot of stuff on there, and it is a super wonky API anyway. I don't understand why it has a single static method that more or less acts that the instance constructor. Why not just have a constructor that takes a string or a FileInfo or even a FileStream. Bad API design. I prefer the Version class a lot more since it is super simple. I

using System;
using System.Reflection;
using System.Diagnostics;
namespace FileVersion
{
class Program
{
static void Main(string[] args)
{
Assembly asm;
Version ver;

asm = Assembly.Load("mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
ver = GetFileVersion(asm);
Console.WriteLine(ver.ToString());
}

static Version GetFileVersion(Assembly asm)
{
FileVersionInfo versionInfo;
Version ver;

versionInfo = FileVersionInfo.GetVersionInfo(asm.Location);
ver = new Version(versionInfo.FileMajorPart, versionInfo.FileMinorPart, versionInfo.FileBuildPart, versionInfo.FilePrivatePart);

return ver;
}
}
}

If you look @ the FileVersion class, there is a lot of stuff on there, and it is a super wonky API anyway. I don't understand why it has a single static method that more or less acts like an instance constructor. Why not just have a constructor that takes a string or a FileInfo or even a FileStream. Bad API design. I prefer the above method (for the assembly case) that returns the Version class since it is super simple. I realize that the native file version is a string, so can contain more stuff, but the 4-part version number is really all I want.

Wednesday, November 29, 2006 3:39:29 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 

The file version number is a native code concept – meaning not originating from the .NET Framework. This version number is a resource found within the resource section of the windows PE (portable executable) format of a managed or native code dll. This resource is named “FILEVERSION”. This version number is used for information purposes only, not for any runtime purposes such as binding. In addition, this version number does not have to conform to a particular format, but is only a string, although it does typically takes the form of a simple four-part number (i.e. 1.2.3.4).

Reading the File Version

The easiest way to view this number is to view the properties of a file in Windows Explorer. The version number listed is the file version number. The product version is also listed, although I don’t know how the two numbers differ exactly. Naturally, you can access the file version from code. The following code does just that, largely using the System.Diagnostics.FileVersionInfo class, which I’ve never used before. In fact, I had to ask someone else on the loader team for that information.

using System;

using System.Reflection;

using System.Diagnostics;

namespace FileVersion

{

    class Program

    {

        static void Main(string[] args)

        {

            Assembly asm = Assembly.Load("mscorlib, Version=2.0.0.0, Culture=neutral,  PublicKeyToken=b77a5c561934e089");

            System.Diagnostics.FileVersionInfo fvi = FileVersionInfo.GetVersionInfo(asm.Location);

            Console.WriteLine(fvi.FileVersion);

        }

    }

}

 

Setting the File Version

The CLR provides an assembly-level custom attribute to set this version number for an assembly from managed code. This attribute is called System.Reflection.AssemblyFileVersion. You can see how to set it below.

using System;

using System.Reflection;

 

[assembly:System.Reflection.AssemblyFileVersion("2.3.4.5")]

 

namespace ConsoleApplication1

{

    class Program

    {

        static void Main(string[] args)

        {

            Console.WriteLine("I just set the file version!");

        }

    }

}

 

You can actually set this attribute in Visual Studio 2005 via the properties menu. In that case, you cannot set it in code, as I’ve done above, since you’ll then have two instances of the attribute. You only need to set the attribute directly, as I’ve done  above, if you are using the compiler directly, from the commandline.

Wednesday, November 29, 2006 12:00:36 AM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, November 28, 2006

Versioning and version numbers are always a bit confusing. For the CLR and the .NET Framework, we’ve got lots of version numbers to think about. I’d like to debunk any confusion around them, explain what each version number means, how to view it and how to set it (if appropriate). Let’s take a look …

The version numbers that I’m going to discuss are:

·         Native file version

·         Managed assembly version

·         Metadata version

·         Metadata format version

·         .NET Framework versions

I’m going to discuss these version numbers (and anything else that comes up) across the next few posts.

Tuesday, November 28, 2006 11:53:35 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, November 02, 2006

I made reference to the concept of textual identity in my last post, but didn’t go into a lot of detail. In this post, I’d like to describe the broader concept of assembly identity to provide folks with further insight as to what I was going on about. The following text is from a spec that I wrote; it should apply equally to v1.0, v1.1 and v2.0 and future .NET Framework versions.

Assembly Identity

The assembly identity is the name of an assembly. The filename, path, file hash or other characteristics are not part of the identity. The identity is used in two different ways: (1) to define the name of an assembly, and (2) to reference an assembly by name. These are sometimes referred to as “def” and “ref”. Both of these are assembly identity. In the case of a reference, the identity is used during binding to determine if and where an assembly is available.

 

Identity Composition

The assembly identity is composed of several distinct attributes that detail different characteristics about an assembly. Each attribute is used in binding if it is provided. The allowed attributes follow:

 

·         Simple name

o   Format: string

o   Description: The name is the simple name of the assembly. It is essentially the name without all the other attributes

o   Note: The name should always be the same as filename minus extension

·         Version

o   Format: Four 16-bit integers separated by “.”

o   Description: A four-part version number (Major.Minor.Build.Revision)

o   Note: Each one of the 16-bit integers overflow at 165536 and underflow at -1

·         PublicKeyToken or PublicKey

o   Format: An 8-byte or variable length (48- to 2048-byte) string, respectively or “neutral” or “null”

o   Description: The public key token or key specifies the cryptographic signature of an assembly, guaranteeing that the assembly is from a particular publisher or set of assemblies (with that same token or key)

o   Note: The token is almost always provided instead of the much longer key

·         Culture

o   Format: string or “neutral” or “null”

o   Description: An arbitrary string that represents a culture installed on the system

·         ProcessorArchitecture

o   Format:  “MSIL” or “X86” or “X64” or “IA64”

o   Description: The processor architecture (PA) attribute specifies the requirement of a particular platform to execute a particular assembly. “MSIL” is an agnostic PA, as “MSIL” assemblies are allowed to be executed on any processor. All other PA options are “bit-specific” and must be run on a specific platform.

o   Note: PA doesn’t relate directly to processor or CPU. For example, X86 assemblies can be execute on X64 machines using the WoW64 infrastructure.

·         Retargetable

o   Format: “yes” or “no”

o   Description: The retargetable attribute specifies that an assembly can be retargeted to another assembly, meaning a reference to another assembly can be retargeted to this one.

o   Note: The retargeting mechanism is more complicated than described here, and is not at all a common scenario

 

Note: In all cases, the attributes and enumeration values are matched during binding case insensitively.

 

Textual Identity

The assembly identity can be specified in a string format, most often referred to as a “textual identity”. This form of the assembly identity is used by many APIs within the .NET Framework. There are also APIs that parse the textual identity string and return the identity back as a class, removing the need for developers to parse or create a textual identity string. More on that class later.

 

Textual Identity Specification

The specification of this format follows:

 

simple_name (“,” attribute “=” value)+

 

The textual identity starts with the simple name, and then a set of attributes and their values. Each attribute starts with a “,” and then its name, followed by a “=” and then a quoted or non-quoted value for that attribute. Whitespace can occur pretty much anywhere within the string, except within the attribute names, which are essentially tokens.

 

The allowed attributes, mapping directly to the components described in the previous section, are listed below:

  • Simple name à has no attribute name, requiring only its value
  • Version à “Version”
  • Culture à “Culture”
  • Public key or token à “PublicKey” or “PublicKeyToken”
  • Processor architecture à “ProcessorArchitecture”
  • Retargetable à “Retargetable”

 

 

The following characters can be escaped as part of the identity, with the escape character “\”:

  • t
  • r
  • n
  • \
  • =
  • U(HexChar)

Textual Identity Error Cases

The textual identity parser will error in the following cases:

 

  • The textual identity doesn’t match the correct general format (“,” attribute “=” value)+
  • The textual identity includes attributes that are unknown (i.e. foo=bar)
  • There is a value that doesn’t match a member of a given enumeration (i.e. “powerpc”)
  • A part of any version number under- or over-flows the integer

AssemblyName Class

The .NET Framework includes a class called System.Reflection.AssemblyName. An AssemblyName takes the textual identity in its constructor, parses the string and then provides access to each attribute of the identity via handy properties. The constructor throws if the provided string is invalid according to the specification provided above.

 

The term “assembly name” is sometimes used interchangeably with “assembly identity”. It is generally best to think of “assembly name” as the AssemblyName class, and “assembly identity” as the boarder concept of the multi-part name of an assembly as described earlier.

 

Strong versus Partial versus Weak Names

Up until this point, the assembly identity has been described as if all the parts always have to be there. That is not the case. There are essentially three categories of names, depending on how much of the identity attributes are specified.

 

Strong name

·         Simple name

·         Version

·         Culture

·         PublicKey or PublicKeyToken

 

Weak name

·         Simple name

 

Partial name

·         A weak name, or

·         Additional attributes beyond a weak name, but not enough to be considered a strong name

 

There are two other attributes: ProcessorArchitecture and Retargetable. ProcessorArchitecture is always optional, and just really makes a strong name more stronger. Retargetable is not commonly used.

Thursday, November 02, 2006 11:12:05 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer  |  Comments [0]  | 
# Thursday, October 26, 2006

The CLR loader offers a few APIs for loading assemblies, each of which have a slightly different model and behaviour for how they go about the task. I'd like to cover those and hopefully set folks on the best path for using loading assemblies.

The APIs that I have in mind are:

  • Assembly.Load(), and
  • Assembly.LoadWithPartialName()

First, you need to understand the concepts of fully-specified and partial assembly names.  A fully specified name contains the following parts: the simple name, version, culture, and public key or public key token. A partial name contains at least the simple name and optionally any of the other parts of the full-specified name. This concept is most relevant to the textual identity of an assembly. For example, here is the fully-specified assembly textual identity for v2.0 System.dll: "System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089". The textual identity is a specially formatted string that is used to describe some or all of the aspects of identifying an assembly.

Assembly.Load() takes a string as one of the overloads. The textual identity, as you see formatted above, is just the sort of string that Load() is expecting. Load() also takes other types, such as AssemblyName, but that's not important for the moment. The textual identity can be fully or partially specified, and which one it is has an important impact on the way that these loader APIs operate. The one you see above for System.dll is fully specified, since all the parts are there. Note that there is an additional part (or attribute) of the textual indentity that I've missed -- ProcessorArchitecture -- but that complicates the discussion too much for not much benefit, so I'm not going to cover it here.

The following bit of code shows the use of these APIs with full- and partially-specified names. The comments inline should pretty well explain what to expect

using System;
using System.Reflection;

namespace BindingByIdentity
{
class Program
{
static void Main(string[] args)
{
Assembly asm;

//LoadWithPartialName() looks in both the appbase and the GAC, looking for the best match,
//where "best match" isn't very clearly defined
//In addition, this method has been deprecated, which means "don't use this anymore, and it may be removed later"
try
{
Console.WriteLine("Calling LoadWithPartialName");
asm = Assembly.LoadWithPartialName("System");
Console.WriteLine("Loaded: {0}",asm.FullName);
}
catch(Exception e)
{
Console.WriteLine("LoadWithPartialName threw with the following exception:");
Console.WriteLine(e.Message);
}


//Load() with a partial name looks only in the appbase
//There is no gaurantee that you will get the assembly that you want
//In the case that you have private bin paths specified, there are no order gaurantees
//This particular use of the Assembly.Load() will always throw, since this assembly will not be found (because it is GAC'd)
try
{
Console.WriteLine("Calling Load");
asm = Assembly.Load("System, PublicKeyToken=b77a5c561934e089");
Console.WriteLine("Loaded: {0}", asm.FullName);
}
catch(Exception e)
{
Console.WriteLine("Load threw with the following exception:");
Console.WriteLine(e.Message);
}

//Load() with a fully-specified name looks in the appbase and the GAC and gaurantees that you
//will get the assembly that you asked for
try
{
Console.WriteLine("Calling Load");
asm = Assembly.Load("System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089");
Console.WriteLine("Loaded: {0}", asm.FullName);
}
catch (Exception e)
{
Console.WriteLine("Load threw with the following exception:");
Console.WriteLine(e.Message);
}


}
}
}

Output:

Calling LoadWithPartialName
Loaded: System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
Calling Load
Load threw with the following exception:
Could not load file or assembly 'System, PublicKeyToken=b77a5c561934e089' or one
 of its dependencies. The system cannot find the file specified.
Calling Load
Loaded: System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089

The moral of this story is that Assembly.LoadWithPartialName() is always bad and shouldn't be used since its behaviour isn't well-defined or predictable, and that you should always fully-specify the textual identity strings that you pass into Assembly.Load(). It may be the case that partially specified strings "work" since the assemblies you are attempted to load are always going to be in the app-base, but the fully-specified names do make your code and your intentions more clear, particularly for the next guy that has to look at the code you wrote. The funny thing is that sometimes "the next guy" is you, just two months later ;)

There is also the case that your code might not be strong-named. You should still specify everything but the publickey/token in that case.

Thursday, October 26, 2006 7:43:59 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Wednesday, June 21, 2006

I did an interview with my buddy John Bristowe a while back. You can hear me largely talking non-sensically about the CLR and at Developer Night in Canada. If you read Joel Pobar's blog too, then you hear me taking that guy down. Sorry Joel.

I really like the program that John's got going there. I couldn't believe how fancy the intro sounded. I'm now trying to get other Canadians at Microsoft to do interviews with John. Let's see where that leads. I hope that we'll have something in the later summer, as John made it sound like he'd be taking the summer off.

Wednesday, June 21, 2006 10:51:08 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [5]  | 

I've heard "convention over configuration" a number of times, largely in reference to Ruby on Rails. It's actually a really interested concept. It is simple in nature, and those kind of concepts are always the best. As an aside, I think I'm done with complicated concepts at this point ;) The question is where does the CLR loader lie w/rt CoC and is that the correct place to be.

I can tell you right away that the loader and binder are way, way over on the side of configuration. And the default behaviour -- the behaviour you get before you need to get into configuration -- is only useful for basic scenarios. Let me offer an example if this is seeming a little too vague. So, you've got assembly A (A, Version=2.0.0.0) and then you want to service it, giving us A' (A, Version=2.0.0.1). That's all good and seems to make sense. It makes sense to increment the (managed) version number to differentiate the two versions of the assembly. The only problem is that apps bound to A (A, Version=2.0.0.0) will still load 2.0.0.0 and not 2.0.0.1 (assuming A and A' were in the GAC).

Hmmm ... where does that leave us, since that's not quite the behaviour (read:convention) that we wanted. Well, we get to configure. Here are the choices available to us: re-compile all apps out there with A', configure (app.config) all apps to bind to A' or generate and install publisher policy to centrally configure all apps to bind to A'. And there is one more option still available that differs from the rest: don't change the (managed) version number in the first place to better conform to the loader convention. Ughh!

Hmmm again ... none of that sounds too good. So, what does Microsoft do, since you'd think that they are going with the better option or maybe have some secret hidden option for their use alone. Well, we (for the most part) go with not changing the (managed) version number when we service our binaries, thereby conforming to the convention. Pretty crappy, eh?

The good news is that we're moving much more toward convention-based approaches for v3. There will still be plenty of configurability via XML, but the vast majority of cases should just fall out of convention. Yeahh!!

This sort of thing really does make you need to stop and think. Are the default behaviours correct? Do they cover enough of the common scenarios? Do they address those common scenarios deeply enough? There's nothing worse than software that covers a lot of scenarios, but only 50% deeply enough in each. 100% enough in each is where I'm headed.

Wednesday, June 21, 2006 9:30:11 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [1]  | 

I've been running an early adopter program for a couple months now for a bunch of changes that we're making to the CLR binder/loader in the CLR v3 timeframe. The changes are related to the binding model, versioning, servicing and an add-in model. Also, just to be clear, this isn't .NET Framework v3.0 (AKA WinFX). This is the one after that. Here is the blurb that I sent folks who I thought might be interested. Please @ mail me if you are interested in participating.

We have been busy designing some exciting new changes to the CLR loader/binder. We'd like to start collecting feedback from customers about our change early, in order to ensure that the final product is rock solid. The first phase of the program is to validate that our changes are useful and to understand the compatibility of these changes. In order to collect this information, we’d like you to run two tools on your system so that we can learn more about how you – actually the managed apps you use – use the loader and GAC. The one tool is a tool that collects very basic information about the GAC, while the second tool is actually an instrumented CLR which logs data about how the loader, binder and domains are used. The next phases involve running a prototype version of the CLR that includes the new changes, but we’ll get to that later, as it comes available.

There are also a couple legal documents to sign, specifically an MSFT NDA and a license. I'm happy to discuss those if you want to go to that stage.

Wednesday, June 21, 2006 1:38:12 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  | 
# Tuesday, June 20, 2006

Well, I managed to get the blog back up -- now that my readership has hit zero. I haven't posted in 6 months and its been down for 3. That's a pretty impressive record. Hopefully most other parts of my life are in better shape.

The short version of why it was down was that my ISP moved to partial trust for security reasons and dasBlog requires full trust. They gave me lots of warning and I didn't do anything (read:my fault). I've since moved to thinkjot, which is a derivative version of dasBlog that fixes exactly those partial trust problems. Thanks go to the folks at thinkJot.

In the past six months, I've also moved to a new (to me) house and had a second child. It also turns out that my job is probably changing a fair bit (but in a good way and still on the CLR team). Excuses, excuses ...

Updated: This post in a .Net forum is awesome. If you call having a second child with lots of laziness and procrastination added in "abducted by aliens", then "yes".

Tuesday, June 20, 2006 9:02:13 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer  |  Comments [0]  |