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:
markpollack
2008-06-17 02:13:28 +00:00
parent d56ad5a9dc
commit fc584813bb
16 changed files with 664 additions and 962 deletions

View File

@@ -54,7 +54,7 @@
<title>The Spring.NET Framework</title>
<subtitle>Reference Documentation</subtitle>
<releaseinfo>Version 1.1.2</releaseinfo>
<pubdate>Last Updated May 6, 2008</pubdate>
<pubdate>Last Updated June 12, 2008</pubdate>
<authorgroup>
<author>
<firstname>Mark</firstname>
@@ -288,6 +288,7 @@
&services;
&webservices;
</part>
<!--
<part id="spring-integration">
<title>Integration</title>
<partintro id="spring-integration-intro">
@@ -305,9 +306,10 @@
</listitem>
</itemizedlist>
</partintro>
&jms;
&nms;
&scheduling;
</part>
-->
<part id="index-vsnet">
<title>VS.NET Integration</title>
<partintro>

View File

@@ -1,441 +0,0 @@
<%@ CodeTemplate %>
<%@ Assembly Name="System.Web" %>
<%@ Import Namespace="System.IO" %>
<%@ Import Namespace="System.Xml" %>
<%@ Import Namespace="System.Web" %>
<%@ Import Namespace="System.Text" %>
<%@ Assembly Name="AgileDocs.Core" %>
<%@ Import Namespace="AgileDocs.Core" %>
<script runat="template">
string XmlExample (string fileName, string xpath)
{
return "<programlisting format='linespecific'>"
+ XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(fileName, xpath,
new ExtractXml("<!--@", "@-->")))
+ "</programlisting>";
}
string CsExample (string fileName, string xpath)
{
return "<programlisting format='linespecific'>"
+ XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(fileName, xpath,
new ExtractXml("////", null)))
+ "</programlisting>";
}
string EntireFile (string fileName)
{
return "<programlisting format='linespecific'>"
+ XmlPeek.HtmlEncode (
XmlPeek.GetFileContent(fileName))
+ "</programlisting>";
}
</script>
<chapter id="windows-service">
<title>Windows Services</title>
<sect1>
<title>Remarks</title>
<para>
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 <ulink url="http://opensource.atlassian.com/confluence/spring/display/NET/Project+Structure"></ulink>
(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
<literal>examples\Spring\Spring.Examples.WindowsService</literal>
to better understand the package. Please check the Spring.NET
<ulink url="http://www.springframework.net/doc/reference/windows-service.html">website</ulink>
for the latest updates to this document.
</para>
</sect1>
<sect1>
<title>Introduction</title>
<para>
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.
</para>
<para>
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.
</para>
<para>
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.
</para>
<para>
The executable that at present provides these features is the
<literal>Spring.Services.WindowsService.Process.exe</literal>
assembly. It makes heavy use of classes and interfaces definde in
the <literal>Spring.Services.WindowsService.Common.dll</literal>
assembly. You should reference the common assembly it if you want to
follow the advice on customization contained in the following sections
</para>
<para>
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<footnote></footnote>.
</para>
</sect1>
<sect1>
<title>The <literal>Spring.Services.WindowsService.Process.exe</literal> application</title>
<sect2>
<title>Installing</title>
<para>
The installation can be done in two ways, using the .NET SDK
<literal>installutil.exe</literal> tool or using the more mundane
<literal>Spring.Services.WindowsService.Installer.exe</literal>;
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.
</para>
<para><emphasis>
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)
</emphasis></para>
<para>
That said, while <literal>installutil</literal>
<ulink url="http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cptools/html/cpconinstallerutilityinstallutilexe.asp">
<citetitle>is documented on its own </citetitle></ulink>,
the command line for
<literal>Spring.Services.WindowsService.Installer.exe</literal>
is as follow:
<programlisting format='linespecific'>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</programlisting>
for example, to install, you can invoke it with the following:
<programlisting format='linespecific'>... install Spring.Services.WindowsService.Process.exe "Spring.Service Support" spring-service</programlisting>
and to uninstall it:
<programlisting format='linespecific'>... uninstall spring-service</programlisting>
</para>
</sect2>
<sect2>
<title>Configuration</title>
<para>
The standard .NET <literal>.config</literal> file
can be used to tune some parameters of
<literal>Spring.Services.WindowsService.Process.exe</literal>,
(including log4net settings, for which it is recomended to consult
the log4net documentation).
</para>
<para>
This file also define the context run by this process; here the file in its current beauty:
<%= XmlExample("src/Spring/Spring.Services/App.config", "code") %>
</para>
<para>
As you see, the context is defined in another file: let's review the objects it defines.
</para>
<para>
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 <classname>IObjectFactoryPostProcessor</classname> and so will be
automatically applied to this application context:
<%= XmlExample("src/Spring/Spring.Services/WindowsService/Process/service-process-definition.xml", "code/localizer") %>
</para>
<para>
In that object definition you can customize the prefix for the following string
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Localizer.cs", "code/process.format") %>
but you usually won't need it; the default value is
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Localizer.cs", "code/localizer.def.prefix") %>
</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:
<%= XmlExample("src/Spring/Spring.Services/WindowsService/Process/service-process-definition.xml", "code/service") %>
</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):
<%= XmlExample("src/Spring/Spring.Services/WindowsService/Process/service-process-definition.xml", "code/remoted.service") %>
</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:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.config", "code") %>
</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):
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Echo/service.xml", "code") %>
</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>:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml", "code/localizer") %>
</para>
<para>
As you can see above, one can easily change the prefix used by that localizer and then write someting like:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Simple/service.xml", "code/simple") %>
</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>:
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Deploy/IApplicationWatcher.cs", "code/interface") %>
</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:
<%= XmlExample("test/Spring/Spring.Services.Tests/Data/Spring/WindowsService/Cassini/watcher.xml", "code") %>
</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>
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Deploy/IDeployLocation.cs", "code/interface") %>
<%= CsExample("src/Spring/Spring.Services/WindowsService/Common/Deploy/IDeployEventSource.cs", "code/interface") %>
</para>
</sect1>
</chapter>

View File

@@ -917,7 +917,7 @@ mgr.DeleteTwoTestObjects("Jack", "Jill");
<programlisting>&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.net/schema/tx"
xmlns:tx="http://www.springframework.net/tx"
xmlns:db="http://www.springframework.net/database"
xsi:schemaLocation="http://www.springframework.net http://www.springframework.net/schema/objects/spring-objects.xsd
http://www.springframework.net/schema/tx http://www.springframework.net/schema/tx/spring-tx-1.1.xsd"

View File

@@ -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'>
&lt;!-- provides access to the ${spring.services.process.base.dir} property --&gt;
&lt;object
name=&quot;localizer&quot;
type=&quot;Spring.Services.WindowsService.Common.Localizer+ForProcess, Spring.Services.WindowsService.Common&quot;&gt;
&lt;!-- change this to access the property with another prefix, for example ${foo.process.base.dir}
&lt;property name=&quot;prefix&quot; value=&quot;foo&quot;/&gt;
--&gt;
&lt;/object&gt;</programlisting>
</para>
<para>
In that object definition you can customize the prefix for the following string
<programlisting format='linespecific'>
public static readonly string SpringServicesProcessBaseDirFormat = &quot;{0}.process.base.dir&quot;;</programlisting>
but you usually won't need it; the default value is
<programlisting format='linespecific'>
public static readonly string DefaultPrefix = &quot;spring.services&quot;;</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'>
&lt;object
name=&quot;service&quot;
type=&quot;Spring.Services.WindowsService.Common.DefaultService, Spring.Services.WindowsService.Common&quot;
init-method=&quot;Start&quot;
destroy-method=&quot;Stop&quot;&gt;
&lt;property name=&quot;DeployPath&quot; value=&quot;${spring.services.process.base.dir}/deploy&quot;/&gt;
&lt;/object&gt;</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'>
&lt;object name=&quot;remoted.service&quot; type=&quot;Spring.Remoting.SaoExporter, Spring.Services&quot;&gt;
&lt;property name=&quot;TargetName&quot; value=&quot;service&quot;/&gt;
&lt;property name=&quot;ServiceName&quot; value=&quot;SpringWindowsService.rem&quot;/&gt;
&lt;/object&gt;</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'>
&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name=&quot;spring&quot;&gt;
&lt;section name=&quot;context&quot; type=&quot;Spring.Context.Support.ContextHandler, Spring.Core&quot; /&gt;
&lt;section name=&quot;objects&quot; type=&quot;Spring.Context.Support.DefaultSectionHandler, Spring.Core&quot; /&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;appSettings&gt;
&lt;add key=&quot;port&quot; value=&quot;10&quot;/&gt;
&lt;/appSettings&gt;
&lt;spring&gt;
&lt;context type=&quot;Spring.Context.Support.XmlApplicationContext, Spring.Core&quot;&gt;
&lt;resource uri=&quot;file://~/service.xml&quot; /&gt;
&lt;/context&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</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'>
&lt;objects xmlns=&quot;http://www.springframework.net&quot;
xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation=&quot;http://www.springframework.net http://www.springframework.net/xsd/spring-objects.xsd&quot;&gt;
&lt;object name=&quot;echo&quot;
type=&quot;Spring.Services.WindowsService.Samples.Echo, Spring.Services.WindowsService.Tests&quot;
init-method=&quot;Start&quot; destroy-method=&quot;Stop&quot;&gt;
&lt;property name=&quot;port&quot;&gt;&lt;value&gt;${port}&lt;/value&gt;&lt;/property&gt;
&lt;/object&gt;
&lt;object id=&quot;configurer&quot; type=&quot;Spring.Objects.Factory.Config.PropertyPlaceholderConfigurer, Spring.Core&quot;&gt;
&lt;property name=&quot;locations&quot;&gt;
&lt;list&gt;
&lt;value&gt;file://~/service.config&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;property name=&quot;configSections&quot;&gt;
&lt;list&gt;
&lt;value&gt;appSettings&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;/object&gt;
&lt;/objects&gt;</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'>
&lt;!-- provides access to the ${spring.services.application.*} properties --&gt;
&lt;object
name=&quot;localizer&quot;
type=&quot;Spring.Services.WindowsService.Common.Localizer+ForApplication, Spring.Services.WindowsService.Common&quot;&gt;
&lt;!-- change this to access the property with another prefix, for example ${foo.application.base.dir}
--&gt;
&lt;property name=&quot;prefix&quot; value=&quot;myPrefix&quot;/&gt;
&lt;/object&gt;</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'>
&lt;object name=&quot;simple&quot;
type=&quot;Spring.Services.WindowsService.Samples.Simple, Spring.Services.WindowsService.Tests&quot;
init-method=&quot;Start&quot; destroy-method=&quot;Stop&quot;&gt;
&lt;constructor-arg index=&quot;0&quot; value=&quot;${myPrefix.application.name},${myPrefix.application.fullPath}&quot;/&gt;
&lt;property name=&quot;AppName&quot;&gt;
&lt;value&gt;${myPrefix.application.name}&lt;/value&gt;
&lt;/property&gt;
&lt;property name=&quot;AppFullPath&quot;&gt;
&lt;value&gt;${myPrefix.application.fullpath}&lt;/value&gt;
&lt;/property&gt;
&lt;/object&gt;</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'>
/// &lt;summary&gt;
Interface defining the contract for an application watcher.
&lt;p&gt;An application watcher is responsible to dispatch an
&lt;see cref=&quot;IApplicationWatcherFactory&quot;&gt;event&lt;/see&gt; whenever it thinks the
application has been updated.&lt;/p&gt;
&lt;p&gt;Usually it should not raise other kind of events
as they are usually raised by the &lt;see cref=&quot;FileSystemApplicationWatcher&quot;/&gt;
that creates the watcher itself&lt;/p&gt;
&lt;/summary&gt;
&lt;remarks&gt;Usually instances of this interface need to be disposed&lt;/remarks&gt;
&lt;seealso cref=&quot;DeployEventArgs&quot;/&gt;
&lt;seealso cref=&quot;IDeployLocation&quot;/&gt;
&lt;seealso cref=&quot;DeployEventType.ApplicationUpdated&quot;/&gt;
&lt;seealso cref=&quot;DeployEventAggregator&quot;/&gt;
&lt;seealso cref=&quot;IDeployLocation&quot;/&gt;
&lt;seealso cref=&quot;DeployEventType&quot;/&gt;
public interface IApplicationWatcher : IDisposable
{
/// &lt;summary&gt;
/// The watched application
/// &lt;/summary&gt;
IApplication Application {get; }
/// &lt;summary&gt;
/// Start to watch the application, using the given dispatcher to
/// dispatch deply events
/// &lt;/summary&gt;
/// &lt;param name=&quot;dispatcher&quot;&gt;the dispatcher used to raise deploy events&lt;/param&gt;
void StartWatching (IDeployEventDispatcher dispatcher);
/// &lt;summary&gt;
/// Stop to watch the application.
/// &lt;/summary&gt;
void StopWatching ();
/// &lt;summary&gt;
/// 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.
/// &lt;/summary&gt;
/// &lt;param name=&quot;allows&quot;&gt;the list of allowing filters&lt;/param&gt;
/// &lt;param name=&quot;disallows&quot;&gt;the list of disallowing filters&lt;/param&gt;
/// &lt;seealso cref=&quot;FilteringSupport&quot;/&gt;
/// &lt;seealso cref=&quot;RegularExpressionFilter&quot;/&gt;
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'>
&lt;objects&gt;
&lt;object name='watcher'
type='Spring.Services.WindowsService.Common.Deploy.FileSystem.FileSystemApplicationWatcher'&gt;
&lt;!--
we can get access to the IApplication we are asked to monitor
using a reference like the following
--&gt;
&lt;constructor-arg ref='.injected.application'/&gt;
&lt;!-- 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
&lt;property name=&quot;ignoreCase&quot; value=&quot;false&quot;/&gt;
--&gt;
&lt;property name=&quot;includes&quot;&gt;
&lt;list&gt;
&lt;value&gt;wwwroot/bin/*.*&lt;/value&gt;
&lt;value&gt;service.config&lt;/value&gt;
&lt;value&gt;service.xml&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
&lt;!--
&lt;property name=&quot;excludes&quot;&gt;
&lt;list&gt;
&lt;value&gt;Db/**/*.*&lt;/value&gt;
&lt;value&gt;Jobs&lt;/value&gt;
&lt;value&gt;Jobs&lt;/value&gt;
&lt;value&gt;**/*.log&lt;/value&gt;
&lt;/list&gt;
&lt;/property&gt;
--&gt;
&lt;/object&gt;
&lt;/objects&gt;</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'>
/// &lt;summary&gt;
/// Interface defining how a deploy location should look like
/// &lt;/summary&gt;
public interface IDeployLocation : IDeployEventSource, IDisposable
{
/// &lt;summary&gt;
/// The list of applications deployed at this location
/// Usually non-valid applications are not listed
/// &lt;/summary&gt;
/// &lt;seealso cref=&quot;Application&quot;/&gt;
IList Applications { get; }
}</programlisting>
<programlisting format='linespecific'>
/// &lt;summary&gt;
/// Interface defining the contract for an object acting as the source of
/// deploy events (application added, removed, updated)
/// &lt;/summary&gt;
/// &lt;seealso cref=&quot;DeployEventArgs&quot;/&gt;
/// &lt;seealso cref=&quot;DeployEventHandler&quot;/&gt;
public interface IDeployEventSource
{
/// &lt;summary&gt;
/// The multicaster for deploy events
/// &lt;/summary&gt;
event DeployEventHandler DeployEvent;
}</programlisting>
</para>
</sect1>
</chapter>

View File

@@ -8,7 +8,7 @@
<para>This appendix details the use of XML Schema-based configuration in
Spring.</para>
<para> The <emphasis>'classic' </emphasis>
<para>The <emphasis>'classic' </emphasis>
<literal>&lt;object/&gt;</literal>-based schema is good, but its
generic-nature comes with a price in terms of configuration overhead.
Creating a custom XML Schema-based configuration makes Spring XML
@@ -58,7 +58,7 @@
you can copy and paste (!) and then plug
<literal>&lt;object/&gt;</literal> definitions into like you have always
done. However, the entire point of using custom schema tags is to make
configuration easier. </para>
configuration easier.</para>
</section>
<para>The rest of this chapter gives an overview of custom XML Schema
@@ -90,10 +90,14 @@
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;object xmlns="http://www.springframework.net"
xmlns:aop="http://www.springframework.org/schema/aop"
<emphasis role="bold"> xmlns:tx="http://www.springframework.org/schema/tx"</emphasis>&gt;
xmlns:aop="http://www.springframework.net/aop"
<emphasis role="bold"> xmlns:tx="http://www.springframework.net/tx"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;tx/&gt; transaction definitions here --&gt;
&lt;!-- &lt;aop/&gt; AOP definitions here --&gt;
&lt;/object&gt;</programlisting>
@@ -106,6 +110,28 @@
the tags in the <literal>aop</literal> namespace are available to
you.</para>
</note>
<para>You will also need to configure the AOP and Transaction namespace
parsers in the main .NET application configuration file as shown
below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" /&gt;
&lt;parser type="Spring.Transaction.Config.TxNamespaceParser, Spring.Data" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-aop">
@@ -123,12 +149,33 @@
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:aop="http://www.springframework.org/schema/aop"</emphasis>&gt;
<emphasis role="bold">xmlns:aop="http://www.springframework.net/aop"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;aop/&gt; AOP definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the AOP namespace parser in the
main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Aop.Config.AopNamespaceParser, Spring.Aop" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-db">
@@ -143,12 +190,33 @@
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:db="http://www.springframework.org/schema/db"</emphasis>&gt;
<emphasis role="bold">xmlns:db="http://www.springframework.net/db"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;db/&gt; database definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the Database namespace parser in
the main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Data.Config.DatabaseNamespaceParser, Spring.Data" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-remoting">
@@ -160,13 +228,34 @@
the chapter <xref linkend="remoting" /></para>
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.org/schema/objects"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:r="http://www.springframework.org/schema/remoting"</emphasis>&gt;
&lt;objects xmlns="http://www.springframework.net"
<emphasis role="bold">xmlns:r="http://www.springframework.net/remoting"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;r/&gt; remoting definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the remoting namespace parser in
the main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Remoting.Config.RemotingNamespaceParser, Spring.Services" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-validation">
@@ -178,13 +267,34 @@
linkend="validation" /></para>
<programlisting>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;objects xmlns="http://www.springframework.net"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<emphasis role="bold">xmlns:v="http://www.springframework.org/schema/validation"</emphasis>&gt;
&lt;objects xmlns="http://www.springframework.net"
<emphasis role="bold">xmlns:v="http://www.springframework.net/validation"</emphasis>&gt;
<lineannotation>&lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
<lineannotation> &lt;!-- <literal>&lt;object/&gt;</literal> definitions here --&gt;</lineannotation>
&lt;!-- &lt;v/&gt; valdiation definitions here --&gt;
&lt;/objects&gt;</programlisting>
<para>You will also need to configure the validation namespace parser in
the main .NET application configuration file as shown below</para>
<programlisting>&lt;configuration&gt;
&lt;configSections&gt;
&lt;sectionGroup name="spring"&gt;
&lt;!-- other Spring config sections handler like context, typeAliases, etc not shown for brevity --&gt;
&lt;section name="parsers" type="Spring.Context.Support.NamespaceParsersSectionHandler, Spring.Core"/&gt;
&lt;/sectionGroup&gt;
&lt;/configSections&gt;
&lt;spring&gt;
&lt;parsers&gt;
&lt;parser type="Spring.Validation.Config.ValidationNamespaceParser, Spring.Core" /&gt;
&lt;/parsers&gt;
&lt;/spring&gt;
&lt;/configuration&gt;</programlisting>
</section>
<section id="xsd-config-body-schemas-objects">