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).
Related
Recently i discover that running few instances of method compiled to .exe is faster than running the same method in f.e. few new Tasks. I don't know if that applies to every method, but it does to getting data from API.
I was searching internet to find answer how to manage that. I got answers to try run method in new appDomains. So i create .exe assembly with methods that i want to be run (it is Console application). I Load it by right click on References -> Add Reference. I could easily access that method by exeName.ClassName.Method(params). The thing is that I don't know how to run this methods in new appDomains. Every answer that i found in web was with loaded assembly by path.
I will also be very happy for answers other than creating AppDomain. I just want to pass data to this method and get results.
TL;DR: Method run in Parallel.For(0,4,i=> method()) works slower than run the same method in 4 instances of compiled .exe file.
You could use a multi process architecture using IPC protocol or host your methods inside different domains. In both situations i recommend .net remoting over wcf because you would write almost the same code for both aproaches and because for talking to a class found in another app domain hosted in the same process, .net remoting is the only way (sadly for many devs but not for me). BUT I am almost sure that generally this would NOT be more faster than just creating some threads and calling them asinchronous. Inter domains / process communication must rely on message serialization/ deserialization that adds huge overhead, specially if the method call itself is very light.
After some researching and asking i found solution:
var ad = AppDomain.CreateDomain("mydomain");
ad.DoCallBack(() =>
{
//stuff to do
}
Probably there'll be some issues with passing data to new AppDomain. Easiest way for me is:
ad.SetData("key", value);
and to retrive in AppDomain:
var value = (valueType)AppDomain.CurrentDomain.GetData("key");
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 writing a Web Service in C# and am an outright novice. Please pardon me if what I have asked is dead silly. I have a set of dlls that the Web Service uses. What I want to achieve is as follows:
Let us assume that the dlls are first.dll, second.dll and common.dll
common.dll is referenced in first.dll and second.dll (common.dll contains interfaces that are implemented in first.dll and second.dll)
common.dll has a static dictionary of the types of classes contained in first.dll and second.dll. Classes from this dictionary are instantiated as required.
Whenever I have a new common.dll ready for release, I want to manually delete the common.dll file and replace it with the new release of common.dll while the system is live/running.
Presently, I am getting the following error when I am attempting to perform step 4:
"This action can't be completed because the file is open in vshost32-clr2.exe"
It is so that I am missing something completely?
24/7 availability is not a cheap thing - do you really need one?
One of easy approaches is to re-route traffic to different servers when you upgraded your application. You get both servers running and verified that new one is OK and than switch traffic to go to new one. You can use DNS entries or some software/hardware router to redirect traffic.
If you really want to replace assemblies on the fly you can do that. You may need enough layers of proxy objects and potentially load your final assemblies in custom app-domain. You may be able to get away with simply copying DLL to root folder of Web Site on IIS and hope that app-domain recycle will work correctly and satisfy your "always live" requirement.
Note: "manually delete" and "the system is live/running all the time" should not appear together for the same system... unless you know of a person who can flawlessly perform the same boring tens of steps multiple times at any time of day...
You have to shut down the hosting website. Copy in the new assembly. Then restart the website.
Ok here is the problem, I have a winform application that relies heavily on static variables and it being a singleton application (only one instance of the process at a time).
I now need to create a wrapping application that would create say 6 of those winform applications and switch between their primary windows. The reason for doing it this way, is that these applications have a lot of static references that must be updated depending on what database they are connected to. Our users need to connect to several databases now and re-engineering the code to get rid of the static issues is NOT an option.
So my question is this, I know I can create new app domains in one process, but do each of those app domains get a new set of static references? Or do I actually have to have separate processes? If so, how could I go about building an new application that would create 6 instances of the old application and communicate data to each one of them (things like Hide/Show, load this object, query this database, etc...) Looking for something simple as this is going to end up being a throw away project.
Thanks!
Each app domain has its own set of loaded assemblies (except domain-neutral assemblies, which are shared between domain) and types. Each type in the app domain has it's own instances of static variables (in case of domain-neutral assemblies CLR provides this in special way).
...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