ApplicationServer Boilerplate (.NET)

ApplicationServer Boilerplate code is an entire server app infrastructure built available via a single line of code.

The ApplicationServer class eliminates the need for a whole bunch of boiler-plate code that used to make up an RO server application. With literally a single line of code, the server application can be up and running, and the ApplicationServer class takes care of:

  • Processing command line parameters to run the server in command-line, GUI and Windows Service/Dæmon mode
  • Setting up the infrastructure to register, unregister or launch as Windows Service
  • Providing a default window, in GUI mode
  • Setting up the server channel and messages via code or via external configuration
  • Setting up TLS traffic encryption
  • Optionally making sure only a single instance of the server is active
  • Providing events for exception handling, as well as startup and shutdown

This simple line of code provides all these features:

public static int Main(string[] args)
{
   new ApplicationServer("Server App Name").Run(args);
   return 0;
}
begin
  new ApplicationServer('Server App Name').Run(args);
  result := 0;
end.
ApplicationServer("Server App Name").Run(C_ARGV.nativeArray);
result := 0;
Public Shared Function Main(args As String()) As Int32
  Dim server As New ApplicationServer("Server App Name")
  server.run(args)
End Function

Command Line Parameters

By default the following command-line arguments are recognized (not case-sensitive):

Parameters Description
-i, /i, --install Install service
-u, /u, --uninstall Uninstall service
-q, /q, --quiet Suppress messages on service installation and uninstallation
-c, /c, --commandline Run in command-line/console mode
-d, /d, --debug Request extended debug info (e.g. full stacktraces)
-h, /h, -?, /? Show command-line arguments help message

You don't have to write any code to handle these actions.

Additionally, the ApplicationServer class provides APIs for fine-tuning the server channel used, TLS Certificates management, and so on. A sample of such calls is provided by the Remoting SDK server app template:

public static int Main(string[] args)
{
   ApplicationServer server = new ApplicationServer("ROServer9");

   //
   // Some optional setup for your server:
   //

   // TLS
   server.AutoCreateSelfSignedCertificate = true;

   server.NetworkServer.UseTLS = true;

   //server.NetworkServer.CertificateFileName = "</path/to/certificate>";
   //server.NetworkServer.CertificateThumbprint = "XX XX XX ...";
   //server.NetworkServer.Certificate = <certificate instance>

   //server.NetworkServer.ServerChannel = new IpSuperHttpServerChannel();
   //server.NetworkServer.Port = 8099;

   server.Run(args);
   return 0;
}
class method Program.Main(args: array of String): Integer;
begin
 var server := new ApplicationServer('ROServer9');

 //
 // Some optional setup for your server:
 //

 // TLS
 server.AutoCreateSelfSignedCertificate := true;

 server.NetworkServer.UseTLS := true;
 //server.NetworkServer.CertificateFileName := '</path/to/certificate>';
 //server.NetworkServer.CertificateThumbprint := 'XX XX XX ...';
 //server.NetworkServer.Certificate := <certificate instance>

 //server.NetworkServer.ServerChannel := new IpSuperHttpServerChannel();
 //server.NetworkServer.Port := 8099;

 server.Run(args)
end;
let server = ApplicationServer("ROServer9")

//
// Some optional setup for your server:
//

// TLS
server.AutoCreateSelfSignedCertificate = true

server.NetworkServer.UseTLS = true
//server.NetworkServer.CertificateFileName = "</path/to/certificate>"
//server.NetworkServer.CertificateThumbprint = "XX XX XX ..."
//server.NetworkServer.Certificate = <certificate instance>

//server.NetworkServer.ServerChannel = new IpSuperHttpServerChannel()
//server.NetworkServer.Port = 8099

server.Run(C_ARGV.nativeArray)
Public Shared Function Main(args As String()) As Int32
   Dim server As New ApplicationServer("ROServer9")

   '
   ' Some optional setup for your server:
   '

   ' TLS
   server.AutoCreateSelfSignedCertificate = True

   server.NetworkServer.UseTLS = True
   ' server.NetworkServer.CertificateFileName = "</path/to/certificate>"
   ' server.NetworkServer.CertificateThumbprint = "XX XX XX ..."
   ' server.NetworkServer.Certificate = <certificate instance>

   ' server.NetworkServer.ServerChannel = New IpSuperHttpServerChannel()
   ' server.NetworkServer.Port = 8099

   server.Run(args)
   Return 0
End Function

The server infrastructure can be easily expanded, with little code. For example, it is possible to provide a custom GUI implementation or a custom NetworkServer implementation by simply adding the corresponding component to the project and marking it with the ServerInfrastructure attribute.

Custom Network Server

In the following code a NetworkServer that exposes an additional ServerChannel is defined:

[ServerInfrastructure]
public class ExtendedNetworkServer : NetworkServer
{
   private IpHttpServerChannel _serverChannel;

   protected override void InternalStart()
   {
       base.InternalStart();

       this._serverChannel = new IpHttpServerChannel();
       this._serverChannel.Port = this.Port + 1;
this._serverChannel.Dispatchers.AddRange(this.ServerMessages.Select(m =>
           new MessageDispatcher(m.DefaultDispatcherName, m)));
       this._serverChannel.Open();
   }

   protected override void InternalStop()
   {
       this._serverChannel.Close();
       base.InternalStop();
   }
}
type
  [ServerInfrastructure]
  ExtendedNetworkServer = public class(NetworkServer)
  private
    var fServerChannel: IpHttpServerChannel;
  protected
    method InternalStart(); override;
    method InternalStop(); override;
  end;
 
 // ...
 
method ExtendedNetworkServer.InternalStart();
begin
 inherited InternalStart();

 self.fServerChannel := new IpHttpServerChannel();
 self.fServerChannel.Port := self.Port + 1;
self.fServerChannel.Dispatchers.AddRange(self.ServerMessages.Select((m) -> new MessageDispatcher(m.DefaultDispatcherName, m)));
 self.fServerChannel.Open();
end;

method ExtendedNetworkServer.InternalStop;
begin
 self.fServerChannel.Close();

 inherited InternalStop();
end;
@ServerInfrastructure
public class ExtendedNetworkServer : NetworkServer {
   private var _serverChannel: IpHttpServerChannel!

   public override func InternalStart() -> ()! {
       super.InternalStart()
       self._serverChannel = IpHttpServerChannel()
       self._serverChannel.Port = self.Port + 1
self._serverChannel.Dispatchers.AddRange(self.ServerMessages.Select({ (m) in
           MessageDispatcher(m.DefaultDispatcherName, m)
       }))
       self._serverChannel.Open()
   }

   public override func InternalStop() -> ()! {
       self._serverChannel.Close()
       super.InternalStop()
   }
}
<ServerInfrastructure> _
Public Class ExtendedNetworkServer
   Inherits NetworkServer

   Private Dim _serverChannel as IpHttpServerChannel

   Protected Overrides Sub InternalStart()
       MyBase.InternalStart()

       Me._serverChannel=New IpHttpServerChannel()
       Me._serverChannel.Port=Me.Port+1
       Me._serverChannel.Dispatchers.AddRange(From m In Me.ServerMessages _
                    Select New MessageDispatcher(m.DefaultDispatcherName, m))
       Me._serverChannel.Open()
   End Sub

   Protected Overrides Sub InternalStop()
       Me._serverChannel.Close()

       MyBase.InternalStop()
   End Sub
End Class

This NetworkServer implementation will then be automatically used instead of the default one.

Starting/Stopped Events

Alternatively, ApplicationServer also exposes Starting and Stopped events that can be used to perform additional setup and deconstruction:

public static int Main(string[] args)
{
   ApplicationServer server = new ApplicationServer("RO9Server");

   server.Starting += (sender, ea) =>
   {
       // additional setup
   };

   server.Stopped += (sender, ea) =>
   {
       // additional teardown
   };

   server.CertificateGenerating += (sender, ea) =>
   {
       // here HashAlgorithm, Subject and Issuer of the self-signed certificate can be changed
   };

   server.NetworkServer.Starting += (sender, ea) =>
   {
       // additional setup of the NetworkServer (in some cases this even allows 
       // to avoid defining a custom NetworkServer class)
       // also Started, Stopping and Stopped events are available
   };

   server.Run(args);
   return 0;
}
begin
  var lServer := new ApplicationServer('Server App Name');
  lServer.Starting += method begin
    // additional setup
  end;
  lServer.Stopped += method begin
    // additional teardown
  end;
  lServer.CertificateGenerating += method begin
    // here HashAlgorithm, Subject and Issuer of the self-signed certificate can be changed
  end;
  lServer.NetworkServer.Starting += method begin
    // additional setup of the NetworkServer (in some cases this even allows 
    // to avoid defining a custom NetworkServer class)
    // also Started, Stopping and Stopped events are available
  end;
  lServer.Run(args);
  result := 0;
end.
let server = ApplicationServer("Server App Name")
server.Starting += {
  // additional setup
}
server.Stopped += {
  // additional teardown
}
server.CertificateGenerating += {
  // here HashAlgorithm, Subject and Issuer of the self-signed certificate can be changed
}
server.NetworkServer.Starting += {
  // additional setup of the NetworkServer (in some cases this even allows 
  // to avoid defining a custom NetworkServer class)
  // also Started, Stopping and Stopped events are available
}
server.Run(C_ARGV.nativeArray);
result := 0;
Public Shared Function Main(args As String()) As Int32
   Dim server As New ApplicationServer("ServerSampleVB")

   AddHandler server.Starting,
       Sub(sender As Object, e As EventArgs)
           ' additional setup
       End Sub

   AddHandler server.Stopped,
       Sub(sender As Object, e As EventArgs)
           ' additional teardown
       End Sub

   AddHandler server.CertificateGenerating,
       Sub(sender As Object, e As CertificateGeneratingEventArgs)
           ' here HashAlgorithm, Subject and Issuer of the self-signed 
           ' certificate can be changed
       End Sub

   AddHandler server.NetworkServer.Starting,
       Sub(sender As Object, e As EventArgs)
           ' additional setup of the NetworkServer (in some cases this even 
           ' allows to avoid defining a custom NetworkServer class)
           ' also Started, Stopping and Stopped events are available
       End Sub

   server.Run(args)
   Return 0
End Function

Custom GUI

A custom WinForms form can be provided as custom GUI to be shown instead of the default one. It has to be marked with the ServerInfrastructure attribute and has to provide a constructor that accepts a String (the application name) and an INetworkServer instance.

It is up to the form class to activate and deactivate the network server based on user's actions. A simples custom GUI form could look like this:

[ServerInfrastructure]
public partial class ServerGui : Form
{
   private readonly INetworkServer _networkServer;

   public ServerGui()
   {
       InitializeComponent();
   }

   public ServerGui(String serverName, INetworkServer networkServer) : this()
   {
       this.Text = serverName;
       this._networkServer = networkServer;

       this._networkServer.Start();
   }

   private void ServerGui_FormClosed(object sender, FormClosedEventArgs e)
   {
       this._networkServer.Stop();
   }
}
type
 ServerGUI = partial class(System.Windows.Forms.Form)
 private
 {$REGION designer-generated code}
   method CustomGUI_FormClosed(sender: Object; e: FormClosedEventArgs);
 {$ENDREGION}
   var fNetworkServer: INetworkServer; readonly;
 protected
   method Dispose(aDisposing: Boolean); override;
 public
   constructor();
   constructor(serverName: String;  networkServer: INetworkServer);
 end;
 
//...

constructor CustomGUI(serverName: String;  networkServer: INetworkServer);
begin
 constructor();

 self.Text := serverName;
 self.fNetworkServer := networkServer;

 self.fNetworkServer.Start();
end;

method CustomGUI.Dispose(aDisposing: Boolean);
begin
 if aDisposing then begin
   if assigned(components) then
     components.Dispose();
 end;
 inherited Dispose(aDisposing);
end;

method CustomGUI.CustomGUI_FormClosed(sender: Object; e: FormClosedEventArgs);
begin
 self.fNetworkServer.Stop();
end;
@ServerInfrastructure
public __partial class CustomGUI: Form {
   private var _networkServer: INetworkServer!

   public init()    {

       InitializeComponent()
   }

   public init(_ serverName: String!, _ networkServer: INetworkServer!) {
       InitializeComponent()

       self.Text = serverName
       self._networkServer = networkServer
       self._networkServer.Start()

       self.FormClosed += { (s, e) in
           self._networkServer.Start()
       }
   }
}
<ServerInfrastructure> _
Public Class CustomGUI
   Private _networkServer As INetworkServer

   Public Sub New(serverName As String, networkServer As INetworkServer)
       ' This call is required by the designer.
       InitializeComponent()

       Me.Text = serverName
       Me._networkServer = networkServer
       Me._networkServer.Start()
   End Sub

   Private Sub CustomGUI_FormClosed(sender As Object, e As FormClosedEventArgs) _ 
                                                          Handles MyBase.FormClosed
       Me._networkServer.Stop()
   End Sub
End Class