fixes for daily build target
misc updates to ref documentation use signed NNS assembly based on spring.net key sync vs.net 2003 solution
This commit is contained in:
@@ -172,472 +172,4 @@ usage:
|
||||
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 <classname>IObjectFactoryPostProcessor</classname> and so will be
|
||||
automatically applied to this application context:
|
||||
<programlisting format='linespecific'>
|
||||
<!-- provides access to the ${spring.services.process.base.dir} property -->
|
||||
<object
|
||||
name="localizer"
|
||||
type="Spring.Services.WindowsService.Common.Localizer+ForProcess, Spring.Services.WindowsService.Common">
|
||||
<!-- change this to access the property with another prefix, for example ${foo.process.base.dir}
|
||||
<property name="prefix" value="foo"/>
|
||||
-->
|
||||
</object></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
In that object definition you can customize the prefix for the following string
|
||||
<programlisting format='linespecific'>
|
||||
public static readonly string SpringServicesProcessBaseDirFormat = "{0}.process.base.dir";</programlisting>
|
||||
but you usually won't need it; the default value is
|
||||
<programlisting format='linespecific'>
|
||||
public static readonly string DefaultPrefix = "spring.services";</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The sole important object defined by this context, i.e. the main object run by the service.
|
||||
The thing you can (and should) configure is the path to the folder you will use as the deploy location;
|
||||
the current definition, to avoid the need for a fully qualified path (e.g.: <literal>c:\spring\services</literal>) uses
|
||||
the properties made available by the <literal>localizer</literal> above:
|
||||
<programlisting format='linespecific'>
|
||||
<object
|
||||
name="service"
|
||||
type="Spring.Services.WindowsService.Common.DefaultService, Spring.Services.WindowsService.Common"
|
||||
init-method="Start"
|
||||
destroy-method="Stop">
|
||||
<property name="DeployPath" value="${spring.services.process.base.dir}/deploy"/>
|
||||
</object></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The above object is then easily remoted using spring remoting utilities (please notice you should tune the remoting configuration
|
||||
listed in the standard .NET <literal>.config</literal> file, listed above):
|
||||
<programlisting format='linespecific'>
|
||||
<object name="remoted.service" type="Spring.Remoting.SaoExporter, Spring.Services">
|
||||
<property name="TargetName" value="service"/>
|
||||
<property name="ServiceName" value="SpringWindowsService.rem"/>
|
||||
</object></programlisting>
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Running an application context as a windows service</title>
|
||||
<para>
|
||||
If you package an application using the layout and
|
||||
conventions described here, you'll be able to run an
|
||||
application context as a Windows Service.
|
||||
The conventions used are modeled after those used by ASP.NET
|
||||
and are very easy to follow.
|
||||
</para>
|
||||
<para>
|
||||
As already said, you'll have a Spring.NET application context running in
|
||||
a dedicated <literal>AppDomain</literal> hosted in a process running
|
||||
as a windows service: that process is able to run many application contexts
|
||||
simultaneously.
|
||||
</para>
|
||||
<para>A complete application runable as service consists of a
|
||||
directory containing:
|
||||
<itemizedlist spacing="compact">
|
||||
|
||||
<listitem>
|
||||
<para>The .NET configuration file
|
||||
<literal>service.config</literal>:
|
||||
this file should define your application context.
|
||||
Moreover this files will be used
|
||||
by the CLR to configure the application domain
|
||||
your application will run in, exactly as you expect.
|
||||
This file has the same role of ASP.NET <literal>Web.config</literal>
|
||||
file.
|
||||
</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Optional: an xml context file (<literal>watcher.xml</literal>)
|
||||
defining the watcher for your application.</para>
|
||||
<para>The watcher controls the automatic redeployment of the
|
||||
service and is discussed more in the following section.</para>
|
||||
</listitem>
|
||||
|
||||
<listitem>
|
||||
<para>Recomended: along the lines of ASP.NET convention, a <literal>bin</literal>
|
||||
subdirectory containing all
|
||||
the assemblies your application needs; you can of course put
|
||||
your assemblies in the same directory where you put
|
||||
<literal>service.config</literal> but this is not encouraged ...
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<sect2>
|
||||
<title><literal>service.config</literal></title>
|
||||
<para>
|
||||
This is the standard .NET configuration file for the
|
||||
<literal>AppDomain</literal> that will host your application. It is
|
||||
semantically equivalent to the ASP.NET <literal>Web.config</literal>
|
||||
file.
|
||||
<footnote>
|
||||
<para>
|
||||
<literal>log4net</literal> users please notice that (as
|
||||
of 1.2 beta 9) file appenders, when dealing with a relative
|
||||
file name, assume it is relative to the application
|
||||
domain code base. If you use log4net, it is very handy with the mechanics used by
|
||||
Spring Windows Service as every log file you will specify will
|
||||
be relative the directory containing the service application.
|
||||
</para>
|
||||
</footnote>
|
||||
</para>
|
||||
<para>
|
||||
This file should also define your application context. When the
|
||||
service is started and stopped, the corresponding lifecycle methods
|
||||
are called on all the singletons defined. Of course, singletons are
|
||||
automatically instantiated by the application context when the
|
||||
service starts. For more information on lifecycles in Spring.NET see
|
||||
<xref linkend="objects-factory-lifecycle"/>
|
||||
Here an example taken from the tests:
|
||||
<programlisting format='linespecific'>
|
||||
<configuration>
|
||||
|
||||
<configSections>
|
||||
<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>
|
||||
|
||||
<appSettings>
|
||||
<add key="port" value="10"/>
|
||||
</appSettings>
|
||||
|
||||
<spring>
|
||||
<context type="Spring.Context.Support.XmlApplicationContext, Spring.Core">
|
||||
<resource uri="file://~/service.xml" />
|
||||
</context>
|
||||
</spring>
|
||||
|
||||
</configuration></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
In this case the context is (again!) defined in another file (author's personal taste...) and the only 'service' is the
|
||||
<literal>echo</literal> object (there is also a <literal>PropertyPlaceholderConfigurer</literal> just to make the example
|
||||
more realistic):
|
||||
<programlisting format='linespecific'>
|
||||
<objects xmlns="http://www.springframework.net"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd">
|
||||
|
||||
<object name="echo"
|
||||
type="Spring.Services.WindowsService.Samples.Echo, Spring.Services.WindowsService.Tests"
|
||||
init-method="Start" destroy-method="Stop">
|
||||
<property name="port"><value>${port}</value></property>
|
||||
</object>
|
||||
|
||||
<object id="configurer" type="Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core">
|
||||
<property name="locations">
|
||||
<list>
|
||||
<value>file://~/service.config</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="configSections">
|
||||
<list>
|
||||
<value>appSettings</value>
|
||||
</list>
|
||||
</property>
|
||||
</object>
|
||||
|
||||
</objects></programlisting>
|
||||
</para>
|
||||
<sect3>
|
||||
<title>Let the application know where it is</title>
|
||||
<para>
|
||||
There are some properties you may need at runtime, when your services
|
||||
will run, and you cannot know in advance. Hopefully, your xml
|
||||
definition file will allow to find the information it needs using some
|
||||
predefined variables you can use inside the service definition file
|
||||
with the standard
|
||||
NAnt style <literal>${property name}</literal> syntax.</para>
|
||||
<para>These properies are:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para><literal>spring.services.application.fullpath</literal>
|
||||
that will be replaced with the full path of the application's
|
||||
<literal>AppDomain.BaseDirectory</literal>, i.e., where your
|
||||
application has been deployed;</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para><literal>spring.services.application.name</literal> that
|
||||
will be replaced with the name of the subdirectory where the
|
||||
application has been deployed. Each application is deployed in
|
||||
its own directory, of course;</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
These properties are accessible only if one defines a localizer in the
|
||||
context like this (the localizer is a special <literal>IObjectFactoryPostProcessor</literal>:
|
||||
<programlisting format='linespecific'>
|
||||
<!-- provides access to the ${spring.services.application.*} properties -->
|
||||
<object
|
||||
name="localizer"
|
||||
type="Spring.Services.WindowsService.Common.Localizer+ForApplication, Spring.Services.WindowsService.Common">
|
||||
<!-- change this to access the property with another prefix, for example ${foo.application.base.dir}
|
||||
-->
|
||||
<property name="prefix" value="myPrefix"/>
|
||||
</object></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
As you can see above, one can easily change the prefix used by that localizer and then write someting like:
|
||||
<programlisting format='linespecific'>
|
||||
<object name="simple"
|
||||
type="Spring.Services.WindowsService.Samples.Simple, Spring.Services.WindowsService.Tests"
|
||||
init-method="Start" destroy-method="Stop">
|
||||
<constructor-arg index="0" value="${myPrefix.application.name},${myPrefix.application.fullPath}"/>
|
||||
<property name="AppName">
|
||||
<value>${myPrefix.application.name}</value>
|
||||
</property>
|
||||
<property name="AppFullPath">
|
||||
<value>${myPrefix.application.fullpath}</value>
|
||||
</property>
|
||||
</object></programlisting>
|
||||
</para>
|
||||
</sect3>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title><literal>watcher.xml</literal> - optional</title>
|
||||
<para>
|
||||
This file allows you to optionally define a watcher for your application
|
||||
that can automatically redeploy it when needed.
|
||||
</para>
|
||||
<para>
|
||||
The important thing to notice is that you can define your own
|
||||
application watcher, named <literal>watcher</literal>. Here it is used
|
||||
a watcher that listen for changes on the filesystem, configured to
|
||||
listen for some changes and to ignore others.
|
||||
</para>
|
||||
<para>
|
||||
You can provide your own implementation defining an object named
|
||||
<literal>watcher</literal> that implements
|
||||
<literal>Spring.Services.WindowsService.Common.Deploy.IApplicationWatcher</literal>:
|
||||
<programlisting format='linespecific'>
|
||||
/// <summary>
|
||||
Interface defining the contract for an application watcher.
|
||||
<p>An application watcher is responsible to dispatch an
|
||||
<see cref="IApplicationWatcherFactory">event</see> whenever it thinks the
|
||||
application has been updated.</p>
|
||||
<p>Usually it should not raise other kind of events
|
||||
as they are usually raised by the <see cref="FileSystemApplicationWatcher"/>
|
||||
that creates the watcher itself</p>
|
||||
</summary>
|
||||
<remarks>Usually instances of this interface need to be disposed</remarks>
|
||||
<seealso cref="DeployEventArgs"/>
|
||||
<seealso cref="IDeployLocation"/>
|
||||
<seealso cref="DeployEventType.ApplicationUpdated"/>
|
||||
<seealso cref="DeployEventAggregator"/>
|
||||
<seealso cref="IDeployLocation"/>
|
||||
<seealso cref="DeployEventType"/>
|
||||
public interface IApplicationWatcher : IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The watched application
|
||||
/// </summary>
|
||||
IApplication Application {get; }
|
||||
|
||||
/// <summary>
|
||||
/// Start to watch the application, using the given dispatcher to
|
||||
/// dispatch deply events
|
||||
/// </summary>
|
||||
/// <param name="dispatcher">the dispatcher used to raise deploy events</param>
|
||||
void StartWatching (IDeployEventDispatcher dispatcher);
|
||||
|
||||
/// <summary>
|
||||
/// Stop to watch the application.
|
||||
/// </summary>
|
||||
void StopWatching ();
|
||||
|
||||
/// <summary>
|
||||
/// If physical events watched by this watcher should be filtered, this methods
|
||||
/// will allow to set filters that allows and disallows the event to be raised
|
||||
/// by the watcher.
|
||||
/// </summary>
|
||||
/// <param name="allows">the list of allowing filters</param>
|
||||
/// <param name="disallows">the list of disallowing filters</param>
|
||||
/// <seealso cref="FilteringSupport"/>
|
||||
/// <seealso cref="RegularExpressionFilter"/>
|
||||
void SetFilters (IList allows, IList disallows);
|
||||
}</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Please notice that this interface is currently a movable target and
|
||||
will probably change before the first official release (this will probably
|
||||
affect also the way a watcher will know about the application it should
|
||||
monitor, as shown in a few lines).
|
||||
</para>
|
||||
<para>A tipical example of this file is give here:
|
||||
<programlisting format='linespecific'>
|
||||
<objects>
|
||||
|
||||
<object name='watcher'
|
||||
type='Spring.Services.WindowsService.Common.Deploy.FileSystem.FileSystemApplicationWatcher'>
|
||||
<!--
|
||||
we can get access to the IApplication we are asked to monitor
|
||||
using a reference like the following
|
||||
-->
|
||||
<constructor-arg ref='.injected.application'/>
|
||||
|
||||
<!-- sometimes the windows OS will decide to not give you the same case you see in explorer:
|
||||
in fact one should consider this OS case-insensitive with regard to file names ...
|
||||
The following property, true by default can however be tuned
|
||||
<property name="ignoreCase" value="false"/>
|
||||
-->
|
||||
|
||||
<property name="includes">
|
||||
<list>
|
||||
<value>wwwroot/bin/*.*</value>
|
||||
<value>service.config</value>
|
||||
<value>service.xml</value>
|
||||
</list>
|
||||
</property>
|
||||
|
||||
<!--
|
||||
<property name="excludes">
|
||||
<list>
|
||||
<value>Db/**/*.*</value>
|
||||
<value>Jobs</value>
|
||||
<value>Jobs</value>
|
||||
<value>**/*.log</value>
|
||||
</list>
|
||||
</property>
|
||||
-->
|
||||
|
||||
</object>
|
||||
|
||||
</objects></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
As you can see, if you need it, you can reference the
|
||||
<literal>Spring.Services.WindowsService.Common.IApplication</literal>
|
||||
object that your watcher should watch using the name
|
||||
<literal>.injected.application</literal>.</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title><literal>bin</literal> directory - optional</title>
|
||||
<para>
|
||||
This is, by default, the folder where your assemblies are placed
|
||||
in the same way they are in an ASP.NET application.
|
||||
</para>
|
||||
<para>
|
||||
Putting assemblies there is more a convention and maybe a good
|
||||
practice (they are isolated from other artifacts, but maybe you will
|
||||
prefer to use another directory (modify the
|
||||
<literal>service.config</literal> file accordingly) or the application
|
||||
directory directly (= <literal>bin</literal> parent).
|
||||
</para>
|
||||
<para>
|
||||
Be aware of the fact that the process in which your application will
|
||||
run will have its own PATH environmental variable. As such
|
||||
don't expect to be successfull using dlls imported
|
||||
with [DllImport] if they are not in the system PATH of the
|
||||
hosting machine: while it is well known that the CLR fusion
|
||||
algorithm will not consider the PATH variable, you may be biten
|
||||
by assemblies using non-system dlls (SQLite and Firebird ADO.NET
|
||||
providers are good examples).
|
||||
</para>
|
||||
<para>Reiterating, one can put assemblies in another directory
|
||||
under the application directory tree, and write
|
||||
the .NET configuration file (<literal>service.config</literal>)
|
||||
accordingly: .NET probing algorithm is always in place.
|
||||
</para>
|
||||
<para>
|
||||
Please notice that it is not required that
|
||||
your application uses or include any of the Spring.NET assemblies:
|
||||
any object in any assembly, given it has lifecycle methods, can
|
||||
be run as a service: non invasive infrastructure support courtesy
|
||||
of Spring.NET!
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Customizing or extending</title>
|
||||
<para>
|
||||
It should be said that support for windows service has been initially
|
||||
developed with a clear but limited set of 'extension points' in mind,
|
||||
mainly related to the way you can deploy your services:
|
||||
deploy location (filesystem, zip archives, mailbox, urls, ...),
|
||||
(auto-)updating features, and so on.
|
||||
</para>
|
||||
<para>
|
||||
To better understand the following discussion, the following figure
|
||||
depicts some of the inner details of
|
||||
<literal>Spring.Services.WindowsService.Process.exe</literal>
|
||||
at run-time:
|
||||
<mediaobject>
|
||||
<imageobject>
|
||||
<imagedata align="center"
|
||||
fileref="images/spring.windows-service.png" format="png"/>
|
||||
</imageobject>
|
||||
<textobject>
|
||||
<phrase>Spring.Services.WindowsService.Process.exe run-time details</phrase>
|
||||
</textobject>
|
||||
</mediaobject>
|
||||
</para>
|
||||
<sect2>
|
||||
<title>The <literal>.config</literal> file</title>
|
||||
</sect2>
|
||||
<para>
|
||||
The executable <literal>Spring.Services.WindowsService.Process.exe</literal>
|
||||
is somewhat configured by the corresponding
|
||||
<literal>.config</literal> file.
|
||||
Please notice that this file is the most important extension point
|
||||
for windows service support, and it will probably be made more powerful
|
||||
and flexible in the future.
|
||||
</para>
|
||||
<para>
|
||||
For applications deployed in the standard way (i.e. on the filesystem
|
||||
as explained above) the updating features are configured by the
|
||||
<literal>watcher.xml</literal> file, <emphasis>if present</emphasis>,
|
||||
as already seen.
|
||||
</para>
|
||||
<para>
|
||||
There should be however, other ways to deploy your applications,
|
||||
maybe just as zip files dropped somewhere on the web or sent via
|
||||
e-mail.
|
||||
</para>
|
||||
<para>
|
||||
For these scenarios, your deploy location will be something that
|
||||
implements
|
||||
<literal>Spring.Services.WindowsService.Common.Deploy.IDeployLocation</literal>.
|
||||
<para>
|
||||
Please notice that, while questionable, it actually entends
|
||||
<literal>IDisposable</literal> <footnote><para>this has been done
|
||||
as it is possible that a deploy location holds resources that should be
|
||||
released, for example network connections, lock files or the like</para></footnote>:
|
||||
</para>
|
||||
<programlisting format='linespecific'>
|
||||
/// <summary>
|
||||
/// Interface defining how a deploy location should look like
|
||||
/// </summary>
|
||||
public interface IDeployLocation : IDeployEventSource, IDisposable
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of applications deployed at this location
|
||||
/// Usually non-valid applications are not listed
|
||||
/// </summary>
|
||||
/// <seealso cref="Application"/>
|
||||
IList Applications { get; }
|
||||
}</programlisting>
|
||||
<programlisting format='linespecific'>
|
||||
/// <summary>
|
||||
/// Interface defining the contract for an object acting as the source of
|
||||
/// deploy events (application added, removed, updated)
|
||||
/// </summary>
|
||||
/// <seealso cref="DeployEventArgs"/>
|
||||
/// <seealso cref="DeployEventHandler"/>
|
||||
public interface IDeployEventSource
|
||||
{
|
||||
/// <summary>
|
||||
/// The multicaster for deploy events
|
||||
/// </summary>
|
||||
event DeployEventHandler DeployEvent;
|
||||
}</programlisting>
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
||||
|
||||
Reference in New Issue
Block a user