I am studying .net Remoting
I've read from MSDN, but in one step I am facing some confusion..
Three steps are required for remoting purpose.
1 - RemoteObject
2 - Host
3 - Client
creating RemoteObject and Host is fine. I understand all the things, it uses Configuration File for both Host and Client Configuration. In Client it uses the following code
public static void Main(){
RemotingConfiguration.Configure("Client.exe.config");
RemotableType remoteObject = new RemotableType();
Console.WriteLine(remoteObject.SayHello());
}
Here it is creating Object of RemotableType with new operator. Where as this Client application has reference of RemotableType.dll.
When this dll is available locally then what is the purpose of calling SayHello() remotely?
I ran this client without running server and it still displays me Hello World message.
Is this creation of remoteObject with new operator is valid here?
Where as the other method of getting remoteobject is:
RObject remoteObject = (RObject)Activator.GetObject(typeof(RObject), "tcp://localhost:9999/RObject");
Usually you will create two DLLs: One that contains an interface definitions for your remotable object and another one that contains the implementation of the interface definitions.
You will then add the interface definition DLL to the client, while the server needs both DLLs. The client will then create instances of the class using the Activator.GetObject(...) call.
If you reference the implementation DLL from your client - as you pointed out - you do not have any advantages from the client/server implementation.
Calling new RemotableType() is simply creating a local instance of RemotableType on the client. Calling any methods on it will get called on this instance.
Using Activator.GetObject() is creating a TransparentProxy in the client to the instance of RemotableType that was published in the host application. Calling any methods on this will make a remote call to the host application and will execute there. If your implementaion of SayHello was to return the name of the entry assembly (using Assembly.GetEntryAssembly()), it would return Host.exe even though you are running in the client.
Related
I am currently creating a .NET6 C# trading API client application and the API has two different WebSocket endpoints.
I'm wondering whether the ClientWebSocket object (System.Net.WebSockets) should be declared static or instance. I'm aware HttpClient should be declared static to prevent unnecessary new connections so I'm wondering if the same rationale applies to ClientWebSocket.
From my testing so far my impression is that the ClientWebSocket should be connected and disconnected manually as required, opposed to leaving it connected without any requirement (i.e. just pinging and ponging), and therefore instance objects may be fine to use. Put another way: if websocket connections are explicitly managed there does not appear to be an issue of 'connection re-use' like HttpClient and therefore instances are ok.
Having said that, another design option might be to declare the ClientWebSocket as static and just maintain an open connection + auto re-connect as long as the application is running.
My current design is to have two instance objects of ClientWebSocket, one for each API endpoint. They will be newed up each time a connection is needed.
Any thoughts appreciated.
I am writing two applications in C# that need to be able to communicate (in one direction only). The two apps will always run on the same machine, so using WCF with named pipes, and self-hosting the WCF service, seemed like the logical choice.
I understand that I can use InstanceContextMode to configure if a service instance is instantiated per session, per call, or if there should just be a single instance. In my case I want a single instance, because I will have just the two apps running, so there will be a single client and a single server.
But here's where I'm stuck. When my client makes a call on the service, which I'm doing this way:
var myServiceFactory = new ChannelFactory<IMyService>(
new NetNamedPipeBinding(), new EndpointAddress("net.pipe://localhost/MyService"));
IMyService myService = myServiceFactory.CreateChannel();
myService.DoStuff();
I don't want a new server object instance to be created on the server. Instead I'd like myService to point at the (one and only) IMyService instance that has already been constructed on the server. At the moment, a second IMyService instance gets constructed.
In other words, I want my server object to be constructed by the server (when the server starts up), not when a client first makes a call.
Can anyone explain how to do this? From what I understand, .NET Remoting makes this quite easy, and WCF has supposedly replaced Remoting, so there must be an easy way... right?
WCF's ServiceHost has a constructor which takes a singleton instance of the service class rather than the service type, for exactly this purpose. You must set InstanceContextMode to Singleton if using this constructor in your service host.
Note that in the client side code you quote, IMyService myService is not what you call "the server object" ... it is the client-side proxy through which WCF routes messages from the client to the actual service.
I have a query about .Net Remoting, versioning and creating client activated objects.
Here is the scenario:
There are 2 interfaces, residing in their own assembly “SharedTypes”: IServer and IAccount. IServer contains methods “GetStatus” which returns a string, and “CreateAccount” which returns an IAccount type. This is registered into the GAC as v1.0.0.0.
Server application references SharedTypes and implements IServer and IAccount with concrete classes, Server and Account. These are MarshalByRefObject objects. The Server application marshals the Server class as a singleton object.
Client application references SharedTypes and connects to the remoteable Server object through the IServer interface successfully. Here I can call GetStatus and CreateAccount (which returns a client activated object) successfully. All OK so far.
Now I increment the version of SharedTypes to v2.0.0.0 and register into the GAC, removing the old v1.0.0.0 version.
The Server application is built against this version, but the client is not.
Now when I run the client application, it will as expected complain with a System.IO.FileNotFoundException, i.e. it could not find v1.0.0.0 of SharedTypes in the GAC.
If I copy v1.0.0.0 of SharedTypes in the exe directory of the client, the client application eventually binds to this (after GAC lookup was unsuccessful). The client application starts and I can call the GetStatus on the IServer object successfully (through the singleton object). However, if I call CreateAccount – which should return a client activated object, I get the following exception:
System.InvalidCastException: Return argument has an invalid type.
at System.Runtime.Remoting.Proxies.RealProxy.ValidateReturnArg(Object arg, Type paramType)
at System.Runtime.Remoting.Proxies.RealProxy.PropagateOutParameters(IMessage msg, Object[] outArgs, Object returnValue)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at SharedTypes.IServer.GetAccount()
My question is why does calling GetStatus on the server activated singleton object from the client (which is using v1.0.0.0) not throw this exception, whereas creating the client activated object through CreateAccount does? Since both types are created on the server, I would have thought that GetStatus call would have resulted in the same exception?
The CLR normally ensures that only one specific version of an assembly can be loaded into a process. That doesn't work in this scenario because there are two copies of the CLR at work, one on the server and one on the client. So now it is up to the remoting infrastructure to ensure that remoted type objects are compatible. Which is does with aplomb in your case. Not sure I got the question posed in your last sentence but the server is not otherwise aware of the version of the assembly loaded in the client.
Recompiling the client is required.
This may not answer your specific question, but yours is the only question I can find on StackOverflow regarding an inexplicable InvalidCastException with the message "Return argument has an invalid type" involving a server singleton.
In my case, my client started by requesting the server's singleton (i.e. the object that was passed to RemotingServices.Marshal() on the server), then in the course of its processing, it happened to get a reference to that singleton via other methods, and got this exception.
I worked around it by creating two remote-proxies for the top-level object, one to serve as the singleton, and one that could be used internally in other contexts. Perhaps it's because, in the course of client processing, it tried to get a reference to that singleton object through a different type than the one that was passed to RemotingServices.Marshal(). I'm still not sure. But having two remote-proxies for the same local object, one to serve as a remoting singleton, and one for all other internal purposes, worked around the problem. Luckily I have a stateless remote-proxy architecture, so having two for the same local-object didn't cause any trouble.
Edit: Later, I found a simpler solution, one that doesn't require two proxies -- call RemotingServices.Marshal() with the actual type of the proxy in parameter 3, instead of the interface type.
For me, client application was on .net 4.0 while server app was running on 4.5.
Installing .net framework 4.5 on client machine fixed this issue.
Coming from a Java background, this is the way I'm thinking:
The server provides an object to the client. This object should be able to execute on the server.
Server:
private string _S = "A";
public interface IFoo { void Bar(); }
private class Foo : IFoo {
void Bar() { _S = "B";}
}
public IFoo GetFoo() { return new Foo(); }
Client:
IFoo foo = serverChannel.GetFoo();
foo.Bar();
Is this possible? Or is my understanding wrong and this is not how it works in WCF? What would be a better design?
No, I don't think that'll work. You see: WCF is not some kind of a remoting, remote-object, or remote-procedure call mechamism.
WCF at its core is a messaging infrastructure. Your client make a call to a method on a client-side proxy; the WCF runtime on the client captures the input parameters and the method name and a few more bits and pieces, serializes them into a message (either text or binary), and send that message across the wire (using whatever transport you like). The server does the same thing in reverse, deserializes the message, instantiantes a service class, executes a method on that class, and packages the return values back into a serialized message.
But there's really no connection or remoting link between client. Anything that goes between the two has to be serializable - into XML text at its core. You can pass around concrete classes and so on - but you cannot pass around interface, object references etc.
No - you cannot send objects around. As marc_s pointed out, WCF is a message-oriented communications framework.
But, you do have different instancing options.
By default, Windows Communication Foundation instantiates services on a per-call basis: a service instance, a common language runtime (CLR) object, exists only while a client call is in progress. Every client request gets a new dedicated service instance. This is something like Stateless Session Beans in J2EE.
Another option is session-based activation, which is something like Stateful Session Beans in J2EE. Using this approach, when the client creates a new proxy to a service configured as session-aware, WCF activates a new service instance and attaches it to the session. Every message sent by the client over that proxy will go to the same instance on the server side.
This activation behavior is selectable with the ServiceContract attribute.
Juval Lowy has written a good article on instantiation options in WCF.
Within these instancing options, you may find something that works for you.
Given that my client code knows everything it needs to about the remoting object, what's the simplest way to connect to it?
This is what I'm doing at the moment:
ChannelServices.RegisterChannel(new HttpChannel(), false);
RemotingConfiguration.RegisterWellKnownServiceType(
typeof(IRemoteServer), "RemoteServer.rem", WellKnownObjectMode.Singleton);
MyServerObject = (IRemoteServer)Activator.GetObject(
typeof(IRemoteServer),
String.Format("tcp://{0}:{1}/RemoteServer.rem", server, port));
The first two lines are in the server-side code, for marshaling out the server object, yes?
In that case, yes, the third line is the simplest you can get at client-side.
In addition, you can serve out additional server-side objects from the MyServerObject instance, if you include public accessors for them in IRemoteServer interface, so, accessing those objects become the simple matter of method calls or property accesses on your main server object, so you don't have to use activator for every single thing:
//obtain another marshalbyref object of the type ISessionManager:
ISessionManager = MyServerObject.GetSessionManager();
WCF.
I have used IPC before there was a WCF, and believe me, IPC is a bear. And it isn't documented fully/correctly.
What’s the simplest way to connect to a .NET remote server object? WCF.