Introduction

This document will provide details on how to build an etch application using csharp.

Sample Etch File

The following is the etch file we will refer to in this document. Lets call this File Example.etch and store it in directory c:\EtchExamples\Example

module etch.examples.example

/**
 * Service version of hello world.
 */
service Example
{

	/** the number of times to perform the action */
	const int COUNT = 4

	/* Exception thrown if ping doesn't work.
	 * @param msg the explanation.
	 */
	exception PongException ( string msg )


	/**
	 * Says hello to the server.
	 * @param msg a greeting for the server.
	 * @param d the current date.
	 * @return the id of our hello
	 */
	@Timeout( 1234 )
	@Direction( Server )
	int helloServer( string msg, Datetime d )
	
	/**
	 * Says hello to the client.
	 * @param msg a greeting for the client.
	 * @return the id of our hello
	 */
	@Timeout( 2345 )
	@Direction( Client )
	int helloClient( string msg )
	
	/**
	 * Says hello to the client or server.
	 * @param msg a greeting for the client or server.
	 * @return the id of our hello
	 */
	@Timeout( 3456 )
	@Direction( Both )
	int hello( string msg )

	/**
         * Says howdy to the server. Oneway.
	 * @param msg a greeting for the server.
	 */
	@Oneway
	@Direction( Server )
	void howdyServer( string msg )

	/**
	 * Says howdy to the client. Oneway.
	 * @param msg a greeting for the client.
	 */
	@Oneway
	@Direction( Client )
	void howdyClient( string msg )

	/**
	 * Says howdy to the client or server. Oneway.
	 * @param msg a greeting for the client or server.
	 */
	@Oneway
	@Direction( Both )
	void howdy( string msg )

	/**
	 * Pings the other side.
	 * @throws PongException
	 */
	@Timeout( 4567 )
	@Direction( Both )
	@AsyncReceiver( Queued )
	void ping() throws PongException
}

Using Etch Compiler

Before compiling etch file, please make sure Etch is installed and is present in the path

Command Line

  • Before we generate the server code, lets create a directory for server (c:\EtchExamples\Example\server).
  • From the command line, use the following command to generate the server side code
etch -b csharp -d .\server -w server,impl,main Example.etch
  • This command will generate the server side code under

c:\EtchExamples\Example\server\etch.examples.example

  • The directory name "etch.examples.example" is generated by the compiler. This name corresponds to the module name of the etch file.
  • Like we did for server, lets create a directory for client (c:\EtchExamples\Example\client)
  • Similarly using the following command to generate the client side code
    etch -b csharp -d .\client -w client,impl,main Example.etch
    
  • This command will generate the client code under

c:\EtchExamples\Example\client\etch.examples.example

Please refer to the Etch Compiler Guide for more details on the various compiler options

Visual Studio Plugin

  • If you are using Visual Studio as your IDE, then you can install the Visual Studio Etch Plugin. TODO Make sure the setup.exe for the plugin is a part of etch install...
  • Once the plugin has been installed, open Visual Studio and goto Tools->Add-in Manager. Make sure Etch is checked
  • Create a new Empty solution add two projects client and server to the solution.
  • Copy Example.etch to both client and server project
  • Right click on the etch file in the solution explorer and chose server compiler option for server project. Add the generated files to the project by right clicking on the project and choosing Add->Existing Item. Do the exact same thing for client project

Generated Files

Once the etch file has been compiled successfully, either from command line or Visual Studio Plugin, a bunch of files are generated.

This section briefly explains the purpose of each generated file.

Interface Files

Example.cs
ExampleClient.cs
ExampleServer.cs

These three files are the generated interface classes. Service defined constants and types are in Example.cs, as well as direction "both" messages, which are messages which are shared between client and server. ExampleClient.cs and ExampleServer.cs are respectively the messages for just the direction client or server. These Files should not be edited by the user

Remote Files

RemoteExample.cs
RemoteExampleClient.cs
RemoteExampleServer.cs

RemoteExample*.cs are the generated classes which implement the interfaces, with message implementations which encode the message type and arguments for transport to the connection peer and then receive and decode any response. These files should not be edited by the user either

Stub Files

StubExample.cs
StubExampleServer.cs
StubExampleClient.cs

StubExample*.cs are the generated classes which receive messages encoded by RemoteExample*.cs and decode them, calling the appropriate message implementation and then encoding and sending any result. These Files are also not edited by the user

Value Factory File

ValueFactoryExample.cs

ValueFactoryExample.cs is a generated class which contains helper code to serialize service defined types and also the meta data which describes the messages and fields, field types, timeouts, etc. This file is also not edited by the user

Base Files

BaseExample.cs
BaseExampleClient.cs
BaseExampleServer.cs

BaseExample*.cs are generated classes which implement the interfaces, with message implementations which call the delegate. If no delegate is defined i.e. if delegate is null, an UnsupportedOperationException is thrown. These files are also not edited by the user

Impl Files

ImplExampleClient.cs
ImplExampleServer.cs

ImplExample*.cs are the generated sample client and server implementation classes. They extend the generated base classes. These are used by the sample main programs to provide implementations of the client or server messages. Edit these files as you wish to implement your service (overriding the default implementations from the generated base classes or uisng delegates).

Helper File

ExampleHelper.cs

ExampleHelper.cs is a generated class which includes static methods to help construct transports for client and listener. This file should not be edited by the user

Main Files

MainExampleClient.cs
MainExampleListener.cs

MainExample*.cs are the generated sample client and server main programs. They show how to setup a transport and start it and how to create a session. Edit these files as you wish to implement your service, or just copy the code into your own application.

Changes Required to Make the Application Work

Only a few files need to be edited to make the etch application run.

MainExampleListener

As mentioned in the previous section, MainExampleListener is the class where the listener (server) is started. The user needs to edit the URI to point to the location where listener must listen for connection from the client

string uri = "tcp://localhost:4002";

In the above code snippet, the listener will run at port 4002 on localhost.

When the listener accepts a connection from the client, an server object (ImplExampleServer) is created to service the client request. The code to create the Impl object is auto generated by the compiler.

public ExampleServer NewExampleServer( RemoteExampleClient client )
{
     return new ImplExampleServer( client );
}

If a user wishes to, he can pass more parameters to the Impl Object. In the context of our example, we do not need to pass any other arguments, thus we will keep the generated code as is.

In summary, editing the uri is the only change required for our example.

ImplExampleServer

In this class, we will provide implementation of any "both" or "server" directed messages. To get a better understanding of what is meant by "both" and "server" directed message, lets look at snippet of Example.etch

        @Timeout( 3456 )
	@Direction( Both )
	int hello( string msg )

	@Oneway
	@Direction( Server )
	void howdyServer( string msg )

        @Oneway
	@Direction( Client )
	void howdyClient( string msg )

The keyword @Direction(....) is used to specify the direction of the message. @Direction(server) implies that the message is headed towards the server. Both implies that the message can be directed towards the server or client. For more details please refer to the Etch Language Reference Manual.

For our purpose, in ImplExampleServer we will only implement the messages that are directed towards server "@Direction(Server)" or both "@Direction(Both)"

ImplExampleServer extends from BaseExampleServer which provides a default implementation of all messages with direction server or both. Below is a snippet of BaseExampleServer

...
...
...
/// <summary>
/// Delegate Definition; Please do not modify
/// </summary>

public delegate int? _delegate_type_helloServer	(string msg, System.DateTime? d);

/// <summary>
/// Add your implementation method to this variable
/// </summary>

public _delegate_type_helloServer  _delegate_helloServer;


public virtual int? helloServer (string msg, System.DateTime? d)
{

     if (_delegate_helloServer != null)
	  return _delegate_helloServer(msg,d);
     else
	  throw new NotSupportedException( "helloServer" );
}
...
...
...

In ImplExampleServer we can either override method helloServer or use the power of delegate (see example below for how to use delegate)

public ImplExampleServer(RemoteExampleClient client)
{
     this.client = client;
     _delegate_helloServer = SayHello;
}

/// <summary>A connection to the client session. Use this to
/// send a message to the client.</summary>
private readonly RemoteExampleClient client;

public int? SayHello(string msg, DateTime? d)
{
      Console.WriteLine("Msg is {0} and date is {1}", msg,d);
      return 0;
}

Notice that method SayHello is assigned to delegate _delegate_helloServer in the constructor.

In summary, ImplExampleServer is where the actual server implementation resides. The user can choose to either override the methods in BaseExampleServer or assign methods to delegates.

MainExampleClient

The uri in MainExampleClient needs to be modified such that it points to location where listener was started. In the context of our example the uri will point to the following

string uri = "tcp://localhost:4002";

The compiler generates code to setup up the transport layer. It also gets an instance of RemoteExampleServer. The client uses RemoteExampleServer to send messages to server.
In the context of our example, we will call method helloServer on RemoteExampleServer. Following is a code snippet

public static void Main(String[] args)
{

    string uri = "tcp://localhost:4002";

    RemoteExampleServer server = ExampleHelper.NewServer( uri, null, new MainExampleClient());

   // Connect to the service
   server._StartAndWaitUp( 4000 );

   server.helloServer("Hi !!!", DateTime.Now);

   // Disconnect from the service
   server._StopAndWaitDown( 4000 );

}

Thus a user only needs to change the uri and use the RemoteExampleServer instance to invoke messages on the server

ImplExampleClient

MainExampleClient also contains method NewExampleClient, which creates an ImplExampleClient object. This class provides implementation of "both" directed and "client" directed messages. This class is analogous to the ImplExampleServer. The only difference being that ImplExampleServer implemented "server" and "both" directed messages, while ImplExampleClient implements "client" and "both" directed messages.

To see ImplExampleClient at work, we will have to modify ImlExampleServer as well. In ImplExampleServer section, we provided implementation of helloServer method using delegates, lets tweak this a little such that the server replies back client with a howdyClient message.

public ImplExampleServer(RemoteExampleClient client)
{
     this.client = client;
     _delegate_helloServer = SayHello;
}

/// <summary>A connection to the client session. Use this to
/// send a message to the client.</summary>
private readonly RemoteExampleClient client;

public override int? helloServer(string msg, DateTime? d)
{
     Console.WriteLine("Msg is {0} and date is {1} ", msg, d);
     client.howdyClient("Hi Client");
     return 0;
}

It is very important to remember that howdyClient is defined as a @oneway message in the Example etch file. Such messages don't wait for a response. They are often referred to as event or "fire and forget" message. If howdyClient was not defined as @oneway, it would have resulted in a deadlock or a timeout exception. This is because client would expect to hear back from helloServer message, while server would be waiting to hear back from howdyClient. Since neither can respond until they hear from the other, they will eventually timeout if a timeout has been defined or just wait indefinitely. However since howdyClient message has been defined as @oneway the server does not have to wait for a response from the client.

In summary, ImplExampleClient is the place where the client implementation resides. The user can chose to override the base implementation provided in BaseExampleClient or assign methods to delegates.

Compile and Run the Application

Using CSC

Please make sure that .NET 2.0 or greater is installed on your system

Building on our example, lets first compile the server files.

  • The first step would be to change directory to the server location
    (c:\EtchExamples\Example\server\etch.examples.example).
  • The next step would be to copy Etch.dll from Etch Home Directory to the server directory.
  • Once the file is copied, use csc to compile the *.cs file.
copy "%ETCH_HOME%\lib\Etch.dll" .

csc "/reference:%ETCH_HOME%\lib\Etch.dll" /main:etch.examples.example.MainExampleListener *.cs

If there are no compile errors MainExampleListener.exe is created. Use the exe file to run the listener.

For the client files, cd to the client directory and follow the same instructions as mentioned above. In csc command replace etch.examples.example.MainExampleListener with
etch.examples.example.MainExampleClient

use MainExampleClient.exe to run the client.

Using Visual Studio

  • Please make sure you have followed the steps mentioned in section "Visual Studio Plugin".
  • Add %ETCH_HOME%\lib\Etch.dll as a reference to both client and server project
  • Build solution by either right clicking on solution and choosing Rebuild Solution or by using keyborad shortcut (CTRL+SHIFT+B).

To Run the Application

  • Right click on the server project and chose "Set as Startup Project".
  • Press CTRL+F5 to run the listener or server.
  • Follow the above two steps to run client as well.