.NET Remoting in Simple English(转一)
Introduction
This article is meant to be a step by step guide to give its reader a gist of .NET Remoting. I've tried to search good tutorials, but it was rather hard to find one that could work on my PC! So here's my first shot at a .NET Remoting tutorial in VB.NET. It shouldn't be hard to get it running, if you'd follow these few steps. After going through this article, be sure to read the continuation of this article here.
Q. What is an application boundary or domain?
A. Application domain is a logical boundary, and may be process or machine boundaries. Usually, no direct access exists to objects across this imaginary boundary. This is where Remoting services come into the picture, since it is able to access an object across a domain or boundary.
Q. By Value? By Object? Huh?
A. Now that you understand what an application domain is, we ask ourselves, how do we want to request the instance of a particular class to be accessible outside the original Application Domain. We have two choices, we either request a copy of the object or request a reference (or in techie words, proxy) to the original object.
Q. Let's use by Value... but how?
A. If you want your object, during runtime, to request a copy of the remote object (marshal-by-value), we have to do either one of these on the remote object:
- Add the
SerializableAttributeto the classExample:
<Serializable()> Public Class XYZ
- Implement the
ISerializableinterface (for more details, consult: .NET Framework Class Library,ISerializableInterface)Example:
Public Class XYZ Implements ISerializable
Q. What about by Ref...?
A. If you want your object, during runtime, to request a reference to the remote object (marshal-by-reference [MBR]), we have to ensure that the remotable object's class derives, directly or indirectly, from MarshalByRefObject. This allows the runtime to create a proxy to the object.
Q. How do I begin?
A. Generally, two things need to happen. A server must publish a remotable object (or service). The service may be on a TCP channel or HTTP channel, or even both. We give a name to the service, like "RemotingChat". The client, on the other hand, connects to a specific server or host name, specifies the service name using a supported channel, and either says, "I want an (value) or this (reference) instance of the object called RemotingChat". Remember all this can be done either programmatically or by using an app.config file.
Q. Did I just forget something...? Oh yes, you ALSO need to decide whether you want the object to be client or server activated. What are they about and how do you do it?
A. Server-activated objects are published at a URL, like so:
ProtocolScheme://ComputerName:Port/AppName/ObjectUri
The URL is so called as "well-known" to the client, even John Jones can use it! So it's called a well-known type. Even the URL is termed as the the well-known object URL.
On the other hand, the client activation creates one object for each, and its object's lifetime extends until either of this happens:
- Client drops dead... and loses reference to object
- The object's lease expires (can't live any longer...)
Your client URL would look like:
ProtocolScheme://ComputerName:Port/AppNameQ. So you've chosen to go for Server Activated? There's a choice between SingleCall and Single-what? Singleton,...
A. Another choice?? Well you would SingleCall remote objects when you want each object to service one and only one request. This is useful when you want it to be created on-demand as method calls arrive. Oh yes, don't forget, that after the method call, it dies... Therefore, its lifetime is limited to the method call. You might want to use it in stateless applications (in simplicity: applications that forget you ever called them...). Some say, it's the choice for load-balanced applications.
Another pound of the tonne? Ahh, yes it's singleton. This is useful, if you need all the clients to access one and only one remote object. Here, the server's remoting layer creates one Singleton object. This lone-ranger object handles method calls from all clients. Sad huh? But it lives up to a 100 years, -it lives as long as the server's lifetime. Pretty much the opposite of the SingleCall fellow, so it's useful in stateful applications. A good choice is when the overhead of creating and maintaining objects is substantial.
To activate the remote objects programmatically on the host, you might code it as:
new WellKnownServiceTypeEntry(typeof(InBetween.Manager), _
"Manager", WellKnownObjectMode.Singleton);
or
new WellKnownServiceTypeEntry(typeof(InBetween.Manager), _
"Manager", WellKnownObjectMode.Singlecall); Q. You mentioned that there are 2 ways to configure my remotable object's creation: Programmatically and by using a config file. What do you mean?
A. Bearing in mind, that you want to do a server activation; it means you either do this:
<configuration>
<system.runtime.remoting>
<application name="WiseOwlMathService">
<service>
<wellknown mode="SingleCall" type="InBetween.Manager,Manager"
objectUri = "MYOBJECT1" />
<wellknown mode="Singleton" type="InBetween.Manager,Manager"
objectUri = "MYOBJECT2" />
</service>
<channels>
<channel port="9999" ref="http" />
<channel port="8888" ref="tcp" />
</channels>
</application>
</system.runtime.remoting>
</configuration>
or this:
using System;
using System.Reflection;
using System.Runtime.Remoting;
class RemotingHost {
static void Main(string[] args) {
String s = Assembly.GetExecutingAssembly().Location;
RemotingConfiguration.Configure ("Yourserver.exe.config");
Console.ReadLine();
}
}Q. What about Client Activation codes?
A. Here you are again, you can either do it programmatically: The code below shows what you need to place on your server (host) portion of your code to specify the type of the object being registered
using System.Runtime.Remoting;
//. . .blah blah blah
ActivatedServiceTypeEntry as =
new ActivatedServiceTypeEntry(typeof(InBetween.Manager));
RemotingConfiguration.RegisterActivatedServiceType(as);
On the client,
using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;
using System.Runtime.Remoting.Channels.Tcp;
class RemotingHost {
static void Main(string[] args) {
RemotingConfiguration.ApplicationName = "YOURSERVICENAME";
ActivatedServiceTypeEntry as =
new ActivatedServiceTypeEntry(typeof(InBetween.Manager));
RemotingConfiguration.RegisterActivatedServiceType(as
ChannelServices.RegisterChannel(new HttpChannel(9999));
ChannelServices.RegisterChannel(new TcpChannel(8888));
//etc etc
}
}
or:
<configuration>
<system.runtime.remoting>
<application name="YOURSERVICENAME">
<service>
<activated type="InBetween.Manager,Manager" />
</service>
<channels>
<channel port="9999" ref="http" />
<channel port="8888" ref="tcp" />
</channels>
</application>
</system.runtime.remoting>
</configuration>Q. So, now you have your client. But how does it activate the remote object?
A. If you're referring to a Server activated or Well-known object that exists at a URL, you would use:
- Client obtains proxy using
Activator.GetObject - Client can also obtain proxy using
new
Otherwise, you would use the Client to request the object factory (that exists on the URL) to instantiate object and return a proxy to it using
Activator.CreateInstance
Or use, our simple
newQ. What are the differences between all the object activation codes?
A. To summarise, here's a table
GetObject
|
This returns a proxy for the well-known type served at the specified location. Interestingly, there is no network traffic until first method call. This will cause the object Proxy to be built on the client from metadata of the server. The server activates object on first method call. |
GetObject via System.Runtime.Remoting. RemotingServices
|
There is a GetObject wrapper around System.Runtime.Remoting. RemotingServices.Connect too: Using System.Runtime.Remoting;
static object o RemotingServices.Connect
(Type classToProxy, string url);
|
Activator.CreateInstance
|
This is a bit of a bad guy as this client activation requires a network round trip. It sends an activation message to the server. But the goody thing is that, you can include constructor parameters (unlike, just new Dim activationAttributes() As Object = { New _
Activation.UrlAttribute _
("http://localhost:9999/RemotingChat")
}
Dim o As Object = _
Activator.CreateInstance_
(GetType(InBetween.Manager),_
Nothing, activationAttributes)
InBetween.Manager c = _
CType (o, InBetween.Manager)
|
Q. Anything else?
A. Oh yes... You would need to consider some things when using this code in v1.1 of the framework... You need to add a property called typeFilterLevel to the formatter tag and set it to Full to relax security, or else, you'll get an exception:
System.Security.SecurityException.
Type System.DelegateSerializationHolder and the types derived from it (such
as System.DelegateSerializationHolder) are not permitted to be deserialized
at this security level.
System.Runtime.Serialization.SerializationException
Because of security restrictions,
the type System.Runtime.Remoting.ObjRef cannot
be accessed.
Be sure to change your config file (on the server):
<configuration>
<system.runtime.remoting>
<channel ref="http" port="7777">
<serverProviders>
<provider ref="wsdl" />
<formatter ref="soap" typeFilterLevel="Full" />
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
<clientProviders>
<formatter ref="binary" />
</clientProviders>
</channel>
<service>
<!-- ... Add your services here ... -->
</service>
</system.runtime.remoting>
</configuration>
and client:
<configuration>
<system.runtime.remoting>
<channel ref="http" port="0">
<clientProviders>
<formatter ref="binary" />
</clientProviders>
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
<client>
<!-- ... Add your classes here ... -->
</client>
</system.runtime.remoting>
</configuration>
For more details on how to do it programmatically, please refer to this link.
Q. Can you give us a diagram that explains all this?
A. Sure...
浙公网安备 33010602011771号