How to get references to already instantiated remote objects using WCF? - c#

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.

Related

What is the difference between CAO and SAO in Remoting?

What is the difference between CAO(Client-activated objects ) and SAO(Server-activated objects) in Remoting?
Hoping for some good answers clearing citing the differences. any links or explanations are welcome.
I have googled about this but there wasnt much good answers in it either.
An instance of an remote class can be activated by either the server or client.
Client-activated objects are created on the server as soon as the client calls New or the Activator object.
(Basically, each client-activated instance of a remote class has a 1:1 mapping with a particular client. Each client holds its own personal instance of the remote class.)
Server-activated objects are created by the server only when the client invokes the first method through the local proxy.
(server-activated objects can be declared as Singleton or SingleCall objects. A Singleton object has exactly one instance to serve all possible clients. A SingleCall object requires that each incoming call is served by a new instance.)
Please check the below 2002 MSDN magazine about remoting. But as advised by #John Saunders, you should better use WCF. In WCF, you don't need to learn different technologies for webservices, remoting or messaging communication. These are all under the umbrella of WCF.
http://msdn.microsoft.com/en-us/magazine/cc188927.aspx#S6

Share an instance between multiple projects

I am working in VS 2008 C# and need to share an instance of an object created in one project with another project. I tried creating a static class in project1 and adding it as a link to project2, but the information wasn't saved. The static class was written in project1.
//object o = new object
//project1.staticObject = o
//project2.object = project1.staticObject
When I tried something like above, project2.object would be null. By adding a class as a link, is it creating a new instance of the static class in project2 or is it referencing the same class? If it is referencing the same class, shouldn't any information saved into the static class from project1 be accessible by project2? I know this isn't the most elegant manner of sharing data, but if anyone would help with this problem or provide a better manner of doing it, I would greatly appreciate it.
Thanks in advance.
Projects run in separate processes, so they can't share data in this manner. You'll need to persist the data in another type of store. I recommend using a database (hey, 20 gazillion websites, stock trading apps, airlines, etc can't be wrong).
If you don't want to use a database, you could open an IP connection between instances of the app and have a thread send packets of data to sync back and forth between the applications. Or, in your "server" app, add a web service that each process would call to update and retrieve information.
If you need really high-speed communication between the processes, sockets with a peer or star topology is a good way to go. If you're okay with some latency, having a web service (which works fine even if these aren't web apps) or a database could be a good solution. The right approach depends on your application.
WCF could also solve this problem. It effectively wraps the IP/socket layer and provides some nice object persistence/remote control capabilities, but I find it overly complex for most applications.
To share a single instance of an object among different processes (that's what I think you are intending to do) you need something that will maintain that object's state. You can look at the WCF and how to set up it's behaviour to act as a singleton so essentially every requester gets the same instance across the board.
http://msdn.microsoft.com/en-us/magazine/cc163590.aspx
Creating the link creates only applies to the source code. When you compile each project, it then has that single class definition available in both projects. The process you took does nothing for instances during runtime for sharing.
You can look at WCF or .NET Remoting, although .NET Remoting is now officially replaced by WCF.
If you are talking about sharing the same object between two processes, you can do that, the concept is called memory-mapped files. Here is some starter docs from msdn.
Though the docs and API use the term "FileMapping" quite a bit, you can use it just for sharing memory between two processes.
In .NET 4.0, you can use the System.IO.MemoryMappedFiles namespace. For your case, looks like .NET 3.5, you'll have to use some sort of interop to use the Win API.

WCF - Complex Objects - KnownTypes

Ok, not really sure how to word, but will try my best.
I have a number of WCF services that are setup and run awaiting an object to come in for processing.
WCFServiceA
WCFServiceB
WCFServiceC
Service A will run some processing and decide to send the object onto Service B or C.
So my object has [DataContract] attribute on all classes in it and [DataMember] on all properties.
So so far so good.
But now I well lose all the functionality from my object, as this is now basically a serialised version of the object.
So is it best practice if I want to use a full complex object to include the same assembly in all 3 services as a reference and send things across as "KnownTypes"?? Providing the basic DataContract and DataMember for anything using the services that does not know these types so they can still create these object for the services to run with?
Hope I have worded this correctly and you understand my question here.
:EDIT:
To try and clarify.
The object I am sending can have a "Policy" attached to it, this policy object is a class and can be one of several types, vehicle, house, life, pet policy etc.
But the actual type will not be known by the receiving service. Hence the need for KnownTypes.
I think I just answered my own question!! :)
That was a good explanation of the problem. The draw back I see in this approach is if you are going to update the object , say adding new properties or removing some , all the 3 service needs to be updated with the new assembly.
Using of the known types can sometimes lead to backward compatibility issues when you want to upgrade the objects in live depending on the setup.
Or create a DTO (Data transfer object) with just the properties and pass it across the services as a data contract and strip the complex logic in to a helper class which can be referenced by the services.

Why are Static Methods not Usable as Web Service Operations in ASMX Web Services?

I just wanna learn why I can't static web methods in web services ? Why is it restricted ?
Can some body give me concise explanation of this.
The answer is: because you can't.
It's not designed that way. The design is that an instance of the web service class will be created, and then an instance method will be called.
I can only guess why Microsoft designed it that way. To know for sure, you'd have to ask them. Consider:
There's no particular benefit to permitting static methods. Anything you can do with a static method, you can also do with an instance method.
A [WebService] class is not meant to be some arbitrary class that happens to be used as a web service. It's meant to be a class that you created for the purpose of exposing web service operations. As such, there is no need to support classes that already exist and already have static methods.
The SOAP Header implementation permits your class to contain an instance field of a type deriving from the SoapHeader class. This field will be filled with an incoming SOAP header and/or will contain the SOAP Header to be returned. You could not do this with a static field, as it would be overwritten with each request.
As I said, these are all guesses. The correct answer to the question is, "you can't because that's how Microsoft designed it. If you want to know why they designed it that way, you need to ask them".
FWIW, I just checked, and it does not appear that WCF permits static methods to be operations either.
When a client creates an object for your web service, what they are really creating is a proxy object to that web service. This proxy object handles things like opening and closing your connections for you as well as all the overhead of actually working with the web service. A static method call would be difficult to manage. The "static proxy" for lack of a better word would have to do all of things that the instance of the proxy object is doing each and every time a client called one of the static methods, thus adding massive overhead.

Workaround .net application domain only passing objects by value

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.

Categories