Thursday, June 26, 2008

Anyone who's read this blog long enough to see some of the larger articles can tell that I am carrying the torch for UML.  I know a lot of people who model things, but not a lot who use what I consider to be the canonical real-deal modeling language: UML.  Even when I'm whitboarding, I'm drawing actual UML constructs for classes, interfaces, packages, and components.  If you draw boxes with lines connecting them to other boxes, people will often get the idea you are trying to convey, but there's something compelling about an industry standard modeling dialect with the ability to express some more subtle semantics than "this thing somethings with this thing".  Why don't we hear that much about UML in the blogosphere?  Why is Microsoft developing its own modeling language?  To some degree I blame the round-trip engineering folks who want to keep code and models in perfect sync, and there are some idioms in CLR languages that just don't succinctly map to UML: The Terski brought up the example of delegats.  My response is and has always been that I'm not interested in modeling at the implementation level: that's what code is for.

I still keep tabs on the DSL tools team at MSFT, so it was nice to hear from Steve Cook that UML tools are going to find their way into Architecture Edition.

http://blogs.msdn.com/stevecook/archive/2008/06/25/i-ve-got-a-new-job-working-on-dsls-and-uml.aspx

Thursday, June 26, 2008 9:42:13 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, April 17, 2008

In the past I've occasionally announced something "coming soon" that never saw the light of day, and because of this I've greatly reduced the number of times that I mention any ideas that are still in the vaporware stage.  This time though I just wanted to get it out there.

I mentioned here that Unit Testing was a big chance to save developers time using concurrency.  I actually downloaded the NUnit source immediately after posting that and started looking at what it would take to get NUnit to run tests concurrently.  It's my current opinion, though I reserve the right to change my position later, that NUnit is an over engineered mess.  It uses some interesting combinations of patterns that ultimately makes an amazingly deep and hard to follow pipeline for test execution and result reporting.  The path for running a test suite goes something like this:

  1. Click "Run tests" button
  2. GUITestRunner
  3. ... passes to ThreadedTestRunnger (so the UI remains responsive)
  4. ... passes to ProxyTestRunner
  5. ... crosses a remoting boundary for some reason
  6. ... RemoteTestRunner
  7. ... passes to SimpleTestRunner
  8. Foreach unit test, execute, collect results...
  9. ... pass the results back across the remoting boundary to display in the GUI

I'm sure I'm missing at least one step in there.  The first trial of making SimpleTestRunner execute the tests in Parallel failed because there seems to be some bizarre hook in the test result capturing scheme that didn't like being threaded.  I will either track down this issue, create my own XTestRunner implementation, or blow an evening making my own unit test scheme that can run in parallel.  If I can then get TestDriven and NCover to hook into that, life would be good indeed.

Thursday, April 17, 2008 8:45:53 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Tuesday, April 08, 2008

Someone in my fan club has too much time/money on their hands.  I took this screenshot just now:

 

Tuesday, April 08, 2008 10:41:53 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, March 03, 2008

I have never been more ready for spring than I am this year.

It was a whopping 40degrees here yesterday and I took advantage of it.  I spent hours chopping ice out of my driveway, I can't type so well today due to the blisters on my fingertips.  The huge piles of snow on either side of my driveway make surprisingly good reach-level beer holding areas, and I pulled out the bbq pit and made some brats.

I also wrote a Mapping tool this weekend.  When you're first getting started it's interesting to note the similarities in flat file, XML, object-to-object, and SQL to Object mapping: at least in terms of the initial abstractions that present themselves.  I specifically wanted to solve a flat-file to complex object problem and write a tool that previews the mapping in real time and realized I couldd do quite a bit more if I weren't lazy.  The main place I could see using this in my own efforts are class-to-class mapping.  For example: if you are consuming a web service the proxy generated will return to you class instances using whatever naming conventions and object structure the designers of said service wanted to give you.  Even if another team in your organization is the maintainer of this service, Directly using these proxy types within your code is probably a mistake; mapping ProxyObject.PrimaryKey to MyDomainObject.Id quickly becomes tedious.  A mapping tool that does the annoying work for you and saves the mapping as an easy XML file or better yet generates transformation code might be helpful. 

Monday, March 03, 2008 9:50:15 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Sunday, January 27, 2008

Parallel Tasks

A while back (http://www.damonpayne.com/PermaLink,guid,fdb0de99-446c-428b-ba98-14ef8c5dfaf0.aspx) I had written about my desire to use brute force concurrency to make up for my poor prime number algorithm and started writing some code to help facilitate this.

At some point an article on the Task Parallel Library came up in my RSS reader and I also got caught up on Dot Net Rocks episodes, one of which was Joe Duffy talking about the TPL.  I went and read the article and I was generally pleased to see that the Task class and the Paralell ForEach was very generally going towards the same type of developer experience that I was shooting for with my WorkUnit<TResultType>.  Obviously, the TPL is 1000x more complete and detailed than my incredibly brief experience but in general it pleases me when I discover I was barking up the same tree as people who are far smarter than I am.

The TPL is just a CTP right now and requires the .NET Framework 3.5 which put me in a situation where I wanted to use it but couldn’t justify the risk on a production app.  I have a very intensive Data Import project that takes far too long to run through the test data set.  I wanted to show some thought processes here for the code I wrote to get some of the same functionality without TPL, which will also help one “to think parallel” in preparation for many-core systems becoming the norm in coming years.

The Command Pattern

I use the Command pattern quite a bit to chunk bits of work/responsibility into succinct and portable units.  Let’s review the summary for the Command pattern:

Encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations.

Many people use the example of a GUI action that is invokable from more than one menu but the Command pattern is all over the place in .Net, SqlCommand for example.   Breaking units of work into Commands can also help code readability quite a bit.  In the Import process I mentioned above, the Main() method was over 700 lines when I inherited it, it’s now down to 50-ish due in large part to identifying what the units of work were and Commandifying them. 

The Command pattern also lends itself to completing large workloads faster by distributing the workload over multiple cores.  Take a look at the Task class from the TPL:

class Task<T> : Task

{

  Task ( Func<T> function );

  T Value { get; }            // does an implicit wait

}

Looks a bit Command-y to me.  Unfortunately, as I’ve mentioned, I can’t really use the TPL yet so let’s describe the problem and look at the home-rolled solution.

The Process

Let’s describe a generic data import process that involves data, photos, remote sites, and a data store:

There are two ways we can use concurrency to save time here.  The first involved the entire system being blocked by network I/O during some of these operations.  The second involves some of these tasks not being dependent on each other meaning we can take advantage of more cores by running several threads.  In this particular case, the I/O blocking deserves special consideration.  Suppose I have 50,000 rows of relational data to process from a file, and each row is processed very quickly.  I also have 50,000 images to download from another file that is logically part of this import, and each image takes three seconds to download.    The compute-bound tasks could still be running while the I/O bound tasks are taking their sweet time.  Now that we have a problem, let’s look at using commands and parallelism to save me time when I’m testing this import.

Solutions

After considering my problem I can clearly see that I want to have a DataImportCommand that I can treat generically by the task scheduling code I’m about to write.  From the Activity Diagram above, I decide on the following population of classes to model my problem:

 

In the Main() method I build up a List<DataImportCommand> in the logical order I would execute them in sequentially.  If I could use the TPL and these DataImportCommands had no dependencies I could use Paralell.For(myCommandList) since my generic list implements IEnumerable<T>.    I can’t, and they do, so we have two more items to design.

Using Threads

One thing that the TPL does that I have not home-rolled is to have a smart work-stealing task scheduler.  You want to have your work scheduled such that there is one Task (Command) running on every available CPU core at any given time.  At first thought I thought ThreadPool.QueueUserWorkItem would be the appropriate tool.  Reviewing the documentation for QueueUserWorkItem (which is always a good idea to do when writing thread code) this isn’t a good idea.  The managed thread pool should not be used for long running tasks and should not be used if you need to change the priority of threads.  Some of our DataImportCommands are surely long running, and when I deal with the Command dependency issue in a moment I may care about thread priority.  The managed thread pool is really for delegates and short tasks and such, so I spin up one real thread per DataImportCommand.  This is something you must consider on a case by case basis.  In this case I’ll really only have 6-10 Commands to do for one import.  According to a Dot Net Rocks guest, Outlook spins up 60 threads immediately upon starting so I’m not too concerned (yet) about having too many threads running.

                foreach (DataImportCommand cmd in commands)

                {

                    log.Info("Queing " + cmd);

                    ThreadStart ts = new ThreadStart(cmd.Execute);

                    Thread t = new Thread(ts);

                    t.Name = cmd.FriendlyName + "WorkerThread";

                    if (cmd.HasDependencies)

                    {

                        t.Priority = ThreadPriority.Normal;

                    }

                    else

                    {

                        t.Priority = ThreadPriority.AboveNormal;//Give first tasks priority

                    }

                    t.Start();

                }

Start a Thread, name the thread (for logging/debugging) and away we go.   Regarding the thread priorities, this is an optional experiment.  The experimental idea is that a thread with dependencies be given a lower priority and those without dependencies be given a higher priority since other threads may be depending on them.

Command Dependencies

I didn’t immediately see a way to determine dependencies between units of work automatically so we must resort to hinting, and by hinting I mean “explicitly spelling it out”.   We can clearly see that we can’t unzip a file before its downloaded and we can’t begin processing a data text file before it’s unzipped.  We must, therefore, come up with a programming lexicon for

1.       Describing that C depends on B, which in turn depends on A

2.       Blocking the execution of C until the tree of C’s dependencies is complete.  As I write this, I realize I didn’t actually use a Tree structure per se in my solution, but that a Tree and a functional programming language may be a better way of restructuring the problem.  I’ll revisit this idea at the end of the article.

We start by adding some functionality to the base class.  We need to be able to know when a Command is complete, we need to know what other Commands any given Command might depend on, we need to block a command from executing even though we’ve already created and started it’s thread, and we need to signal the Command thread that the prerequisite are now complete.  My classes now look like this:

 

When building commands we “hint” as to what the dependencies are.  We then fire off a thread for each command and let the dependencies work out.  The base class Execute method looks like this:

        public virtual void Execute()

        {           

            WaitOnDependencies();           

        }

… and we follow the best practice of calling overridden methods first in our derived classes…

        public override void Execute()

        {

            base.Execute();

//do our real work here…

            Complete = true;

        }

The Complete property is very vanilla with one minor exception:

        public bool Complete

        {

            get

            {

                return _isComplete;

            }

            set

            {

                _isComplete = value;

                _resetEvent.Set();

            }

        }

And now we can see what the WaitOnDependencies() method does for us:

        protected virtual void WaitOnDependencies()

        {

            if (HasDependencies)

            {

                foreach (DataImportCommand dep in Dependencies)

                {

                    if (!dep.Complete)

                    {

                        ILog log = LogManager.GetLogger(GetType());

                        log.Warn("Waiting on dependency command " + dep.FriendlyName);

                        dep.ResetEvent.WaitOne();

                    }

                }

            }

        }

So, each command checks its list of dependencies before executing its own Command code. On a dual core machine we go from seeing 50% utilization of each core to 90% utilization of each core and a tremendous decrease in the amount of time needed for the entire import to run.  To revisit the Thread priority question above, we could potentially increase the priority of the current thread in this method once we know the dependencies are accomplished.

Also, note that Consolas is the best code font ever.

A Tree by any other name…

Perhaps a more elegant way of modeling the problem would be to describe our tasks as a Tree of dependent tasks.  At this point I will change the lexicon to say Prerequisite instead of Dependency.   The root node of the tree is the one task or Command we can run without any prerequisite, perhaps this is just Main().  Using the same working example, and looking at which commands are set as dependencies of which commands we could model our problem like so:

 

Or, more generally, like so:

 

 

The tree’s we are talking about now are obviously not Binary Trees.  Right now I have two cores on my desktop on and four on my server.   Pretty soon I’ll have four on my desktop and eight on my server, then perhaps 16 cores on my server after that.  In light of this consideration, what can we gain by structuring the problem as a Tree?

What we are currently doing is attempting to start each command even if it’s not really ready to run, and we in fact know at runtime what it would take for a DataImportCommand to be ready to run.  When we take the shotgun approach and throw them all out there as eligible Threads, we are wasting some resources with the ManualResetEvents and blocking/waiting for Prerequisites to complete.  Assuming the Task tree in the above diagram, we might create 16 threads and all but two of them will be blocking until the “level 2” tasks complete.  Using a recursive structure might be a cleaner way to envision this, which I will explore in a future article.

 

 

Sunday, January 27, 2008 10:36:23 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, January 11, 2008

I saw this over at Peter Foot's blog and the first thing I thought was "Maybe they are using Exception handling to control program flow?"; by this I mean just trying to use a Proxy without first checking to see if it's valid, and handling this situation in a try/catch block.  I have the utmost repect for the CF team, so maybe this is not what they're doing, or maybe they have a good reason for doing so. 

Regardless of what the CF team is doing, this re-opened a barely healed wound.  I recently inherited a codebase which I am modifying to help a friend.  This code is riddled with the age-old no no of "Using exception handling blocks to control program flow".  I think I first saw this best practice in Bjarne Stroustroup's "The C++ Programming Language" at least ten years ago.  The code has things like catching NullReferenceException rather than checking for null first, and catching ClassCastException rather than checking a column's DBNull status.  Logic that should be the "if" or "else" of a condition statement is then executed in the catch{} block. Not only is this ugly practice making the code hard to read, but considering the frequency of these conditions the code is being slowed down quite a bit while the exception is handled. 

Friday, January 11, 2008 11:59:02 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, November 01, 2007

There are various little gotchas writing software for Vista.  I've posted before about ridiculous things like logging not working.  You must use the Admin token to write to the Program Files directory so in some cases your program will silently fail and create no logs.  I've also been looking for a way to elevate a single action from .NET: an application that can run without elevation but has a button with the cute shield icon that invokes an action that requests elevation from the user.  At any rate, I just switched to Enterprise Library from log4net and had to get it to produce log files in a User location rather than \program files\myprogdir and the configuration (though the tools are nice) do not support this.  Luckily Enterprise Library 3.1 comes with the source so I dug around and found what to do.  To save you the trouble.

I'm using RollingFlatFileTraceListener.  This class only has one constructor:

public class UserScopeRollingFileListener : Microsoft.Practices.EnterpriseLibrary.Logging.TraceListeners.RollingFlatFileTraceListener
{
public UserScopeRollingFileListener(string fileName, string header, string footer, ILogFormatter formatter, int rollSizeKB, string timeStampPattern, RollFileExistsBehavior rollFileExistsBehavior, RollInterval rollInterval)
: base(GetUserScopedFilePath(fileName), header, footer, formatter, rollSizeKB, timeStampPattern, rollFileExistsBehavior, rollInterval)
{
}

protected static string GetUserScopedFilePath(string logFileName)
{
string path = logFileName;
if (Environment.OSVersion.Version.Major > 5)
{
string homeDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
path = System.IO.Path.Combine(homeDir, logFileName);
}

return path;
}
}

So, in the constructor call the GetUserScopedFilePath().  If the OS is Vista, it takes the log file name from the app.config file and maps it into My Documents.  It could just as easily be Local Application Data or something else.  The Logging configuration uses a "Data" class associated with each listener to build to the listener class.  This seems odd since this Data class explicitly invokes the constructor of the Listener even though the configuration requires the Type of the listener to be present in the app.config.


/// <summary>
/// Represents the configuration data for a <see cref="RollingFlatFileTraceListenerData"/>.
/// </summary>    
[Assembler(typeof(UserScopedRollingTraceListenerAssembler))]
public class UserScopedRollingTraceListenerData : Microsoft.Practices.EnterpriseLibrary.Logging.Configuration.RollingFlatFileTraceListenerData
{
public UserScopedRollingTraceListenerData()
{
}
}

/// <summary>
/// This type supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Represents the process to build a <see cref="RollingFlatFileTraceListener"/> described by a <see cref="RollingFlatFileTraceListenerData"/> configuration object.
/// </summary>
/// <remarks>This type is linked to the <see cref="RollingFlatFileTraceListenerData"/> type and it is used by the Custom Factory
/// to build the specific <see cref="TraceListener"/> object represented by the configuration object.
/// </remarks>
public class UserScopedRollingTraceListenerAssembler : RollingTraceListenerAssembler
{
public UserScopedRollingTraceListenerAssembler()
{
}

/// <summary>
/// This method supports the Enterprise Library infrastructure and is not intended to be used directly from your code.
/// Builds a <see cref="FlatFileTraceListener"/> based on an instance of <see cref="FlatFileTraceListenerData"/>.
/// </summary>
/// <seealso cref="TraceListenerCustomFactory"/>
/// <param name="context">The <see cref="IBuilderContext"/> that represents the current building process.</param>
/// <param name="objectConfiguration">The configuration object that describes the object to build. Must be an instance of <see cref="FlatFileTraceListenerData"/>.</param>
/// <param name="configurationSource">The source for configuration objects.</param>
/// <param name="reflectionCache">The cache to use retrieving reflection information.</param>
/// <returns>A fully initialized instance of <see cref="FlatFileTraceListener"/>.</returns>
public override TraceListener Assemble(IBuilderContext context, TraceListenerData objectConfiguration, IConfigurationSource configurationSource, ConfigurationReflectionCache reflectionCache)
{
UserScopedRollingTraceListenerData castObjectConfiguration
= (UserScopedRollingTraceListenerData)objectConfiguration;

ILogFormatter formatter = GetFormatter(context, castObjectConfiguration.Formatter, configurationSource, reflectionCache);

UserScopeRollingFileListener createdObject
= new UserScopeRollingFileListener(
castObjectConfiguration.FileName,
castObjectConfiguration.Header,
castObjectConfiguration.Footer,
formatter,
castObjectConfiguration.RollSizeKB,
castObjectConfiguration.TimeStampPattern,
castObjectConfiguration.RollFileExistsBehavior,
castObjectConfiguration.RollInterval
);

return createdObject;
}
}

Now, if you used the Enterprise Library configuration tool to create the RollingFlatFileListener configuration, you need to make two changes:

<listeners>

<add fileName="MyLogFileName.log" rollSizeKB="0" timeStampPattern="yyyy-MM-dd"

rollFileExistsBehavior="Overwrite" rollInterval="None" formatter="Text Formatter"

header="" footer=""

listenerDataType="MyNS.MyNS.UserScopedRollingTraceListenerData, MyAssembly.Name"

traceOutputOptions="None"

type="MyNS.MyNS.UserScopeRollingFileListener, MyAssembly.Name"

name="Rolling Flat File Trace Listener" />

</listeners>

One other thing I wanted to change about the logging, is that I like the log4net syntax for different log levels.  You would get an ILog implementation and call log.Debug(message) or log.Error(message) or log.Fatal(message).  With the joy of Extension Methods you can create your own on-the-fly facade with the compiler doing most of the work:

    public static class LogExtensions

    {

        static void Debug(this LogWriter l, string message)

        {

            LogEntry entry = new LogEntry();

            entry.Message = message;

            entry.Severity = System.Diagnostics.TraceEventType.Verbose;

            l.Write(entry);

        }

 

        static void Error(this LogWriter l, string message)

        {

            LogEntry entry = new LogEntry();

            entry.Message = message;

            entry.Severity = System.Diagnostics.TraceEventType.Error;

            l.Write(entry);

        }

    }

So extension methods now allow me to say Logger.Writer.Error("An error has occurred: value was null").  I am now happy with the Logging application block.

Thursday, November 01, 2007 8:36:15 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [3]  |  Trackback

I'm enjoying Enterprise Library right now, especially the unexciting yet very useful Logging and Caching application blocks.  In the past I have used things like log4net, but the configuration tool that comes with Enterprise Library 3.1 is enough reason to use EL by itself. 

Thursday, November 01, 2007 3:55:06 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, October 15, 2007

In previous articles I've shown how to host the Windows Forms designer outside of Visual Studio, which can be very useful in some sitations.  I had some down time before catching a plane (read: didn't want to start something bigger) so I started looking into the WPF designer.  The WPF designer, code-named "Cider", will not be hostable outside Visual Studio in the first release.  I will be providing feedback through the appropriate channels...

I'm going to go back and finish my ClickOnce thoughts next.

Monday, October 15, 2007 11:32:28 AM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 27, 2007

Regarding my last ClickOnce article, I have solved the initial code-theft issue I believe.  There is one more ClickOnce weakness I need to work around, and that is SSL.  If there is a problem with an SSL cert, ClickOnce is not smart enough to handle it.  System.Deployment.Application, I'm not done with you yet...

Thursday, September 27, 2007 12:06:34 PM (Central Standard Time, UTC-06:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Tuesday, September 25, 2007

ClickOnce is so close to greatness, as I’ve said before.  Yes, I know the “official word” is that this is not really meant for software ISVs deploying software to end users but it seems with a few extra things it could indeed be very good for this.  With some features in the Orcas Beta 2, I think ClickOnce is getting much closer to providing the plumbing I’ve been wanting in some cases and home rolling in others.  A new product I’m working on has some Architectural Desires.  I call them “desires” because we’ve been selling desktop applications without these architectural features for a while but I really want to meet some Service Level Requirements that will make my life easier, the customer’s life easier, and our support staff’s life easier.

Environment

·         I have an existing web system that users sign into.  Credentials are stored in an app-specific schema in a MySQL database.  Users of the current desktop application must be in this MySQL database and authenticate over web services.  Users of the new system increasingly do not need access to the web based system.  Putting their credentials in MySQL is polluting this system.

·         We have an OpenLDAP server we are slowing moving credential stores to.

·         We have a Windows2003 server that’s not doing much right now

·         We have a client application that ships with specialized hardware and an install disk.

·         Upgrades go out to customers via installing a new MSI

Requirements/Desires

1.       My software requires some specialized hardware.  I’d like to ship this without install disks.

2.       I’d like the desktop application to be able to have the Role information and authenticate against our existing credential stores.  I don’t want users to be able to run this within a very short time period if we turn them off.

3.       I’d like to stop polluting the existing web system credential store with users that should not ever be able to log into this system, however SOME users of the web based system will also need to be able to authenticate using the client application.

4.       I’d like to be able to keep random people from stealing software.

5.       I’d like to be able to keep random people from installing my software.

 

Solution in Code and UML

Let’s take the big red pill and see where it leads us.

ClickOnce - Part 1

I start with .NET 3.5 Beta 2, VS 2008 Beta 2, and my current environment.  Setting up ClickOnce deployment is easy enough, I set the application to check for updates before it runs, and verify that this works.  Oddly enough with Beta 2, 100% of my testers who have tried to click “Install” rather than installing .NET 3.5 and choosing “launch” have had the install .exe lock up.  Hopefully this gets fixed.

Client Application Services – Server Side

There is a wonderful bit of plumbing available now Called Client Application Services.  In order to use this you need an ASP.Net web site.  You need to add a reference to System.Web.Extensions, and configure your web.config such that the Role and Membership services are enabled.  With .NET 3.5 this is done like so:

      <system.web.extensions>

            <scripting>

                  <webServices>

                        <authenticationService enabled="true" requireSSL="false"/>                   

                        <roleService enabled="true"/>

Now, the Role and Membership providers I have configured are my LDAP based home rolled code.  Discussing these is outside the scope of this article; suffice to say they are straight up Provider implementations.  I will need to set up my Forms authentication a certain way to meet my single sign on goals:

            <authentication mode="Forms">

                  <forms domain=".office.carspot"

                           enableCrossAppRedirects="true"

                           cookieless="UseCookies"

                           slidingExpiration="false"

                           defaultUrl="Cookies.aspx"

                           path="/"

                           protection="Encryption"

                           timeout="1440"

                           name="FooBar"/>

            </authentication>

For testing I am allowing the clients to sign on once for a day.  The domain attribute is important, as the cookie created by my web site will now be passed to anysite.office.carspot.