...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
Related
I'm developing modular application using WPF and Prism.
All my UserControls have separate assemblies and implement IUserControl interface.
I would like to list all Types which implement IUserControl interface form a loaded module library in this way;
//ModuleA.cs
var interfaceType = typeof(IUserControl);
var userControlTypes = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => interfaceType.IsAssignableFrom(p) && p.IsClass);
But I cannot see all UserControl types implementing IUserControl in userControlTypes list.
When I use the all classes that implements IUserControl in Bootstrapper.cs like in the following;
var userControlTypes = new List<Type>()
{
{typeof(HastaKayitControl)},
{typeof(ViziteUserControl)},
{typeof(DenemeUserControl)},
...
};
I can get all desired UserControls from the list just I wrote above(userControlTypes).
What is the reason behind this?
FYI:
All assemblies target the same .NET framework version.
My Prism version is 6.1.0
I will use userControlTypes to show all UserControl types inside the application to the end-user.
IUserControl interface contains nothing.
This behavior is by design. The .net CLR will not load in an assembly unless it is called/entered which forces it to be loaded. Imagine the startup cost of running an app if every .dll file in the directory were loaded into memory when the application started as opposed to when a type was referenced at run time for the first time, some apps with large libraries would have load times of minutes (maybe even more?). Also it would not be realistic because some types are resolved to libraries outside of the execution folder like assemblies that resolve to the GAC.
In your first example AppDomain.CurrentDomain.GetAssemblies will only return the loaded assemblies, not all the assemblies, in that application domain. To see this you could add a {typeof(ViziteUserControl)} (taken from your next code part) and place it right above it, this will force the type (and containing assembly) to be loaded by the CLR and now it (types containing assembly) too will be returned by AppDomain.CurrentDomain.GetAssemblies.
In your next code fragment your code is explicitly entering these assemblies and adding the types. I do not think this requires any explaining.
So if you want AppDomain.CurrentDomain.GetAssemblies to load all your types across your application you need to force the assembly to load into memory if it has not already done so. Depending on your structure you could do this a couple of ways.
Iterate through the .dll files on disk (using a reference location like Assembly.GetExecutingAssembly.Location) and call Assembly.LoadFrom. Use wild cards to ensure you are only loading your assemblies and not every .dll library you are encountering.
Reference interested types in a configuration file and load them from there. You can use Type t = Type.GetType(yourConfigType); when creating your list of types from your configuration string list.
Reference interested assemblies in a configuration file and load in the DLL in the same manner as option 1.
Just hard code the list as you did in your last example.
If you choose option 1 or 3 you will have to check to make sure you have not already loaded the assembly in memory before you call Assembly.LoadFrom. You can do this by again checking what is already loaded with AppDomain.CurrentDomain.GetAssemblies().Any(x =>your search query).
Also Note that once you load an assembly into your application domain you cannot unload it for the life of that application domain. If you do not want this but you still want to dynamically find all your types you will have to create a 2nd application domain to find all the types and return them as an array/list of fully qualified type name as a string. You can then unload this created application domain. Also, as correctly noted by #Peter below in the comments, use ReflectionOnlyLoadFrom if you go with this approach. This incurs much less overhead.
AppDomain.GetAssemblies() tells you the loaded assemblies, not the referenced ones. I can't speak to the Prism aspect of your question, and I agree with the comments that there is probably a better way to design this. But…
If you really want to enumerate all of the types that might get loaded in your AppDomain, you can approximate this by enumerating the types in the existing assemblies (i.e. as you've done here, with AppDomain.CurrentDomain.GetAssemblies(), but then for each assembly, call GetReferencedAssemblies()), which returns an array of AssemblyName values that you can use to load additional assemblies. For each of those, you can in turn inspect all of their types (to find the implementors of IUserControl) and to call GetReferencedAssemblies() to continue the recursive search.
Note that this still will not necessarily return all implementors of the IUserControl interface that your process might load. Assemblies can be loaded by means other than being referenced in your AppDomain's assemblies, such as by code searching a directory for candidates, or even the user explicitly naming an assembly to load. This is why using mechanisms directly supported by whatever API you're using is a much better approach, to make sure that you find exactly those assemblies that that API would find.
I am little confused about usage of Application class and AppDomain class.
For example Application.StartupPath is equal to AppDomain.CurrentDomain.BaseDirectory
I usually used Application class and recently discovered AppDomain - Can someone explain to me AppDomain class and its usage?
They have nothing in common, really.
Application is a class specific to Windows Forms, a .NET GUI technology. The Application.StartupPath is handled by the Kernel32 function GetModuleFileName. Through not passing a pointer to a module, the main module's path is returned - that is the exe file, basically.
AppDomain is a core .NET concept for domain isolation. Basically, it allows you to isolate (imperfectly of course) multiple applications in a single native process. Most applications only have a single AppDomain, but you can create as many as you like. The base path of an application domain is handled by Fusion, a .NET assembly loading technology. A very typical example would be ASP.NET applications hosted in IIS - each application has its own AppDomain, but they're all hosted in a single native process ("application pool"). Each logical application can be restarted without touching the others, and they don't have (simple) access to each other, but a process-tearing exception (e.g. StackOverflowException) will still kill the whole pool.
Another interesting class that's somewhat related is Environment. You can use Environment.CommandLine to get the process command line (which includes the path to the executable, including the name of the executable). This is basically a communication interface between the CLR and the underlying system - in this case, it takes care of saving the arguments for the application (which are passed by the OS to the Main function) and making them available at any time in the future.
Environment.CommandLine is somewhat clunky to parse (it's the raw command-line, basically - I assume it will have different conventions on Windows than on Linux, for example), but it's the only way you can always get to the executable. Again, Application.StartupPath is Winforms specific, and you can have more than one AppDomain - and possibly, the AppDomain might not even have a reasonable BaseDirectory.
The .NET Reflection APIs also give you a few ways. For example, Assembly.GetEntryAssembly() will give you the executable assembly - however, this only works for the main AppDomain - other domains will have their own entry assemblies (in fact, they'll usually just return null :)). You can get the path to an assembly through the Assembly.CodeBase property, but do note that this might not always be what you expect. You can also use Assembly.Location, or get the FullyQualifiedName of any of the assembly's modules (again, most assemblies only have a single module; and again, ASP.NET is one of the prime examples of when this isn't the case).
I am attempting to use the Razor view engine as a general templating engine backed by a database.
http://razorengine.codeplex.com/ The problem is that for every template compilation a new dynamic assembly is created and loaded. As there is no way to unload an assembly from the current appdomain and no way to use a separate appdomain for the templating system (use of anonymous types) these assemblies will keep accumulating until the appdomain is destroyed. The templates themselves will change on a regular basis and as such will result in more recompiles.
The question is will these dynamic assemblies (potentially thousands) hurt the appdomain performance? Or alternately is there a better way to do this?
In general having many small assemblies loaded in the AppDomain shouldn't be something to worry about too much. The only general statement anyone could make about this is to measure the actual performance of the app in the relevant scenarios and then see if it matters.
ASP.NET has some automatic app lifecycle management that will recycle the AppDomain after certain events. For example, if there are too many recompilations in the app then ASP.NET will automatically restart the app. This means that all the previously loaded assemblies will be cleared out and you start from scratch.
See MSDN for more info: http://msdn.microsoft.com/en-us/library/s10awwz0.aspx
numRecompilesBeforeAppRestart
Optional Int32 attribute.
Specifies the number of dynamic recompiles of resources that can occur before the application restarts. This attribute is supported at the global and application level but not at the directory level.
Note
ASP.NET increases the NumRecompilesBeforeAppRestart property every time an assembly is invalidated and fails to be deleted.
The default is 15.
I have a program that utilises a plugin architecture. When the inital form loads, it scans the current directory, queries each dll and obtain some basic data which is displayed to the user.
Whilst using the program, the software will often need to ask the dll's to perform some work.
My question is, when the program initially checks the dll files, should I keep a reference to each dll object for future use, or should I query the dll files each time and create the object as and when needed?
if it's the first one, what is the best way to keep a list of an undetermined number of objects that derive from a common interface and then know which one to refer back to when needed?
Thanks.
Using the first one you could just create a
List<IYourCommonInterface> pluginDlls
and then just
pluginDlls.Add(dllReference);
Edit
Alternate method using a Dictionary, note that this will require you having some kind of ID for the dictionary that you can make use of to id the dlls.
Dictionary<SomeIDField, IYourCommonInterface> pluginDlls
pluginDlls.Add(dllRefrence);
Most apps do the check on load.
I wouldn't store the list of interfaces. If you do store them then you run into the possibility that the assemblies either disappear or are updated in some way. At which point you need to "refresh" them anyway.
Once you've loaded the assembly and gotten an instance of System.Reflection.Assembly for reflection (using Assembly.Load(), Assembly.LoadFrom(), Assembly.LoadFile(), etc.), the assembly is loaded. To quote MSDN on the subject:
...it is...possible to load specific assemblies into the current application domain
at runtime...There is no way to unload an individual assembly without unloading
all of the application domains that contain it. Even if the assembly goes out of
scope, the actual assembly file will remain loaded until all application domains
that contain it are unloaded. [emphasis mine]
So if you want to unload the DLLs until such time as you actually need them, you're going to have to create a new app domain and then unload that. Its easier to just load them and have done with it. You can keep the assemply reference around if you like, but if you call Assembly.Load() again, it won't actually load the assembly: it'll just get a reference to the previously loaded assembly.
If you've gone through the trouble of finding and loading the DLLs, normally you'll want to keep them around. This would depend mostly on how many resources the DLLs use and how your app is using the DLLs.
I'm assuming you're using LoadAssembly here. You can just store references to the assemblies you've loaded using some kind of map. Or even a list that you iterate through.
Perhaps if you give some more details we can help you better.
I have the following situation:
multiple virtual directories under same application pool in IIS
copy of same DLL in all those directories (same version number)
a singleton class in one in this DLL
The question is, is this singleton class created only once for all those Virtual Directory instances or is there for each of these directories a separate singleton class.
The code looks something like this:
[
Transaction(TransactionOption.Supported),
ClassInterface(ClassInterfaceType.AutoDispatch),
Guid("7DE45C4D-19BE-4AA4-A2DA-F4D86E6502A8")
]
public class SomeClass
{
private static readonly Singleton singleton = new Singleton();
A singleton will be created for each application using it. Each application is separated from each other, because they each exist in their own application domain.
To have a truly singleton class across different applications, you'll need to have them communicate to a common application holding the information (like through remoting or WCF etc.).
The application pool controls how much memory and processor(s) applications in that pool can access (along with the account the programs run under). They are still separate from each other.
In IIs each virtual directory has a single application associated with it. An application does not share memory space with other applications so there will be a new instance of this class for each virtual directory.
You can create a shared application pool which all these applications will use. However, in this case the memory will be shared but each will get a unique process using that memory and each unique process will load the class.
Loading an Assembly (DLL) from different locations into the .net CLR (even an identical copy of the same file into the same process (*)) the CLR treats each of these as separate Assemblies ... so the types in these assemblies - whilst syntactically identical (even in namespace terms) - are still different types!
So even if they were in the same application context (OS process) the singleton would not be a single common instance across the callers (you would have three separate static instances of the same class). Also: an Application Context is defined as having a base path (in the ASP.Net case this is the virtual directory) ... further evidence that the web applications all run in separate processes (Kevin is right).
Just a general point (perhaps off the topic of your question) about copying DLLs, though: the Global Assembly Cache (GAC) comes with different challenges ... but the CLR response to "DLL hell" is to treat every different file (identical copy or not) as a separate assembly ... use the GAC - I would strongly advise against copying assemblies into multiple places on a single machine. If nothing else: such file copying is a deployment nightmare. The GAC comes with all sorts of powerful version management utilities to boot (check out: GAC binding policies).
Hoping to help with your long term solution ...
Aidanapword
(*) this can be done using Reflection ... not a good idea but it happens.
First a note - when you run under IIS 6 and 7, AppDomains can be in separate worker processes if you allow IIS to use multiple processes per AppPool. To put it in proper historical context, AppDomain just emulates what IIS AppPool mechanism would do to any binary. Allows for a lot of scalability and in many cases it doesn't really matter if you have a few copies of a "singleton" - that can improve perf as well.
If you really, really, and I mean really :-) have the need for a server-level singleton there is a way to do it, without paying the cost of remoting, but only if you know your COM or WinNT API.
WinNT route will be the lightest resource-wise but you'll have to do complete WinNT work to the point that you'll start asking why are you still in C# and not C++ - shared memory, events or WinNT mutexes etc.
COM route will require you to force out of proc invocation (proper registry keys) and you may want to go with AutoDual instead of AutoDispatch - first to buy perf and second to make sure that .NET has the minimal chance of trerating that dll as "it's own". The gola is to make it look and quack like any other out of proc COM
Important question to ask yourself is - why do I actually need it? Very different tactics needs to be used if the purpose is caching, vs. fast event processing (in which case MSMQ will serve well - it's now under WCF umbrella).