GAC Registration

Problem
You want to know the pros and cons of registering your DLL assemblies in the GAC.

Solution
The pros of registering are 1. The .NET runtime finds GAC assemblies more quickly and loads them faster because it doesn’t have to check their integrity. 2. Assemblies in the GAC are protected from accidental deletion because only an administrator can access the GAC directory. The cons of registering are 1. More complicated deployments since you can’t rely on XCOPY to automatically register the assembly for you. 2. Having to uninstall the previous version from the GAC each time you recompile.

Comments
You don’t want to use the GAC if your sole purpose is to share types among different applications; there are better ways to accomplish this goal. You can share an assembly, including private ones, among different applications if all applications’ executable files are deployed in the same directory. Or, using a different approach, you can reference a strong-named assembly that is located outside the application’s main directory by using the element in the application’s configuration file.

Additional details
There are ways to make GAC registration simpler. There’s a utility named Gacutil that comes with the Windows SDK and is automatically installed with Visual Studio. If you’re not a Visual Studio user like me, you can simply get it with the Windows SDK. You can configure Gacutil to run as a post-build event. In Visual Studio, you can configure the command to run in the Project Properties dialog box. Otherwise, you can add it to the .csproj file like so:

<Target Name="AfterBuild">
    <Exec Command="Path to SDK\...\Gacutil.exe" /i $(TargetPath)" Condition="" />
</Target>

Culture Attribute for Main Assembly

Problem
You want to know the best way to mark your main assembly for a given locale.

Solution
Use the NeutralResourcesLanguage attribute on the main assembly. This will inform the resource manager about the language for neutral resources that are embedded in the main assembly.

Comments
Using this attribute speeds up resource loading when the current user’s locale matches the culture used for resources in the main assembly. Don’t use the AssemblyCultureAttribute in the main assembly. The main assembly should only contain neutral resources (for example, strings and images related to the default language).

Example

// This particular assembly contains resources for the US English culture.
[assembly: NeutralResourcesLanguage("en-US")]

Resources in .Resx Files

Problem
You want to know the benefits of using resource (.resx) files.

Solution
Resource files provide a simple way to localize your .NET applications by automatically determining the .resx file to use based on a user’s locale. In addition, resource files provide a central location to store strings, files, and other scripts that can be referenced in a strongly-typed way. Another advantage is they can be compiled into satellite assemblies, making them easier to modify in a production environment.

Comments
String resources are great for error messages and user interface elements. Use them for human-readable text and not constants to be accessed programmatically.

Manifest Resources vs. Stand-Alone Files

Problem
You want to know when and how to embed resources in your project.

Solution
You should favor using embedded resources for read-only data that will never change during your application’s lifetime. Use separate files to store data that the application can change or that you may want to deploy independently of the main application.

Pros & Cons
Resources that are embedded in the main assembly’s manifest can be located and loaded faster. They are also protected from accidental deletion. This technique is not best used when you have resources that are locale-dependent and should be localized for each language you support.

How-To
You can embed any data file in the assembly’s manifest by following these steps:
1. Add the file to the project.
2. Right-click the file and choose Properties.
3. Set the Build Action to Embedded Resource.

Example
The following code demonstrates how to programmatically access a text file named TestData.txt from inside an assembly whose default (root) namespace is TestAutomation.

string dataFile = "TestAutomation.TestData.txt";
// Get a reference to the assembly.
Assembly assembly = Assembly.GetExecutingAssembly();
Stream stream = assembly.GetManifestResourceStream(dataFile);
// Read the contents of the embedded file and close it.
StreamReader reader = new StreamReader(stream);
string text = reader.ReadToEnd();
reader.Close();

Assembly Versioning

Problem
You want to know how to version your assemblies and any potential pitfalls.

Solution
Edit the AssemblyVersion(“1.0.0.0”) attribute in the AssemblyInfo.cs file, and give the assembly a specific version number. Change the version number when you publish a new version of the assembly.

Comments
Specifying a version number is important because it gives the assembly a strong name. One gotcha: If you use an asterisk in the version number, the version number changes each time you recompile the assembly. As a result, all client assemblies have to be recompiled and the identity of any enclosed types will change. Further, this will lead to problems when deserializing an object that was serialized by a previous version of the same assembly.

Example

// Incorrect. Uses an asterisk.
[assembly: AssemblyVersion("1.0.*")]

// Correct. Remember to change as needed.
[assembly: AssemblyVersion("1.0.0.0")]

Multi-module Assemblies

Problem
You have more than one module and are considering merging it as one assembly. Should you do it?

Solution
Avoid multi-module assemblies. In most cases, you can deploy an application as one main EXE plus zero or more DLLs without creating multi-module assemblies.

Comments
Compiling multi-module assemblies requires using the Al.exe command-line tool, and this slows down the build process. The main advantage of having a single assembly composed of multiple modules rather than multiple distinct assemblies is that types marked as internal are visible to types in other modules. If you have distinct assemblies, you must mark these types public to make them callable by another assembly. However, in this scenario, you can’t easily prevent other assemblies from using your types. Multi-module assemblies are required when you have to merge modules written in different languages into one assembly. But, in such cases, you should consider splitting the application into distinct assemblies (one per language).

Size of Assemblies

Problem
You want to know how large your assemblies should be.

Solution
In general, prefer few large assemblies to many smaller ones. If you have a group of types that are always loaded and used together, place them in the same assembly. If you have two or more assemblies that are always loaded and used together, merge them into a single assembly.

Comments
The .NET runtime loads a large assembly faster than several smaller ones. A single, larger assembly creates a smaller working set of the application, and Ngen.exe can optimize it more effectively. On the other hand, you may need to split a larger assembly into several smaller ones if the types in it need to be assigned different identities or trust levels.

Strong Names for Assemblies

Problem
You want to know the benefits of strong-named assemblies.

Solution
Strong-naming creates a unique identity for an assembly and can prevent assembly conflicts. Always sign DLL and EXE assemblies with a strong name.

Comments
Specify the path of your company’s .snk file in the AssemblyKeyFile attribute in AssemblyInfo.cs. You can generate the .snk file holding private and public keys of your company by running the Sn.exe command-line tool.