...and can those steps also be applied to a 3rd party assembly (that might already be strong-named)?
The context for my question should not be important, but I'll share anyway: I'm thinking of making a logger (or log-wrapper) that always knows what "log source" to target, regardless of whether the assemblies using it are in one appdomain, or spread across several appdomains. I think one way to achieve that, is to have a domain-neutral assembly with a static "LogSource" property. If that static property is set in a domain-neutral assembly, I think all appdomains will see it.
Assemblies aren't marked as domain-neutral in any specific way. You don't have to give them some specific attribute to make them domain-neutral. Any assembly can be loaded by the CLR either into the shared domain or the domain that triggered the assembly load depending on the configuration of the CLR instance that is loading the assembly.
How the CLR instance decides to load an assembly is dictated by policy. There are several ways to explicitly set this policy:
- set LoaderOptimizationAttribute on your executable's entry point (usually Main). The CLR loader will apply the specified policy when starting the executable.
- set the AppDomainSetup.LoaderOptimization property when creating a new app domain from managed code.
- CorBindToRuntimeEx - when starting the CLR from unmanaged code, this function allows you to specify start-up flags, some of which control the loader optimization.
An assembly loaded as domain-neutral will be loaded into the shared domain. The app domain name is "EE Shared Assembly Repository" in CLRv4. That's not a real app domain, because it has no data and can't run any code. Assemblies loaded into it will share its code among all other running app domains. The byte code in the assembly will be JIT-compiled only once. All mutable data in the assembly, however, will be duplicated among the running domains. Static fields are not shared between app domains. Per-app domain static fields will be duplicated and different app domains will read and write in different places in the memory when referring to the same static field.
Aside: there is another kind of static fields - RVA statics, that are shared among all app domains in the current process. There is no way to declare such a field in C#, but it can be done in C++/CLI.
There is a trade-off in using domain-neutral assemblies. Access to static fields is slower. Since they're JIT-ted only once, but may access multiple instances of a per-app domain static field, any access to a static field goes through an additional indirection. When an assembly is loaded straight into the running domain, the address of the static field can be directly embedded into the JIT-ted code. However, when code compiled into the shared assembly tries to access a static field, it must first load the current domain's context and then find in it the static field address for this domain.
The decision whether to load an assembly into the shared domain or into the running domain depends on your use case, more specifically how many app domains you'd create and what sort of core you'd load into it.
- If you load multiple domains that run essentially the same code, you'd want to share assemblies as much as possible, unless it's significantly hurting the performance of accessing static fields. An example is an application that decides to run portions of its own code in a separate app domain for the sake of isolation.
- If you load multiple domains with different code, you'd want to share only assemblies that are likely commonly used by all the different assemblies. These would usually be the .NET Framework's own assemblies and all assemblies loaded from GAC. IIS works this way by default when running ASP.NET apps.
- If you ever use only one app domain, you shouldn't share anything. A regular GUI application will be like that.
Note: mscorlib is always loaded into the shared domain.
Sources and further reading:
- Application Domains and Assemblies
- Domain Neutral Assemblies
- Essential .NET, Volume 1, Addison Wesley; chapter 8 "AppDomains and Code Management"
Domain-neutral assemblies share only code across appdomains. However, data is still per-appdomain. Thus, there will be one copy of your static LogSource
property for each domain.
Actually there is one tricky, undocumented, way to share data across domains, but it can cause runtime errors and whole application crash. Author don't recommend using it in real projects, so you can use MarshalByRef objects instead, to share log consumer.
But you can share it using that tricks too.
http://geekswithblogs.net/akraus1/archive/2012/07/25/150301.aspx