Initial import!

This commit is contained in:
markpollack
2008-05-30 22:55:02 +00:00
commit c478a783c0
2978 changed files with 510966 additions and 0 deletions

Binary file not shown.

View File

@@ -0,0 +1,162 @@
<%@ CodeTemplate %>
<%@ Import Namespace="System.IO" %>
<%@ Assembly Name="AgileDocs.Core" %>
<%@ Import Namespace="AgileDocs.Core" %>
<script runat="template">
string Example(string example, string what)
{
return "<programlisting format='linespecific' xml:space='preserve'>"
+ XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(
Path.Combine("test/Spring/Spring.Core.Tests/Data/PathMatcher", "Examples.test"),
String.Format("examples/example[@name='{0}']/{1}", example, what),
new ExtractXml("#", null)))
+ "</programlisting>";
}
</script>
<chapter id="misc">
<title>Spring.NET miscellanea</title>
<sect1>
<title>Introduction</title>
<para>
This chapter contains miscellanea information on features, goodies, caveats
that does not belong to any paricular area.
</para>
</sect1>
<sect1>
<title>PathMatcher</title>
<para>
<emphasis>Note, Spring.Util.PathMatcher is
currently only available in CVS, not the RC3 release. If you want to use these feature
please get the code from CVS
<ulink url="http://opensource.atlassian.com/confluence/spring/display/NET/Project+Structure">(instructions)</ulink>
or from the download section of the
Spring.NET website that contains an .zip with the full CVS tree.
</emphasis>
</para>
<para>
<literal>Spring.Util.PathMatcher</literal> provides <literal>Ant/NAnt</literal>-like path name matching
features.
</para>
<para>To do the match, you use the method:
<programlisting format='linespecific' xml:space='preserve'><%=
XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(
"src/Spring/Spring.Core/Util/PathMatcher.cs",
"fragments/fragment[@name='match-method']"))
%></programlisting>
</para>
<para>If you want to decide if case is important or not use the method:
<programlisting format='linespecific' xml:space='preserve'><%=
XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(
"src/Spring/Spring.Core/Util/PathMatcher.cs",
"fragments/fragment[@name='match-method-nocase']"))
%></programlisting>
</para>
<sect2>
<title>General rules</title>
<para>
To build your pattern, you use the <literal>*</literal>, <literal>?</literal>
and <literal>**</literal> building blocks:
<itemizedlist spacing="compact">
<listitem>
<para><literal>*</literal>: matches any number of non slash
characters;
</para>
</listitem>
<listitem>
<para><literal>?</literal>: matches exactly 1 (one) non slash/dot
character;
</para>
</listitem>
<listitem>
<para><literal>**</literal>: matches any subdirectory, without
taking care of the depth;
</para>
</listitem>
</itemizedlist>
</para>
</sect2>
<sect2>
<title>Matching filenames</title>
<para>
A file name can be matched using the following
notation:
<%= Example("filename", "pattern") %>
matches:
<%= Example("filename", "match") %>
does not match:
<%= Example("filename", "dont.match") %>
</para>
<para>
The classical all files pattern:
<%= Example("filename-all", "pattern") %>
matches:
<%= Example("filename-all", "match") %>
does not match:
<%= Example("filename-all", "dont.match") %>
</para>
</sect2>
<sect2>
<title>Matching subdirectories</title>
<para>
A directory name can be matched at any depth level using the following
notation:
<%= Example("subdir", "pattern") %>
That pattern matches the following paths:
<%= Example("subdir", "match") %>
but does not match these:
<%= Example("subdir", "dont.match") %>
</para>
<para>
You can compose subdirectories to match like this:
<%= Example("double-subdir", "pattern") %>
That pattern matches the following paths:
<%= Example("double-subdir", "match") %>
but does not match these:
<%= Example("double-subdir", "dont.match") %>
</para>
<para>
You can use more advanced patterns:
<%= Example("subdir-2", "pattern") %>
matches:
<%= Example("subdir-2", "match") %>
does not match:
<%= Example("subdir-2", "dont.match") %>
</para>
</sect2>
<sect2>
<title>Case does matter, slashes don't</title>
<para>
.NET is expected to be a cross-platform development ... platform. So,
<literal>PathMatcher</literal> will match taking care of the case of the pattern
and the case of the path. For example:
<%= Example("case-sensitive", "pattern") %>
matches:
<%= Example("case-sensitive", "match") %>
but does not match:
<%= Example("case-sensitive", "dont.match") %>
</para>
<para>If you do not matter about case, you should explicitly tell the
<literal>Pathmatcher</literal>.</para>
<para>
Back and forward slashes, in the very same cross-platform spirit, are
not important:
<%= Example("slashes", "pattern") %>
matches all the following paths:
<%= Example("slashes", "match") %>
</para>
</sect2>
</sect1>
</chapter>

View File

@@ -0,0 +1,158 @@
<%@ CodeTemplate %>
<%@ Import Namespace="System.IO" %>
<%@ Assembly Name="AgileDocs.Core" %>
<%@ Import Namespace="AgileDocs.Core" %>
<script runat="template">
string PoolExample (string fileName, string xpath)
{
return "<programlisting format='linespecific' xml:space='preserve'>"
+ XmlPeek.HtmlEncode (
XmlPeek.ExtractAndQueryXPath(
Path.Combine("examples/Spring/Spring.Examples.Pool/Examples/Pool", fileName),
String.Format("examples/example[@name='{0}']", xpath)))
+ "</programlisting>";
}
</script>
<sect1>
<title>Pooling example</title>
<para>
The idea is to build an executor backed by a pool of
<literal>QueuedExecutor</literal>: this will show how Spring.NET
provides some useful low-level/high-quality reusable threading and
pooling abstractions.
This executor will provide parallel executions (in our case
<literal>grep</literal>-like file scans). <emphasis>Note: This example
is not in the 1.0.0 release to its use of classes in the Spring.Threading
namespace scheduled for release in Spring 1.1. To access ths example
please get the code from CVS <ulink url="http://opensource.atlassian.com/confluence/spring/display/NET/Project+Structure">(instructions)</ulink> or from the download section of the
Spring.NET website that contains an .zip with the full CVS tree.</emphasis>
</para>
<para>
Some information on <literal>QueuedExecutor</literal> is helpful to
better understand the implementation and to possibly disagree with it.
Keep in mind that the point is to show how to develop your own
object-pool.
</para>
<para>
A <literal>QueuedExecutor</literal> is an executor where
<literal>IRunnable</literal> instances are run serialy by a worker
thread. When you <literal>Execute</literal> with a
<literal>QueuedExecutor</literal>, your request is queued; at some
point in the future your request will be taken and executed by the
worker thread: in case of error the thread is terminated.
However
this executor recreates its worker thread as needed.
</para>
<para>Last but not least, this executor can be shut down in
a few different ways (please refer to the Spring.NET SDK documentation).
Given its simplicity, it is very powerful.
</para>
<para>
The example project <literal>Spring.Examples.Pool</literal> provides
an implementation of a pooled executor, backed by n instances of
<literal>Spring.Threading.QueuedExecutor</literal>: please ignore
the fact that <literal>Spring.Threading</literal> includes already a
very different implementation of a <literal>PooledExecutor</literal>:
here we wanto to use a pool of <literal>QueuedExecutor</literal>s.
</para>
<para>
This executor will be used to implement a parallel
recursive <literal>grep</literal>-like console executable.
</para>
<sect2>
<title>Implementing <literal>Spring.Pool.IPoolableObjectFactory</literal></title>
<para>
In order to use the <literal>SimplePool</literal> implementation,
the first thing to do is to implement the <literal>IPoolableObjectFactory</literal>
interface. This interface is intended to be implemented by objects
that can create the type of objects that should be pooled.
The <literal>SimplePool</literal>
will call the lifecycle methods on <literal>IPoolableObjectFactory</literal> interface
(<literal>MakeObject, ActivateObject, ValidateObject, PassivateObject, and DestroyObject</literal>)
as appropriate when the pool is created, objects are borrowed and returned to the pool, and when
the pool is destroyed.
</para>
<para>
In our case, as already said, we want to to implement a pool
of <literal>QueuedExecutor</literal>. Ok, here the declaration:
<%= PoolExample("PooledQueuedExecutor.cs", "factory-declaration") %>
the first task a factory should do is to create objects:
<%= PoolExample("PooledQueuedExecutor.cs", "make") %>
and should be also able to destroy them:
<%= PoolExample("PooledQueuedExecutor.cs", "destroy") %>
</para>
<para>
When an object is taken from the pool, to satisfy a client request,
may be the object should be activated. We can possibly implement the
activation like this:
<%= PoolExample("PooledQueuedExecutor.cs", "activate") %>
even if a <literal>QueuedExecutor</literal> restarts itself as
needed and so a valid implementation could leave this method empty.
</para>
<para>
After activation, and before the pooled object can be succesfully
returned to the client, it is validated (should the object be
invalid, it will be discarded: this can lead to an empty unusable
pool
<footnote>
<para>You may think that we can provide a smarter
implementation and you are probably right. However, it is not so
difficult to create a new pool in case the old one became unusable.
It could not be your preferred choice but surely it leverages
simplicity and object immutability
</para>
</footnote>).
Here we check that the worker thread exists:
<%= PoolExample("PooledQueuedExecutor.cs", "validate") %>
</para>
<para>
Passivation, symmetrical to activation, is the process a pooled
object is subject to when the object is returned to the pool. In our
case we simply do nothing:
<%= PoolExample("PooledQueuedExecutor.cs", "passivate") %>
</para>
<para>
At this point, creating a pool is simply a matter of creating an
<literal>SimplePool</literal> as in:
<%= PoolExample("PooledQueuedExecutor.cs", "create-pool") %>
</para>
</sect2>
<sect2>
<title>Being smart using pooled objects</title>
<para>
Taking advantage of the <literal>using</literal> keyword seems
to be very important in these <literal>c#</literal> days, so we
implement a very simple helper (<literal>PooledObjectHolder</literal>)
that can allow us to do things like:
<%= PoolExample("PooledQueuedExecutor.cs", "execute") %>
without worrying about obtaining and returning an object from/to the
pool.
</para>
<para>
Here is the implementation:
<%= PoolExample("PooledQueuedExecutor.cs", "holder") %>
</para>
<para>
Please don't forget to destroy all the pooled istances once you have
finished! How? Well using something like this in
<literal>PooledQueuedExecutor</literal>:
<%= PoolExample("PooledQueuedExecutor.cs", "stop") %>
</para>
</sect2>
<sect2>
<title>Using the executor to do a parallel <literal>grep</literal></title>
<para>
The use of the just built executor is quite straigtforward but a
little tricky if we want to really exploit the pool.
<%= PoolExample("Grep.cs", "parallel-grep-class") %>
</para>
<para>
<%= PoolExample("Grep.cs", "parallel-grep-main") %>
</para>
</sect2>
</sect1>

View File

@@ -0,0 +1,37 @@
<?xml version="1.0" encoding="us-ascii"?>
<codeSmith>
<propertySet>
<!--
<property name="MyPurchaseOrder">
<PurchaseOrder xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.ericjsmith.net">
<ShipTo Name="Eric J. Smith">
<Line1>123 Test Dr.</Line1>
<City>Dallas</City>
<State>TX</State>
<Zip>75075</Zip>
</ShipTo>
<OrderDate>05-01-2003</OrderDate>
<Items>
<OrderedItem>
<ItemName>Item #1</ItemName>
<Description>Item #1 Description</Description>
<UnitPrice>5.45</UnitPrice>
<Quantity>3</Quantity>
<LineTotal>16.35</LineTotal>
</OrderedItem>
<OrderedItem>
<ItemName>Item #2</ItemName>
<Description>Item #2 Description</Description>
<UnitPrice>12.75</UnitPrice>
<Quantity>8</Quantity>
<LineTotal>102.00</LineTotal>
</OrderedItem>
</Items>
<SubTotal>45.23</SubTotal>
<ShipCost>5.23</ShipCost>
<TotalCost>50.46</TotalCost>
</PurchaseOrder>
</property>
-->
</propertySet>
</codeSmith>

View File

@@ -0,0 +1,441 @@
<%@ 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>