2008-02-07

Your bug is my bug

I recently released an update to some software and a bug slipped through the net. It introduced some odd behaviour with a control named SmartGrid. After some testing I was able to determine that it wasn't my fault and that I could reproduce a bug in SmartGrid. I hate bugs in other people's source code, I can't fix it, I am at their complete mercy.

Thankfully the Resco support was amazing! I posted on their forums and immediately someone sent me instructions on where to send my project. The next morning I was disappointed to see an email saying that the project worked fine. I posted again and almost immediately someone had offered to chat on skype.

We did that for a while, both confused by the problem. We then went on to use Remote Assistance so that he could observe my bug which he wasn't experiencing.

In the end the problem was very confusing. I had Version A of the DLL in which the error occurred. I upgraded to the latest version (B) and it still occurred. The guy at Resco sent me a DLL with debug strings being sent to the IDE (C.DEBUG) and everything worked. I reverted to Version B and now it worked whereas before it didn't. Don't you just hate phantom bugs that "fix" themselves?

In the end the Resco guy sent me a full build of the very latest code base (Version C) and all seems fine.

Both of us were at a complete loss, but thanks to their excellent support the problem with my application was kept to as short a time as possible!

2008-02-05

Converting a recurring decimal to a fraction

For a couple of hours a week I am doing a beginner's level maths course. The topic today was converting recurring decimals into fractions. For example (the [] are the repeating digits


0.[6]

 1x = 0.[6]
10x = 6.[6]

9x = 10x - 1x
9x = 6.[6] - 0.[6] = 6


Therefore the answer is 6/9, or 2/3

When it got to numbers like 0.12[34] (ie 0.12343434343434.....) the lesson was really complicated, but I came up with a more simple approach, so here it is if ever you need it.

My first observation was that we need a large number and a small number. So let's start with the 10x we used above


 1x = 0.12[34]
10x = 1.2[34]


therefore 9x = 10x - 1x which is


 1.2[34]
-0.12[34]


This is going to give us 1.1(something)

My second observation is that fractions cannot have decimal values in them. In order to get rid of the fraction we need the big number to have the exact same fraction as the small number. e.g.


 B.[34]
-S.[34]
=X.[00]


So our small number needs to end with [34]. Given the number 0.12[34] how many places do we need to shift the decimal to the right? The answer is 2, so we need the number 1 and two zeros, which is 100

Small number = 100x

To do a subtraction and get a positive number our big number needs to be bigger than 100x


  1x = 0.12[34]
100x = 12.[34]


How many digits are recurring? The answer is 2. This means that the larger factor has two more zeros than the lower factor in order to ensure both numbers end with [34].


    1x = 0.12[34]
  100x = 12.[34]
10000x = 1234.[34]

1234.[34]
- 12.[34]
=========
1222.[00]


Now we have a whole number!

1222 / (10,000 - 100) is 1222/9900


So the quick way of doing it is this


x = 0.12[34]
    0.AA[BB]


Small = x * 10 to the power of the number of non recursive decimal digits [A]
Big = x * 10 to the power of the tge total number of decimal digits [B]

Small = x * 102
Big = x * 104

Big - small = 1222
Big factor (10000) - small factor (100) = 9900

Therefore the answer is 1222/9900


Or like this


1x = 0.12[34]

How many non recurring digits? Two, so our small factor is a 1 with 2 zeros = 100
How many recurring digits? Two, so our large factor has 2 more zeros than the small one = 1 00 00 = 10,000

MaxLength

Implementing HTML maxlength was a bit of a pain. Not to write the helpers though, that was easy....

$EcoModelHelper.AttributeLength($Product, "ID")


But when it came to specifying that in the <input> it was too much work! This is how it is done statically...

$FormHelper.TextFieldValue("Product.ID", $Product.ID, "%{maxlength='32'}")


Now I had to replace the static 32 with the EcoModelHelper code.

#set ($ProductIDLength = $EcoModelHelper.AttributeLength($Product, "ID"))
$FormHelper.TextFieldValue("Product.ID", $Product.ID, "%{maxlength='$ProductIDLength'}")


This was starting to look like too much typing!

So instead I have decided to add new methods to the EcoFormHelper. Here is the first:

$EcoFormHelper.ObjectTextField("Product.ID", $Product, "ID")


This will output something like this

<input type="text" id="Product_ID" name="Product.ID" value="AlterEgo" maxlength="32" />

It just uses the normal MonoRail $FormHelper.TextFieldValue helper but passes it the current value of the object and the maximum length as defined in the model

More work up front, less in the long run :-)

EcoRail validation

Here is yesterday's update.

I wanted a way to validate the user input. Seeing as there are constraints in the model to me this was the obvious approach to take. The HTML in my main layout (MasterPage) was changed like so

<body>
  #if ($Errors && $Errors.Count > 0)
    <ul class="errors">
      #foreach ($currentError in $Errors)
        <li>$currentError</li>
      #end
    </ul>
  #end

  $childContent

</body>


This outputs all errors passed in PropertyBag["Errors"] or in my case I used Flash["Errors"].


To validate my product input I changed my controller like so:

[AllowEcoSpaceDeactivateDirty(true)]
public void Modify([EcoDataBind("Product", Allow = "ID,Name", NoObjectIdAction = ObjectIdAction.CreateNewInstance)]Product product)
{
  PropertyBag["Product"] = product;
  IList<string> errors = GetErrorsForAllDirtyObjects();
  if (errors.Count > 0)
    Flash["Errors"] = errors;
  else
  {
    EcoSpace.UpdateDatabase();
    RedirectToAction("List");
  }
}


GetErrorsForAllDirtyObjects uses the DefaultEcoSpaceType to find the EcoSpace instance and then checks all constraints of all dirty objects in order to return a list of strings. Available validation routines are


protected IList<string> GetErrorsForObject(IObjectProvider instance)

Gets error messages for broken constraints on a single object


protected IList<string> GetErrorsForAllDirtyObjects(Type ecoSpaceType)

Gets the EcoSpace instance of the type specified and then returns errors messages for broken constraints on all modified objects


protected IList<string> GetErrorsForAllDirtyObjects()

Calls GetErrorsForAllDirtyObjects(Type ecoSpaceType) using the DefaultEcoSpaceType specified



Now I have to take into account that not everyone wants to have their error messages returned from OCL constraints defined in the model. To cater for this my validation routines do not directly read the model, instead they use a virtual property

private IConstraintProvider m_ConstraintProvider;
protected virtual IConstraintProvider ConstraintProvider
{
  get
  {
    if (m_ConstraintProvider == null)
      m_ConstraintProvider = new ModeledConstraintProvider();
    return m_ConstraintProvider;
  }
}


The default implementation returns an instance of ModeledConstraintProvider which is a class in the DroopyEyes.Eco.Extensions project, but you can now override this property on your controller and return any implementation you like.

So now I have OCL validation from the model. Next I think I will add an EcoModelHelper so that you can obtain information from the model, to start with I think all I will implement is something like the following

$EcoModelHelper.Length("Person", "FirstName")

2008-02-03

Changing the URL structure

I wanted the following URL structure in my website

www.mysite.com/product/myproductname/whatsnew

but the default url mapping in MonoRail would translate this as

www.mysite.com/[controller]/[action]/[id]

So it would expect to find this

public class ProductController
{
  public void MyProductName(string id)
  {
  }
}

whereas what I actually want is

public class ProductController
{
  public void WhatsNew(string productName)
  {
  }
}



  1. Open Web.Config

  2. Locate the monorail node

  3. Locate the routing child node

  4. Now add a new <rule> to the top of the list:


<rule>
<pattern>/(product)/(\w+)/(\w+)</pattern>
<replace><![CDATA[ /product/$3.rails?productName=$2]]></replace>
</rule>


As this is at the top of the list it will have the highest priority. If the URL matches /product it will remap the url

From:
www.mysite.com/product/myproductname/whatsnew

To:
www.mysite.com/product/whatsnew.rails?productname=MyProductName


without the user ever seeing it :-)

2008-02-02

ECO docs progress

I'm currently in the process of migrating the QuickStart series from BDS over to VS and recreating the accompanying source code.

There's quite a lot of information in those articles, I hadn't realised how much I had written! Well, the transcription is going quite well. So far I have made it as far as article number 5. This one is going a bit slower because it is also a translation from VCL .NET to WinForms.

2008-02-01

Inversion of control

As you may already know I am writing a website. I've chosen to use MonoRail for the web part and ECO for the persistence. Today has been great fun! I have modified the Castle.MonoRail.EcoSupport library with the following enhancements.

  1. You can now specify a [DefaultEcoSpaceType(typeof(MyEcoSpace))] on either the class or method.
  2. On the EcoDataBind reflection attribute you can now specify as little as [EcoDataBind("Product")] on your method parameter, this will use the specified DefaultEcoSpaceType specified, or throw an exception if no default was specified.
This lets me write code like this
[AllowEcoSpaceDeactivateDirty(true)]
[UseEcoSpacePool(false)]
[UseEcoSpaceSession(EcoSpaceStrategyHandler.SessionStateMode.Never)]
public class ProductAdminController : BaseController
{
  public void Create()
  {
    PropertyBag["Product"] = new Product(GetEcoSpace<MyWebSiteEcoSpace>());
    RenderView("Modify");
  }
}
I can now easily create actions Create/Modify/Edit which all render the same view "Modify.vm". The method signatures for Edit and Modify are as follows
public void Modify(string id)
public void Modify([EcoDataBind("Product", Allow="Name", NoObjectIdAction=ObjectIdAction.CreateNewInstance)]Product product)
The EcoDataBind attribute additionally says that only "Name" should be applied to the object, this is to stop people from posting custom requests with Product.IsActive set to "false" for example, so everything except Name will be ignored. It also states that if there is no Product.ExternalId in the form (there wont be for new objects) then a new Product instance should be created.

But now the fun part. Instead of writing code like this to get a product by its name
IEnumerable<Product> products =
GetDefaultEcoSpace().Ocl.Evaluate("Product.allInstances->orderBy(name)").GetAsIList<Product>();
PropertyBag["Products"] = products;
Maybe it would be better to have a data-access-layer so that I don't have to hard-code that OCL whenever I want a list of products? Sounds good....
public interface IProductProvider
{
  IEnumerable<Product> GetAll();
  Product GetSingleByName(string name);
  IEcoServiceProvider ServiceProvider { get; set; }
}
Now the code is written as follows
IProductProvider productProvider = new MyImplementationProductProvider();
productProvider.ServiceProvider = GetDefaultEcoSpace();
PropertyBag["Product"] = productProvider.GetSingleByName(id);
Okay, so now I have a generic way of getting a list of products ordered by name and a single product by its name. What next? Well seeing as I am writing "proper" code these days I thought I'd add some unit testing in there. After having Shamresh from Inspiration Matters talk so enthusiastically about Inversion of Control with me on Skype over the last month or so I thought I'd take a look at that.

Here's how it works. First I put some XML into my web.config
<component id="IProductProvider" 
  service="MyWebsite.Services.IProductProvider, MyWebsite"
  type="MyWebsite.Services.Implementation.ProductProvider, MyWebSite"/>


What this does is to register a type for a service. It says that the class ProductProvider should be used whenever I ask for IProductProvider. Here is how my method implementation changes...
public void Create()
{
  PropertyBag["Product"] = new Product(GetEcoSpace<MyWebSiteEcospace>());
  RenderView("Modify");
}

public void List()
{
  IProductProvider productProvider = WindsorContainer.Resolve<IProductProvider>();
  productProvider.ServiceProvider = GetDefaultEcoSpace();
  PropertyBag["Products"] = productProvider.GetAll();
}

public void Modify(string id)
{
  IProductProvider productProvider = WindsorContainer.Resolve<IProductProvider>();
  productProvider.ServiceProvider = GetDefaultEcoSpace();
  PropertyBag["Product"] = productProvider.GetSingleByName(id);
}

public void Modify([EcoDataBind("Product", Allow="Name", NoObjectIdAction=ObjectIdAction.CreateNewInstance)]Product product)
{
  GetEcoSpace().UpdateDatabase();
  RedirectToAction("List");
}
As you can see I now use WindsorContainer (from www.castleproject.org) to retrieve my IProductProvider instead of creating it directly. You might be wondering what the point of doing that is? The point is that later when it comes to running my unit tests I can configure the WindsorContainer to create a different class to supply IProductProvider. This means that I can have a class specific to my test that returns 3 products that I create on the spot with specific names, then I can inspect the output of the view and check that they are all being rendered.

This is just one example. The main idea is that my unit tests can control what data the controller actions are given so that I can ensure a known data state during the tests instead of having to rely on having certain objects in my database.

It's been good fun, I hope I see some more places I can implement IoC during the development of this website.