static objects / multiple app domains / one process - c#

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).

Related

How to run method from assembly loaded to references, in new AppDomain

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");

how create windows global variables in c# winform

(at first i say that use C# with winform and .Net Framework4)
is there any way to create a class library (dll) with static variables and get variable from some programs as concurrent (and static variables does not reset for each program).
more explain:
for example i create a dll with static variables and install on GAC then add to reference of tow my program.
now i want set variables in Program1 and get variables on Program2.
how can do that?
basically you can accomplish by
storing value in a storage accessible from different programs
using some process to process comunication mechanism (IPC mentioned by #SLaks)
storages that comes to my mind could are: database, windows registry, settings file
process to process communication may be WCF, or System.IO.Pipes, or others: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365574(v=vs.85).aspx
it all depends on your needs. Is it performace critical? Do you need to infrom the other process that value has changed, or the other process will just request the value? How many processes will access the value at the same time?

What are the steps for making domain-neutral assemblies?

...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

Singleton class in DLL used on multiple virtual directories

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).

How to handle static variables in a library that is used both for desktop and web?

I have some C# library classes that make use of static variables. I use these library classes both for desktop and web applications. Problem is, as I just discovered, static variables don't go down so well on a web server; the values are shared across all sessions using the web site!
How can I preserve the features of a static variable for use in my desktop apps, while making sure that each session on my web server has its own independent values for these variables - but within the session itself, it still really behaves like a static?
Static variable values are shared across all threads in an application domain. In an ASP.NET application the recommended way to store data that's related only to the current user is the Session.
If you can modify the code of this shared library I would advise you to extract an interface out of these static variables that will provide a mechanism to store values. This will allow each application to provide its own implementation. For a windows application you could use an implementation that internally uses a static variable. For an ASP.NET application you could use the Session. But in all cases you expose only an interface. This will also have the positive side effect of rendering your code easier to unit test.

Categories

Resources