Windows Services
Remarks
This is functionality that will be included after the
1.0 release. If you want to use these features please get the
code from CVS
(instructions) or from the download section of the Spring.NET website that contains an
.zip with the full CVS tree.
In addition to this documentation
you can refer to the example program located at
examples\Spring\Spring.Examples.WindowsService
to better understand the package. Please check the Spring.NET
website
for the latest updates to this document.
Introduction
Developers usually create Windows Services using the
Visual Studio .NET wizard. While not difficult to do, this
procedure is repetative and does not encourage separation between
infrastructure code (windows service) and application code. This is
generally considered a "bad thing" but you can certainly disagree.
As Spring.NET can provide an explicitly managed
initialize/destroy lifecycle for singleton objects, there is
a natural synergy with the lifecycle of a Windows service.
As such, it could be very convenient to expose a Spring application
context as a Windows service. Starting and stopping the service corresponds
to creating and destroying an application context and its
contained objects. This approach provides a high level means to
declare what objects are created and destroyed when developing
a Windows service.
To do that, Spring.NET requires the installation of one physical
service able to run as services as many applications as you want - each a
logical independent service in their own application domain.
By default, the deployment and updating of the service can also
be done by copying the relevant executables to a special directory.
The executable that at present provides these features is the
Spring.Services.WindowsService.Process.exe
assembly. It makes heavy use of classes and interfaces definde in
the Spring.Services.WindowsService.Common.dll
assembly. You should reference the common assembly it if you want to
follow the advice on customization contained in the following sections
The benefits of this approach, a part from those given by separating
infrastructure code and application code (a field where Spring.NET
tries hard to succeed) is that you can think about installing a new
service at client site by simply dropping a new application assembly
in a remote directory.
The Spring.Services.WindowsService.Process.exe application
Installing
The installation can be done in two ways, using the .NET SDK
installutil.exe tool or using the more mundane
Spring.Services.WindowsService.Installer.exe;
while the former is the standard, the latter is probably
more flexible. It allows you to customize the name/display name of the
service and has the ability to install multiple times the same assembly
with different names. This can be useful in a
number of scenarios, especially where you don't like, for some
reasons, to run several different logical services under the
same physical windows service.
Be aware of the fact that the service will be installed as
running with the system account (installing with a specific
user account seems a bit buggy on Windows XP)
That said, while installutil
is documented on its own ,
the command line for
Spring.Services.WindowsService.Installer.exe
is as follow:
Spring.Services.WindowsService.Installer.exe
usage:
install service-exe-path service-display-name service-name
uninstall service-name [i|u] service-exe-path service-display-name service-name
for example, to install, you can invoke it with the following:
... install Spring.Services.WindowsService.Process.exe "Spring.Service Support" spring-service
and to uninstall it:
... uninstall spring-service
Configuration
The standard .NET .config file
can be used to tune some parameters of
Spring.Services.WindowsService.Process.exe,
(including log4net settings, for which it is recomended to consult
the log4net documentation).
This file also define the context run by this process; here the file in its current beauty:
<configuration>
<configSections>
<section name="log4net" type="System.Configuration.IgnoreSectionHandler" />
<sectionGroup name="spring">
<section name="context" type="Spring.Context.Support.ContextHandler, Spring.Core" />
<section name="objects" type="Spring.Context.Support.DefaultSectionHandler, Spring.Core" />
</sectionGroup>
</configSections>
<spring>
<context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
<resource uri="file://~/service-process-definition.xml" />
</context>
</spring>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http" port="1234" />
</channels>
</application>
</system.runtime.remoting>
<log4net>
<!-- see http://logging.apache.org/log4net/release/manual/introduction.html -->
<appender name="RollingFile" type="log4net.Appender.RollingFileAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d [%t] %-5p %c{1} - %m%n" />
</layout>
<file value="logs/Spring.Service.Process.log" />
<appendToFile value="true" />
<maximumFileSize value="500KB" />
<maxSizeRollBackups value="5" />
</appender>
<appender name="OutputDebugString" type="log4net.Appender.OutputDebugStringAppender">
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%d{HH:mm:ss,fff} %-5p %c{2}(line:%L) - %m%n" />
</layout>
</appender>
<root>
<level value="OFF" />
</root>
<logger name="Spring.Services">
<level value="ALL" />
<appender-ref ref="RollingFile" />
<appender-ref ref="OutputDebugString" />
</logger>
</log4net>
</configuration>
As you see, the context is defined in another file: let's review the objects it defines.
Firstly, it is worth notice that in order to 'localize' the service (i.e. to know where it is installed to use that directory as
base for the deploy dir as in the above file) you should define an object like this: the name is not
very important, it is important that it is an IObjectFactoryPostProcessor and so will be
automatically applied to this application context: