Little Things that make a difference. Part I. Application Base
This is the first of a set of short articles related to different Data Abstract or SDK features that I feel are important and interesting. Some of them will be just minor improvement notifications, while others will highlight something that can be called a feature but is still way too specialized to be highlighted in a big article. This first article will be about the common application base class that can be used for RemObjects SDK and Data Abstract server applications.
RemObjects SDK contains the ApplicationServer class which provides base application startup infrastructure including Windows Service management and single instance checks.
The ApplicationServer class was designed to provide a common codebase and simplify development of RemObjects SDK and Data Abstract-based server applications. It provides the following features:
- 3 application run modes – GUI mode (WinForms or WPF), command-line interface or Windows Service.
- Windows Service management (installation/deinstallation).
- Optional Single Instance check.
- Extensible startup arguments parser. The ApplicationServer class provides an overridable method to handle command-line arguments not handled by the default arguments parser. It is also possible to use your own implementation of the command line arguments parser.
- Single exception intercept point (useful for logging etc.).
By default, ApplicationServer-based applications recognize the following command-line arguments (not case-sensitive):
-I, /I, –INSTALL | Install as a Windows Service |
-U, /U, –UNINSTALL | Uninstall a Windows Service |
-Q, /Q, –QUIET | Suppress messages on service installation and uninstallation |
-C, /C, –COMMANDLINE | Run in CLI mode |
-D, /D, –DEBUG | Request extended debug info (i.e. full stack traces) |
-H, /H, -?, /? | Show command-line arguments help message |
Data Abstract project templates rely on the ApplicationServer class, but the RemObjects SDK ones are still old-fashioned Windows Forms applications. The next part of this article describes how to create a base application that can later be used as a seed for new server apps development.
- Create a new RemObjects SDK project named, say, ServerTemplate.
- Delete the ServerTemplateClient from the solution.
- Delete the Getting Started.html file from the ServerTemplate project.
- The next major steps are to provide network connectivity infrastructure, Windows Service stuff and to tie them all together using the ApplicationServer class.
First, update the licensing.licx file with the following content (so there won’t be any need to adjust the licenses file for each server project). RemObjects.SDK.Server.IpTcpServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.IpSuperHttpServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.IpHttpServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.NamedPipeServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.LocalServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.HttpSysServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.HttpSysSuperHttpServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.SuperTcpServerChannel, RemObjects.SDK.Server RemObjects.SDK.Server.EventSinkManager, RemObjects.SDK.Server RemObjects.SDK.Server.MemoryMessageQueueManager, RemObjects.SDK.Server RemObjects.SDK.Server.MemorySessionManager, RemObjects.SDK.Server RemObjects.SDK.Server.OlympiaMessageQueueManager, RemObjects.SDK.Server RemObjects.SDK.Server.OlympiaServerSessionManager, RemObjects.SDK.Server - The next step is to create a component that will perform the networking operations. Unfortunately, it is not feasible to use the components already generated by the project template, as they are placed on a Windows Form. So add a new Component Class project item and set its name to Engine. Open the component and add the IpHttpServerChannel, BinMessage and MemorySessionManager components to the designer pane. Register the newly added BinMessage component in the IpHttpServerChannel.Dispatchers collection. Also, add the following methods and properties to the Engine.cs code:
public void Start() { this.serverChannel.Activate(); } public void Stop() { this.serverChannel.Deactivate(); } public bool IsActive { get { return this.serverChannel.Active; } }
6. Now create the Windows Service definition and infrastructure it needs. Add a new Windows Service item to the project and set its name to MainService. Open the code-behind file of the newly added service and set its code to: partial class MainService : ServiceBase { private Engine _engine; protected override void OnStart(string[] args) { base.OnStart(args); this._engine = new Engine(); this._engine.Start(); } protected override void OnStop() { base.OnStop(); this._engine.Stop(); this._engine.Dispose(); this._engine = null; } protected override void OnPause() { base.OnPause(); this._engine.Stop(); } protected override void OnContinue() { base.OnContinue(); this._engine.Start(); } }
The code above is quite simple. It handles the service state change events and either creates and opens the server channel or closes it and disposes the corresponding components.
7. Now open the service in design mode again and right-click the designer pane. In the context menu, choose the Add Installer item. This command will automatically add a service installer instance that encapsulates the WinAPI calls needed to install or uninstall a Windows Service.At this point, the ServerTemplate project has almost all code and components needed to work as a Windows Service.
8. Delete the Main.cs form present in the ServerTemplate project and add a new Windows Form to the project named MainForm. Add the following code to its code-behind file: public partial class MainForm : Form { private Engine _engine; public MainForm() { // // Required for Windows Form Designer support // InitializeComponent(); this.FormClosed += OnFormClosed; this.StartServer(); } private void StartServer() { if (this.IsServerActive) { this.StopServer(); } this._engine = new Engine(); this._engine.Start(); } private void StopServer() { if (this.IsServerActive) { this._engine.Dispose(); this._engine = null; } } // Properties public bool IsServerActive { get { return ((this._engine != null) && this._engine.IsActive); } } private void OnFormClosed(object sender, FormClosedEventArgs e) { this.StopServer(); } }
9. The next step is to tie all these components together using the ApplicationServer class. Add the following class to the ServerTemplate project: using System; using System.ServiceProcess; using System.Windows.Forms; namespace ServerTemplate { sealed class ServerApplication : RemObjects.SDK.Server.ApplicationServer { private Engine _consoleEngine; protected override String Identifier { get { return "2a42e444-5b2c-4f5c-b73a-dd1cab801c0a" ; } } protected override String ServiceName { get { return "SimpleProject Service"; } } protected override String ApplicationName { get { return "SimpleProject"; } } protected override void RunAsConsoleApplication() { this._consoleEngine = new Engine(); this._consoleEngine.Start(); } protected override void ShutdownAsConsoleApplication() { this._consoleEngine.Stop(); this._consoleEngine.Dispose(); } protected override void RunAsWindowsService() { ServiceBase.Run(new MainService()); } protected override void RunAsWindowsApplication() { Application.EnableVisualStyles(); Application.Run(new MainForm()); } } }
10. And as the very last step change the application entry point code in the Program.cs file to: using System; namespace ServerTemplate { static class Program { [STAThread] static void Main(string[] args) { new ServerApplication().Run(args); } } }
And that’s it: The server application project template. Applications created using this template can be run as Windows Forms apps, Windows Services or Linux daemons and are able to install themselves as Windows Services.
If you really want a quick result but don’t want to go over all the steps, here is the download link for the project created during this article: ServerTemplate
So far the only way to use this project template is to copy it to a new place when a new SDK server app is needed. In the next article, this application will be turned into a real Visual Studio project template.