2008-10-08

ECO, Winforms, ASP.NET, and WCF

The technologies I used in an app I wrote for friends recently. The app manages properties at different locations, bookings, and tariffs. In addition to this the application (which uses SQLite) connects to their website using WCF and updates their database so that people can check prices and availability.

I need to get them using it now so that there is data available by the time I put up their website.

Implementing complex unit testing with IoC

I have a method that looks something like this

public void DoSomething(SomeClass someInstance, User user)
{
  var persistence = someInstance.AsIObject.GetEcoService<IPersistenceService>();
  persistence.Unload(someInstance.AsIObject());
  
  if (someInstance.CurrentUser != null)
    throw new ..........;
  someInstance.CurrentUser = user;

  persistence.UpdateDatabase(someInstance);
}


This unloads the local cache before ensuring someInstance.CurrentUser == null, it then sets someInstance.CurrentUser and updates the DB. The unit test I wanted would check what happens when two users try to perform this at the same time. What I wanted was

User A: Unload
User B: Unload
User A: Check == null, it is
User B: Check == null, it is
User A: Change + update DB
User B: Change + update DB + experience a lock exception

What I didn't want was

User A: Unload
User B: Unload
User A: Check == null, it is
User A: Change + update DB
User B: Check == null, it isn't

To achieve two things running at once I need to either

A: Execute a line of code at a time for each user within the unit test instead of executing the method.
B: Execute the same method from two different threads.

Option A is easy to follow but is rubbish because it involves copying the method source out into the test method, no thanks! Option B is good but harder because I need to ensure that the two threads execute the lines of code in sync. What I really could do with is sync code inside the method, but there is no way I want to add additional sync logic because it is only needed for testing! However, there is already an opportunity to inject some code into the method; take a look here

  var persistence = someInstance.AsIObject.GetEcoService<IPersistenceService>();
  ...
  persistence.UpdateDatabase(someInstance);


Because we are using Inversion of Control it means that the method will call UpdateDatabase() on the reference we pass rather than a hard-coded reference. This means that we could quite easily replace the IPersistenceService with our own implementor and intercept the call to UpdateDatabase.

  public class PersistenceServiceWithEvents : IPersistenceService
  {
    //An event to call back
    public event EventHandler BeforeUpdateDatabase;

    //A reference to the original persistence service
    private readonly IPersistenceService PersistenceService;

    //Constructor
    public PersistenceServiceWithEvents(IEcoServiceProvider serviceProvider)
    {
      PersistenceService =
        serviceProvider.GetEcoService<IPersistenceService>();
    }

    //Interface implementation
    public void UpdateDatabase(IObjectProvider obj)
    {
      EventHandler handler = BeforeUpdateDatabase;
      if (handler != null)
        handler(this, EventArgs.Empty);
      
    }

    //Other methods omitted
  }


Now I have the opportunity to call back some code just before the real UpdateDatabase is executed, which gives me the chance to insert some thread sync' code:

  [TestMethod]
  public void HandlesConcurrency()
  {
    //Create a shared object to work with
    var ecoSpace = TestHelper.EcoSpace.Create();
    var someInstance = new SomeClass(ecoSpace);
    ecoSpace.UpdateDatabase();
    //Get it's external ID
    string someInstanceID = ecoSpace.ExternalIds.IdForObject(someInstance);

    //Create a thread sync object which both threads will wait for before
    //passing on their UpdateDatabase call to the original persistence servce
    var startUpdateDB = new ManualResetEvent(false);

    //Create a thread sync object which tells the test when this thread has called
    //PersistenceService.UpdateDatabase
    var user1ReadyToUpdateDB = new AutoResetEvent(false);

    bool user1Conflict = false;
    var user1ThreadStart = new ThreadStart(
        delegate()
        {
          HandlesConcurrency_UserEmulation(
            ecoSpace.PersistenceMapper,
            someInstanceID,
            user1ReadyToUpdateDB,
            startUpdateDB,
            out user1Conflict);
        }
      );


    //Create a thread sync object which tells the test when this thread has called
    //PersistenceService.UpdateDatabase
    var user2ReadyToUpdateDB = new AutoResetEvent(false);

    bool user2Conflict = false;
    var user2StartUpdateDB = new AutoResetEvent(false);
    var user2ThreadStart = new ThreadStart(
        delegate()
        {
          HandlesConcurrency_UserEmulation(
            ecoSpace.PersistenceMapper,
            someInstanceID,
            user2ReadyToUpdateDB,
            startUpdateDB,
            out user2Conflict);
        }
      );

    //Create and start both threads
    var user1Thread = new Thread(user1ThreadStart);
    var user2Thread = new Thread(user2ThreadStart);
    user1Thread.Start();
    user2Thread.Start();

    //Wait until they have both signalled that the call to UpdateDatabase has been reached
    user1ReadyToUpdateDB.WaitOne();
    user2ReadyToUpdateDB.WaitOne();

    //Both threads have now executed DoSomething() as far as the call to
    //persistenceService.UpdateDatabase and are waiting for me to tell them
    //to continue.
    startUpdateDB.Set();

    //Both threads will now wake up and call the original PersistenceService.UpdateDatabase.
    //Wait for both threads to finish so that the test does not end prematurely.
    user1Thread.Join();
    user2Thread.Join();

    //Check at least one experienced a conflict
    int lockCount = 0;
    if (user1Conflict)
      lockCount++;
    if (user2Conflict)
      lockCount++;
    Assert.AreEqual(1, lockCount, "One should experience a lock conflict");
  }

  private void HandlesConcurrency_UserActionEmulation(
    PersistenceMapper persistenceMapper,
    string someInstanceID,
    AutoResetEvent readyToUpdateDB,
    WaitHandle startUpdateDB,
    out bool lockConflict)
  {
    //SETUP

    //Create secondary ecospaces with the same persistence mapper as the
    //original. This is because my test EcoSpace uses a memory persistence mapper
    var ecoSpace = TestHelper.EcoSpace.CreateWithSharedMapper(persistenceMapper);

    //Create the persistence service with the BeforeUpdateDatabase event
    var callbackPersistenceService = new TestHelper.PersistenceServiceWithEvents(ecoSpace);
    //Register it
    ecoSpace.RegisterEcoService<IPersistenceService>(callbackPersistenceService);

    //Ensure update happens in sync, this occurs when we try to lock the object
    callbackPersistenceService.BeforeDatabaseUpdate += (sender, args) =>
      {
        //Notify we are ready to update
        readyToUpdateDB.Set();
        //Now wait to be told to complete the update
        startUpdateDB.WaitOne();
      };

    //ACT

    //Now test our code
    var someServiceToTest = new SomeService(ecoSpace);
    var someInstance = ecoSpace.ExternalIds.ObjectForId(someInstanceID).GetValue<SomeClass>();
    try
    {
      lockConflict = false;
      someServiceToTest.DoSomething(someInstance, new User(ecoSpace));
    }
    catch (OptimisticLockException)
    {
      lockConflict = true;
    }
  }


So there you have it. An example of how Inversion of Control and the Service Provider pattern can enable you to redirect calls in parts of your code to enable complex testing scenarios without having to change your implementation!

2008-09-30

Unit testing security

Following on from my previous post about using(Tricks) here is an example which makes writing test cases easier rather than just for making your code nicely formatted. Take a look at the following test which ensures Article.Publish sets the PublishedDate correctly:

[TestMethod]
public void PublishedDateIsSet()
{
  //Create the EcoSpace, set its PMapper to a memory mapper
  var ecoSpace = TestHelper.EcoSpace.Create();

  //Creat an article
  var article = new Article(ecoSpace);

  //Create our Rhino Mocks repository
  var mocks = new MockRepository();

  //Mock the date/time to give us a predictable value
  var mockDateTimeService = mocks.StrictMock<IDateTimeService>();
  ecoSpace.RegisterEcoService(typeof(IDateTimeService), mockDateTimeService);

  //Get a date/time to return from the mock DateTimeService
  var now = DateTime.Now;
  using (mocks.Record())
  {
    //When asked, return the value we recorded earlier
    Expect.Call(mockDateTimeService.Now).Return(now);
  }

  //Check mockDateTimeService.Now is called from Article.Publish
  using (mocks.Playback())
  {
    article.Publish();
  }

  //Check the date/time from IDateTimeService is stored in PublishedDate
  Assert.AreEqual(now, article.PublishedDate);
}


The method it is testing

public void Publish()
{
  IEcoServiceProvider serviceProvider = AsIObject().ServiceProvider;
  var dateTimeService = serviceProvider.GetEcoService<IDateTimeService>();
  PublishedDate = dateTimeService.Now;
}


Now at some point in the future you decide to enforce some security within your business objects. You decide that only certain people can publish your article, such as the author or an administrator. This will now break every test you have which assumes article.Publish will just work.


public void Publish()
{
  IEcoServiceProvider serviceProvider = AsIObject().ServiceProvider;

  var currentUserService = serviceProvider.GetEcoService<ICurrentUserService>();
  var currentUser = currentUserService.CurrentUser;
  if (currentUser != this.Author && !currentUser.HasRole<SystemAdministratorRole>())
    throw new SecurityException("Cannot publish this article");

  var dateTimeService = serviceProvider.GetEcoService<IDateTimeService>();
  PublishedDate = dateTimeService.Now;
}


This would dramatically complicated any test which relied on having a published article. Each time you would additionally have to:
01: Create a user.
02: Mock ICurrentUserService to return that user.
03: Ensure the article.Author is set to that user, or the user owns a SystemAdministratorRole.

If you have 20 tests requiring a published article this is going to cause you a lot of work! The first mistake here is that the article is testing for permissions; permission granting should be a service. I would separate the service out like so...

public interface IPermissionService
{
  bool MayPublishArticle(Article article);
}


Your EcoSpace would have a class implementing this interface and return the appropriate result, the EcoSpace would register this default service.

public class PermissionService : IPermissionService
{
  IEcoServiceProvider ServiceProvider;
  
  public PermissionService(IEcoServiceProvider serviceProvider)
  {
    ServiceProvider = serviceProvider;
  }

  public bool MayPublishArticle(Article article)
  {
    var currentUserService = serviceProvider.GetEcoService<ICurrentUserService>();
    var currentUser = currentUserService.CurrentUser;
    return currentUser == article.Author
      || currentUser.HasRole<SystemAdministratorRole>());
  }
}


In the EcoSpace:
public override bool Active
{
  get { return base.Active; }
  set
  {
    if (value && !Active)
      RegisterDefaultServices();
    base.Active = value;
  }
}

private void RegisterDefaultServices()
{
  RegisterEcoService(typeof(IPermissionService), new PermissionService(this));
  RegisterEcoService(typeof(ICurrentUserService), new CurrentUserService());
  RegisterEcoService(typeof(IDateTimeService), new DateTimeService());
}


Now Article.Publish looks like this

public void Publish()
{
  IEcoServiceProvider serviceProvider = AsIObject().ServiceProvider;
  var permissionService = serviceProvider.GetEcoService<IPermissionService>();

  if (!permissionService.MayPublishArticle(this))
    throw new SecurityException("Cannot publish this article");

  var dateTimeService = serviceProvider.GetEcoService<IDateTimeService>();
  PublishedDate = dateTimeService.Now;
}


But how does this help? The first advtange is that we have separated the PermissionService so that we can test it in isolation, but we would still need to mock the IPermissionService wouldn't we? Yes we would! But how does this look?

using (TestHelper.Permissions.PermitAll(ecoSpace))
{
  article.Publish();
}


Much more simple eh? To achieve this I have a static class named Permissions in my test project

public static class Permissions
{
  private class TestPermissionService : IPermissionService
  {
    (simple code omitted)
    Accept a boolean in the constructor, and return
    it for every method call.
  }

  public static IDisposable Allow(MyEcoSpaceType ecoSpace)
  {
    var originalService = ecoSpace.GetEcoService<IPermissionService>();
    var newService = new TestPermissionService(true);
    ecoSpace.RegisterEcoService(typeof(IPermissionService), newService);
    return DisposableAction(
      () => ecoSpace.RegisterEcoService(typeof(IPermissionService), originalService)
    );
  }
}


All this does is to record the current IPermissionService, register a new one which always returns True/False (depending on what we pass to its constructor), and then return an instance of DisposableAction. To this instance we pass an Action which re-registers the original service. The action is called when IDisposable.Dispose is called:

public class DisposableAction : IDisposable
{
  Action Action;
  public DisposableAction(Action action)
  {
    Action = action
  }

  void IDisposable.Dispose()
  {
    Action();
  }
}



So the following line

using (TestHelper.Permissions.PermitAll(ecoSpace))
{
  article.Publish();
}


will
01: Record the original IPermissionService.
02: Register a new one which always returns True.
03: Execute the code within the Using { } block.
04: IDisposable.Dispose will be called on my DisposableAction.
05: The previous service will be restored.

Single instance application - revisited

Not so long ago I posted a solution to having a single-instance application. Rather than just preventing secondary instances from running the requirement was to have the 2nd instance pass its runtime parameters onto the 1st instance so that it can process them. My solution used remoting on the local machine. This appeared to work very well until recently when I needed an OpenFileDialog. Attempting to show the dialog resulted in an error about COM thread apartments. So, it wasn't THE solution.

After a bit of research I decided to use named pipes instead. This meant I had to upgrade my app from .NET 2 to 3.5, but I think it is worth it. To implement the feature in an app you need to do 2 things. First you need to realize the interface ISingleInstanceApplicationMainForm on your app's main form in order to accept command line arguments from any subsequently started instances. Next you need to change your Program.Main method like so:

[STAThread]
static void Main(string[] args)
{
  Application.EnableVisualStyles();
  Application.SetCompatibleTextRenderingDefault(false);
  new SingleInstanceApplication<MainForm>("CompanyName.ApplicationName", args);
}



The source code for SingeInstanceApplication is an adaptation of some code I read here; and here it is:


public interface ISingleInstanceApplicationMainForm
{
  void AcceptCommandLineArguments(string[] args);
}

public class SingleInstanceApplication<TForm> : IDisposable
  where TForm : ISingleInstanceApplicationMainForm
{
  Mutex Mutex;
  bool IsFirstInstance;
  string ApplicationUniqueID;
  protected TForm MainForm { get; private set; }

  public SingleInstanceApplication(string applicationUniqueID, string[] args)
  {
    ApplicationUniqueID = applicationUniqueID;
    Mutex = new Mutex(true, ApplicationUniqueID, out IsFirstInstance);
    if (IsFirstInstance)
    {
      MainForm = (TForm)Activator.CreateInstance(typeof(TForm));
      (MainForm as ISingleInstanceApplicationMainForm).AcceptCommandLineArguments(args);
      ThreadPool.QueueUserWorkItem(new WaitCallback(ListenForArguments));
      Application.Run((Form)(object)MainForm);
    }
    else
      PassArgumentsToFirstInstance(args);
  }

  private void ListenForArguments(Object state)
  {
    try
    {
      using (var server = new NamedPipeServerStream(ApplicationUniqueID))
      {
        using (var reader = new StreamReader(server))
        {
          server.WaitForConnection();

          string[] args = reader.ReadLine().Split(new char[] {'\t'}, StringSplitOptions.RemoveEmptyEntries);
          ThreadPool.QueueUserWorkItem(new WaitCallback(ReceiveArgumentsFromNewInstance), args);
        }//using reader
      }//using server
    }
    catch (IOException) { }
    finally
    {
      ListenForArguments(null);
    }
  }

  private void ReceiveArgumentsFromNewInstance(Object state)
  {
    string[] args = (string[])state;
    (MainForm as Form).Invoke(
      new ThreadStart(
        delegate()
        {
          MainForm.AcceptCommandLineArguments(args);
        }
        )
      );
  }

  private void PassArgumentsToFirstInstance(string[] args)
  {
    var builder = new StringBuilder();
    foreach (var arg in args)
      builder.AppendFormat("{0}\t", arg);

    try
    {
      using (var client = new NamedPipeClientStream(ApplicationUniqueID.ToString()))
      {
        using (var writer = new StreamWriter(client))
        {
          client.Connect(500); // 0.5 seconds timeout
          writer.WriteLine(builder.ToString());
        }//using writer
      }//using client
    }
    catch (TimeoutException) { }
    catch (IOException) { }
  }




  void IDisposable.Dispose()
  {
    if (IsFirstInstance && Mutex != null)
      Mutex.ReleaseMutex();
  }

}

2008-09-24

using(TricksToFormatYourCodeNicely)

I've been writing a data importer which takes a specific data input format and outputs XML, this XML is then imported within my application. What annoyed me was the way in which the source code was formatted....


writer.WriteStartElement("data");
writer.WriteAttributeString("1", "1");
writer.WriteAttributeString("2", "2");
writer.WriteAttributeString("3", "3");

writer.WriteStartElement("systemData");
writer.WriteAttributeString("a", "a");
writer.WriteAttributeString("b", "b");
writer.WriteEndElement();//systemData

writer.WriteEndElement();//data


It just didn't look nice. I thought about splitting it into separate methods, but most of the time this would have been overkill as the methods would have been very short. Instead I wrote an extension method on XmlWriter:


public static class XmlWriterHelper
{
  public static IDisposable StartElement(this XmlWriter writer, string elementName)
  {
    return new DisposableElementWriter(writer, elementName);
  }

  private class DisposableElementWriter : IDisposable
  {
    private XmlWriter Writer;

    public DisposableElementWriter(XmlWriter writer, string elementName)
    {
      Writer = writer;
      Writer.WriteStartElement(elementName);
    }

    public void Dispose()
    {
      Writer.WriteEndElement();
    }
  }
}



Now I can write code like this instead:

using (writer.StartElement("data"))
{
  writer.WriteAttributeString("1", "1");
  writer.WriteAttributeString("2", "2");
  writer.WriteAttributeString("3", "3");
  using (writer.StartElement("systemData"))
  {
    writer.WriteAttributeString("a", "a");
    writer.WriteAttributeString("b", "b");
  }//systemData
}//data



Less code AND easier to read. What a bonus!

2008-09-17

Parameterised queries in ECO

Whenever I generate OCL queries in code I find myself having to escape user input in order to avoid making the query invalid, or allowing malicious input.

I've decided instead to use the ECO equivalent of parameterised queries (variables in ECO) and here is the result.

public static string CreateParameterisedQuery(
  this IEcoServiceProvider serviceProvider,
  string query,
  out IModifiableVariableList vars,
  params object[] args)
{
  vars = serviceProvider.GetEcoService<IVariableFactoryService>().CreateVariableList();
  for (int varIndex = 0; varIndex < args.Length; varIndex++)
  {
    string variableName = "autoVar_" + varIndex.ToString();
    query = query.Replace("{" + varIndex.ToString() + "}", variableName);
    vars.AddConstant(variableName, args[varIndex]);
  }
  return query;
}



To use this code you would do something like this

//1: Create the OCL with string.format style parameters
string query = "Person.allInstances" +
  "->select(name.sqlLikeCaseInsensitive({0}))" +
  "->select(gender = {1}";

//2: Parse the query and build the variable list
IModifyableVariableList vars;
query = self.AsIObject().ServiceProvider.CreateParameterisedQuery(query,
  out vars,
  "Peter Morris",
  Gender.Male);


Now you can use IOclPsService or IOclService to execute the new query passing the variables.

2008-09-08

User authentication in SilverLight

I wanted to know how to authenticate users in a SilverLight app using their Windows login info.

01: Set the authentication mode to Windows and <deny users="?"/> in <system.web> within web.config
02: Move the silverlight control to Default.aspx and set that as your start page
03: Add the following Page_Load code

  protected void Page_Load(object sender, EventArgs e)
{
IPrincipal p = HttpContext.Current.User;
if (p == null)
throw new SecurityException("No current user");
if (!(p is WindowsPrincipal))
throw new SecurityException("Not a windows user");
if (!p.Identity.IsAuthenticated)
throw new SecurityException("Not authenticated");
Xaml1.InitParameters =
string.Format("user={0},session={1}", p.Identity.Name, Session.SessionID);
}


04: In app.xaml.cs you can now read the InitParameters using e.InitParameters in the Application_Startup method.