Workaround .net application domain only passing objects by value - c#

I am developing an .net application which heavely depends on plugins. The application itself contains an connection to a remote server.
Recently I digged into Application domains and see them as the ideal solution for isolating the plugin code from the rest of the application.
However there is one big disadvantage which makes me unable to implement the application domains for hosting the plugins. It seems there is no way to pass an object by reference to another application domain which is needed to pass an reference to the connection object.
I was hoping someone could give me a workaround so I can pass an reference to that object.
Note: Creating a proxy is out of the question, the connection layer already acts as a proxy since the classes are auto generated.
Note2: System.AddIn can not be used as it is not available on the compact framework.

Have you tried deriving from MarshalByRefObject? It's a pain in that it screws up your inheritance hierarchy, but I think it's what you want.
From the docs:
MarshalByRefObject is the base class
for objects that communicate across
application domain boundaries by
exchanging messages using a proxy.
Objects that do not inherit from
MarshalByRefObject are implicitly
marshal by value. When a remote
application references a marshal by
value object, a copy of the object is
passed across application domain
boundaries.
MarshalByRefObject objects are
accessed directly within the
boundaries of the local application
domain. The first time an application
in a remote application domain
accesses a MarshalByRefObject, a proxy
is passed to the remote application.
Subsequent calls on the proxy are
marshaled back to the object residing
in the local application domain.
Types must inherit from
MarshalByRefObject when the type is
used across application domain
boundaries, and the state of the
object must not be copied because the
members of the object are not usable
outside the application domain where
they were created.
In my experience, it can be pretty limiting - you really need to do as little as possible across the AppDomain boundary, preferrably restricting yourself to operations which only require primitive types, strings, and arrays of both. This may well be due to my own inexperience in working with multiple AppDomains, but it's just a warning that it's a bit of a minefield.

To talk to the same instance between AppDomains, it must inherit from MarshalByRefObject. Done this way, every method call to the object (including properties etc) is actually a remoting call to the other app-domain. Does that help?

Be aware that clean-up of MarshalByRefObject proxies are cleaned up based on a lease. In short if you don't use the object for a specific time it will be reclaimed. You can control this by overriding InitializeLifetimeService to return a lease object which matches you needs. If you return null you effectively disable the leasing and then the object is only reclaimed when the AppDomain is unloaded.

Related

Library in the GAC used by multiple applications, does it share the same objects or not?

I have seen this in multiple questions, but so many of the accepted answers are contradictory.
Some say that only IPC can be used if you want to use a single instance (actually just a synced instance) of an object across applications and domains.
Others say that using a singleton pattern in an assembly in GAC will result in the data being shared because the GAC will share an instance if the DLL is already loaded by another assembly (providing the lib has a singleton pattern).
Somebody help me out and put this to rest, I need to share a Global object across multiple applications in multiple threads and need to know before I get too far into it if its even possible without IPC such as WCF. I would prefer to use the GAC as my library is more like a framework anyway that will be used by a suite of applications both developed by me and other 3rd party developers. Additionally speed is a major concern and serializing/deserializing an object to constantly sync it would probably add too much latency, would much rather it be a single instance referenced from multiple locations.
No, each instance of an application is using it's own memory for all loaded assemblies. It is even possible to separate two singleton instances within one application (by using AppDomains)
A singleton pattern can be used cross assembly, but this will always be within one AppDomain.
So two application doesn't share memory/object instances.
This is desired behavior, because you don't want other applications to access your Thread/Dispatcher/AppDomain(and load a custom assembly in your application)/Application class instances
If you need to 'share' memory or objects between applications, you'll need to serialize the data and 'transport' them over something like a communication layer.
For example:
TCP/IP
'Shared' memory (named pipes)
Files

How to get references to already instantiated remote objects using WCF?

I’ve just read Ingo Rammer's article titled “From .NET Remoting to the Windows Communication Foundation (WCF)”, on the MSDN website (http://msdn.microsoft.com/en-us/library/aa730857(v=vs.80).aspx).
I still have one doubt, though, and I hope someone can help me.
In session “Step 3 - Use Sessions instead of Client-Activated Objects”, which covers exactly the kind of use of Remoting we make here in our company, he has shown how to obtain and use references to remote objects instantiated on the other side (server’s side). However, in our case, we don’t instantiate these objects on the server’s side at the moment the client requests references to them. The objects already exist on the server’s side (they were previously instantiated), and I just want to get references to these already active objects.
How do we do this today, using Remoting? We have an “Object Server” object (which derives from MarshalByRefObject). This object is available through an URL “tcp://localhost:9002/ObjectServerInstance”. Remote applications can get a reference to it using Activator.GetObject. This Object Server object implements an interface IObjectServer, that declares a method with the following signature:
Object GetObject (string objTag);
Client applications use the reference to this Object Server object to call its GetObject method, passing an object tag string as parameter (Ex: “Portfolio”). This method then returns a reference to the Portfolio object, which has previously published itself before the Object Server object using this tag “Portfolio”. The Portfolio object also derives from MarshalByRefObject, of course. And it isn’t instantiated only when a remote client asks for a reference to it, it was already instantiated on the server.
Of course, this could be done differently. Each object that might be accessed remotely could programmatically use its own objectUri to publish itself before the Remoting layer on the server’s side (Ex: “tcp://localhost:9002/MyObjectInstance”), and on the clients’ side we could use Activator.GetObject directly to get each object’s reference. But this is irrelevant to the point I’m raising. Anyway, the server objects would already exist when they publish themselves before the Remoting layer.
Was I clear enough? Do you see a way to do this using WCF?
Looking at the code at the link you provided, it seems to me that you need to modify the GetInstanceMethod implementation of the IRemoteFactory interface to return an existing object, instead of creating a new one.
public interface IRemoteFactory
{
IMySessionBoundObject GetInstance();
}
public class RemoteFactory : MarshalByRefObject, IRemoteFactory
{
public IMySessionBoundObject GetInstance()
{
// Return an already existing object, instead of a new one.
return MyAlreadyExistingSessionBoundObject;
}
}
There is a solution to your problem, but be warned it goes against the grain of WCF and the concepts of service orientation.
Maintaining a sessionful state on the server has all sorts of ramifications and potential pitfalls. You introduce coupling between the client(s) and the server and have to think carefully what you will do in the case of corrupt state and exceptions.
The solution is a bit too long for a Stack Overflow post, so I've posted it on github here.
I can't claim any credit for the solution - most of it comes from a blog post I read somewhere (I'll update this once I remember what it was). It is interesting from the point of view that it uses some fairly advanced WCF low-level code - and it great for furthering your understanding on how WCF works.
I would further iterate that if there is anyway of avoiding implementing this in a production environment to go down that route.

Use .net remoting to call a local "remote"?

I have a large app which uses COM via .net remoting to call from the web tier to the middle tier.
It's quite slow to startup and to run when in this mode. Both sides of the COM boundary are our code.
I'd like to be able to (optionally) run it in a single process.
Quite a bit of the behaviour relies on calls to ServicedComponents having all their arguments serialized, and that changes made to the objects inside the components don't leak out unless the argument is a 'ref' argument.
My current plan to force this two-process app into a single process without needing to change too much code is by using a fake middle tier boundary with custom .net remoting.
If I change all the:
class BigComponent : ServicedComponent {
...
}
into
[FakeComponent]
class BigComponent : ContextBoundObject {
...
}
Then I can write a custom ContextAttribute to fake the process boundary and make the arguments serialize themselves:
i.e.
[AttributeUsage(AttributeTargets.Class)]
public class FakeComponentAttribute :
ContextAttribute,
IContributeServerContextSink
{
... lots of stuff here
}
As per http://msdn.microsoft.com/en-us/magazine/cc164165.aspx
Now this works fine, so far, and I can intercept all calls to methods on these classes.
However, I can only view the IMethodCallMessage.Args in the IMessageSink.ProcessMessage call -- I don't seem to be able to replace them with objects of my choice.
Any time I change entries in the IMethodCallMessage.Args array, my changes are ignored. From what I can tell in Reflector, this interface is a wrapper around a native object in the runtime itself, and I can't write to this object, just read it.
How can I modify the arguments to method calls in .net remoting?
Do I need to implement my own Channel? Is there a "local" channel tutorial out there I can crib from?
My aim is to have these Components act like remote objects (in that all their args get serialized on the way in to the method, and that their return value is serialized on the way out), but have the remote endpoint be inside the same process.
I have not found a way to edit the argument array as it passes through the IMessageSink.
In the end, I had to make the argument object classes aware of this issue, and implement a new interface IFakeRemotingAware. This allowed the complex object arguments which exhibit the pass-by-val behaviour due to serialization/deserialization when using remoting to simulate that behaviour when using fake remoting.
The interface has two methods: EnteringFakeRemote which causes the object to cache a local copy of its state, and LeavingFakeRemote which causes the object to restore its state from the cache.

Is there a way to pass and use an address of a reference type/value type across an app doamin? (C#)

I have an application and a set of plug-ins. They communicate across an app domain.
What I need is a way for the application to send an object (user defined or C# int, double, string, etc.) across the app domain boundary, allow the plug-in to edit it directly (i.e. the address, like a pointer) and then return and have the object keep the value as was set by the plugin.
Also, I do not want to have to use "Unsafe" code in my application.
Any ideas?
It's kind of the definition of an app-domain that you can't do this.
If you don't want to marshal the value of an object across the app-domain boundary, the best you can do is have some kind of callback for the plugin to set the value within the original app-domain.
Addresses can only be used in unsafe code. I doubt you can reachout side of your app domain.
You can create classes that inherit from MarshalByRefObject and it will create a proxy for you to use.
Not as such - the app domain is quite a strict boundary. You would need to code a wrapper layer to pass the serialised object across and set the object on the original side to the value passed back.
Inherit your class from MarshalByRefObject. Then it can be called via appdomain boundary. But if you use your class directly you'll get the assembly loaded into your main domain. To avoid this create an interface and put it in your main assembly or some third assembly. And get the reference to this interface instead:
AppDomain domain = AppDomain.CreateDomain("MyDomain");
return (IMyClass)domain.CreateInstanceAndUnwrap("MyLib.MyClass", "MyLib");

What is the major use of MarshalByRefObject?

What's the purpose for MarshalByRefObject?
Remoting; it means that between AppDomains or machines, rather than serialize and transfer the object, the object stays at one end and a proxy is created at the other. All method calls to the proxy are intercepted and the call is transmitted as RPC wiki, msdn, causing the method to execute on the other machine (typically serialising the arguments and return value).
Note: this can lead to unexpectedly "chatty" interfaces. The object/proxy/RPC approach is now less preferable to approaches with an explicit service boundary; Microsoft now recommends WCF wiki, msdn instead of remoting.
Another important use of MarshalByRefObject is for implementing AOP via remoting sink-chains.
If you have an object that derives from ContextBoundObject (which itself derives from MarshalByRefObject) you can instantiate it in a separate Context within the same AppDomain and have communications between objects automatically go through the Remoting proxy system - allowing you to plug custom sinks into the Remoting sink-chain.
This ultimately allows you to 'decorate' method calls to your objects and implement cross-cutting services, such as logging and security etc.
it basic use is for support access of objects between two appdomains and these appdomains can be on the same computer or in the different computers via remoting.
See Here
Any object outside the application domain of the caller application should be considered as Remote Object. A Remote Object that should be derived from MarshalByRefObject Class. Any object can be changed into a Remote Object by deriving it from MarshalByRefObject. Objects without inheriting from MarshalByRefObject are called Non-remotable Objects.

Categories