|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionUpdated on 18th January, 2006 - I received many positive comments about this article and several requests to add some descriptive code to the contents. Based on this feedback, I have reworked on the article to provide a more detailed discussion - with code - of the remoting server and client setup. Please enjoy! I have spent a lot of time learning how to create and use basic remoting services in my applications. Code Project has been very helpful in this. Although the various articles and tutorials provided me with the information I needed, I never did find a simple, bare bones, use-it today remoting example. This article will attempt to solve that problem. Once you have mastered the basics presented here, you can refer to the following Code Project articles for more detailed information: Many other interesting articles are also available at CodeProject. GoalTo provide you with a very simple, easy to understand implementation of a client/server system using .NET remoting. Once you understand this code, you can immediately enhance it for use in your own applications. I have left out everything except the minimum code required to setup and test a remoting client and server. Using the codeThe included zip file contains a Visual Studio .NET 2003 solution with three projects. Each project is described below:
As configured, you should be able to build the solution and run the client and server on your local machine. To get started:
Let's remote!The code is simple and well commented. You should look at it to get the big picture. A few items need closer examination. Server sideOn the server side, you need to complete three key steps to get a server working. The steps are: Create an interface implementationLet us look at the public class ICalculatorImplementation: MarshalByRefObject,
ICalculator
{
/// <summary>
/// Default constructor
/// </summary>
public ICalculatorImplementation()
{
Console.WriteLine(
"ICalculatorImplementation constructor.");
}
#region ICalculator Members
public int Add(int A, int B)
{
Console.WriteLine("Calculator service: Add() called.");
return (A + B);
}
#endregion
} // class
The most important thing is to inherit from Create an application to host and start the serviceNext, we need to create some type of application to hold our service. Any application is suitable; console, Windows and NT services are all useful in various situations. For this example, I used a standard C# console application created with the project wizard. All the work is done in the application entry point, Here is an excerpt from ServerStart.cs. I have removed some of the code and comments for clarity: [STAThread]
static void Main(string[] args)
{
// HTTP or TCP connection setup go here.
// See article section 3.
// Register the Http/TCP channel we created above.
ChannelServices.RegisterChannel(chan);
// Start Calculator service.
// Register calculator service
Type iCalc = Type.GetType(
"InterfaceTest.Server.ICalculatorImplementation");
// Configure the service
RemotingConfiguration.RegisterWellKnownServiceType(
iCalc,
"ICalcEndPoint",
WellKnownObjectMode.Singleton
);
}
I will look at the connection setup in a minute, so for now that section of the code has been removed. Once the connection (TCP or HTTP) has been setup, you register then configures the service. The code above is pretty much boiler plate so you can substitute your own interface implementations into the lines above. When you get the type of your interface implementation, you need to include the complete namespace as well as class name to get the correct type return. In this case, it is The When you move beyond this sample, you will want to investigate the
Note: You can host multiple services in a single application. The provided sample code demonstrates this by hosting the For example, the calculator service URL in the sample code is: TCP://LocalHost:65101/ICalcEndPoint
And the test service URL is: TCP://LocalHost:65101/ITestEndPoint
Setup a TCP or HTTP communications channelRemoting can use HTTP or TCP for communications. HTTP is very simple to setup. Here is an example for a remoting server: HttpChannel chan = new HttpChannel(65101);
That's it! Create an A TCP channel is more complex to setup on the client and server. The performance benefits might be worth it depending on your application needs. TCP remoting is faster than HTTP remoting. Here is how you create a TCP channel on the server. See ServerStart.cs for all the details: BinaryClientFormatterSinkProvider clientProvider = null;
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 65101;
props["typeFilterLevel"] =
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
TcpChannel chan =
new TcpChannel(props, clientProvider, serverProvider);
Although there are many more steps required for TCP setup, you can use this code as boiler plate. Just replace the Client sideOn the client side, when you want to gain access to a remote service you have to do two things. They are: Create a channel to the remote serviceLike the server, you need to create a TCP or HTTP channel. The steps are almost identical. For HTTP the statement: The TCP code is also similar to the server. Here is an excerpt from MainForm.cs in the client project: url = @"tcp://LocalHost:65101/";
BinaryClientFormatterSinkProvider clientProvider =
new BinaryClientFormatterSinkProvider();
BinaryServerFormatterSinkProvider serverProvider =
new BinaryServerFormatterSinkProvider();
serverProvider.TypeFilterLevel =
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
IDictionary props = new Hashtable();
props["port"] = 0;
props["name"] = System.Guid.NewGuid().ToString();
props["typeFilterLevel"] =
System.Runtime.Serialization.Formatters.TypeFilterLevel.Full;
TcpChannel chan =
new TcpChannel(props, clientProvider, serverProvider);
Unlike the server code, this code creates Register and connectOnce you have created a communications channel you register the channel, setup remote access to the server using //
// Register the channel
//
ChannelServices.RegisterChannel(chan);
//
// Setup remote access to ICalc implementation
//
MarshalByRefObject calc =
(MarshalByRefObject)RemotingServices.Connect(
typeof(Interfaces.ITest), url + "ICalcEndPoint"
);
// Set a reference to the service.
calcReference = calc as Interfaces.ICalculator;
// Test
int test = calcReference.Add(10,20);
Console.WriteLine("Add(10,20) returned " + test.ToString());
Once ConclusionThis is the simplest remoting example I was able to create. The code is well commented and hopefully you can use it as is while you become more familiar with remoting concepts. The sections above highlight the most important remoting steps. Below I have listed a few key points and areas of interest that you should also think about when dealing with remoting. InterfacesIf you are not familiar with using interfaces, I suggest you review the topic. Interfaces are the mechanism I use to provide remote services to the client and as far as I know, it is the most common method in use. The interface allows you to treat a remote instance of some class as if it was a local object; it also decouples the client from the server. You will notice that I have created a separate interface class library to hold all interfaces shared by the client and server applications. Simply put, this means that changing the implementation of the client or server does not force you to rebuild the other. Interfaces also provide transparency. Once you create a communications channel to your server and create an interface instance of the service you want to use, the use of the remote object is completely transparent to your client's code. HTTP versus TCP connectionsAs you examine the code, you will see that, by far, the HTTP connection is the simplest to setup. This does come at some cost. The HTTP transport is much slower than the TCP/Binary connection. The advantage is that HTTP will work through a firewall and provide built-in security mechanisms if you need them. It is also compatible with non .NET code. The TCP connection is more complex, but faster and only compatible with other .NET applications. There is a wealth of information available on Code Project and other sites about TCP and HTTP remoting. Once you have the basics down you should spend some time reading these articles. See the links I have provided in the Overview section of this article. Error handlingI have left out all error handling to simplify the code. In a real world application you should, at minimum, add some exception handling to the client. Many real world clients will wrap every call to a remote method in a My servers always have an I find that this technique makes the code easier to read and improves performance. However, my way is not the best way so use it at your own risk.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||