Posts

Showing posts with the label ECO

Domain driven design, Test driven design

I was just reading through the VBUG events list when I came across an event entitled "Domain driven design approach, using unit testing". "Sounds interesting!" I thought to myself, I hope I can make it! As I started to read it I thought it looked familiar. At that point I realised it was me doing the talk! So hopefully I will be able to make it :-) The posting is here . If you come along make sure you say "Hello".

Accommodation manager - runtime error

I've just spotted something I omitted before zipping up my AccommodationManager app and making it available. When you run the app in Release mode you will experience SQL errors. These errors are intermittent, and a query that worked only seconds ago might not always work. The reason for this is that ECO executes all queries within a transaction; SQLite creates a journal file for every transaction and then deletes it when done; and my anti-virus decides it wants to take a look at this new journal file to see what's inside it; resulting in SQLite not being able to open its own journal file exclusively. This was something I noticed a while ago in another ECO+SQLite app of mine and the guy who writes the library spent a couple of hours with me on MSN trying to work out what the problem was (he had a fix to me by the next morning!). Anyway, I have updated the project so that the connection string tells SQLite not to delete the journal file when it has finished with it, as a conse...

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 .

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 thi...

More leak fixes

I have changed the DirtyObjectCatcher so that it initially only hooks Form.Disposed - Automatically disposes the DirtyObjectCatcher Form.Closed - Unhooks all additional form events (below) Form.Shown - To hook additional form events (below) ==Additional form events== Form.Activated Form.MdiParent.Activated Form.MdiChildActivate The additional events are to ensure that the DirtyObjectCatcher's undo block is moved to the top. The reason that these events are now unhooked is so that there is no strong event references from the application's main form (Form.MdiParent) to this component, keeping it alive. Now we only have long-term event references from the owning form itself. Really though this is just an added precaution against something I may not have thought of :-) The true memory saver comes from only holding a WeakReference to the owning form. Otherwise in an MDI application we have the following MainForm.MdiChildActivate->DirtyObjectCatcher->Form In such a case c...

Memory leaks

As a follow up to yesterday's post here is a list of problems I found... 01: The following code for some reason causes the form holding the DirtyObjectCatcher to remain referenced. if (Owner.MdiParent != null) { Owner.MdiParent.Activated += new EventHandler(MdiParent_Activated); Owner.MdiParent.MdiChildActivate += new EventHandler(MdiParent_MdiChildActivate); } The odd thing about this is that it really is the events that matter! I subscribe Shown, Disposed, Activated on the Owner (which is a form) and that doesn't cause the same behaviour. The reason is that the Owner normally gets disposed and takes out the DirtyObjectCatcher with it, however, if I have Owner.MdiParent events referencing DirtyObjectCatcher then the form will never get disposed because DirtyObjectCatcher has a strong reference to Owner. Maybe I should change it, but for now the Shown and Activated events seem to be doing the trick. 02: This one was a real pain! DirtyObjectCatcher creates its own Undo...

DirtyObjectCatcher

Oh boy, what a nightmare! After days of messing around I finally found where the memory leak is in my app, it was in DirtyObjectCatcher! The DirtyObjectCatcher used to subscribe to the DirtyListService, so that it was notified whenever an object was made dirty. I experienced this problem... 01: User creates a "Call" to a customer site. 02: User edits a purchase order. 03: Save purchase order (merges the undo block to the Call undo block and closes the form) 04: Edit the purchase order again from the Call form The PurchaseOrder is already dirty so it wont get triggered again, this used to result in no constraints being checked etc and the possibility of entering dodgy data. The solution at the time was to have a static list in DirtyObjectCatcher private List Instances; whenever a new instance was created it would be added, whenever Dispose was called it would be removed. I then hooked into the cache chain and whenever a value changed I would call a static method on DirtyObjec...

TimeBasedSyncHandler

I recently had to tweak my remote persistence server settings. I noticed that I had leaft the SyncHandler.HistoryLength at the default value of 10,000 items. This was overkill because my clients sync every 3 seconds. I thought maybe I should drop this down to about 100, that should be okay? Each client only does about one update every few minutes so I it should, right? Problem is not all of my users are people. One user is a messenger service which looks for unsent messages, sends them one at a time, marking each in turn as sent and updating the database. This gets run every five minutes so probably sends about fifty messages at the most, but what if someone decides to change it to ten minutes, or thirty? So maybe I should increase the HistoryLength to about 200? Then there is the other client, this one syncs with an external database. This could perform hundreds of updates every minute. If the messenger is set to run every thirty minutes...I'm not sure what a good History...

Making a generic type from a Type

List<Person> p = new List<Person>(); This works fine, but what about this? Type someType = typeof(Person); List<someType> p = new List<someType>(); Nope! But you can do this... Type genericType = typeof(List<>).MakeGenericType(someType); Why would I want to? Because I am creating a tool that generates plain old .NET objects from an EcoSpace's model, and I wanted to implement multi-role association ends as public List<Building> RoleName; rather than just public Building[] RoleName;

Hooking into ECO multi-association events

Although I have not (yet) needed this myself I can see myself needing it in the future and the question has been asked before. "Setting HasUserCode=True on a Child.Parent single role does what I want, but how do I handle the scenario where Parent.Children.Add(item) is called on a multirole?" By default you can’t, but with the addition of a single class and a small amount of tweaking you can get it to do what you want! Here is how to do it: 01: Mark Parent.Children’s association end with HasUserCode=True in the modeler and then generate code. 02: In the source code of your class (not within an ECO region) add the following   private EcoMultiAssociation<Child> m_Children; This is a class that does not yet exist, I will show the source code for it later. 02: In the source code locate the "Children" property and change it like so   public IEcoList<Child> Children   {     get    ...

Test Driven MVC and ECO

I have decided that mocking IEcoServiceProvider is not the way to go. Your controller will use the mocked provider during testing but   You don’t want to have to mock every service the provider may return, it’s a lot of work!   You don’t want your controller using a mocked service, and then the EcoSpace using the real one! At first I was mocking every possible service request. IUndoService, IPersistenceService, IOclService, etc. I get bored typing them out in this blog, so doing it in tests was really annoying me. I decided I would instead only mock the service in question. So if I were ensuring that an action wont save an object with broken constraints I would mock GetEcoService<IConstraintProvider> and ensure that I always got a broken constraint. The problem was that the test to ensure I can save a valid object would then invoke the IPersistenceService.UpdateDatabaseWithList method. In my EcoSpace I have decorated my persistence service so th...

ECO, LINQ, Anonymous types, and Web Extensions

I’ve been finding LINQ + Anonymous types really compliment ECO and the new ASP web extensions approach to writing websites. I may have mentioned recently that I don’t like the idea of passing instances of my business objects to the presentation layer. The reason is that someone else will be writing the views for this site and I want to be able to control what they are capable of displaying. It’s not just that though, the fact is that your view might need to look completely different to how your business classes are structured, one layer should not dictate the structure of another. The example I am about to show does in fact have similar structures for the view and model. Having said that there is a slight difference in that the MinorVersion class has its own "int VersionNumber" property, and gets the major part of the version number from self.MajorVersion.VersionNumber. Anyway, now to get on with it. My requirement was to show all major versions, within each major...

Embedded Firebird, error trying to write to file

This error has been really annoying me tonight! I have an app that uses Embedded Firebird for its DB so that I don't need to install a DB server. On Vista my app throws an exception "Error trying to write to file (the correct path here)". I recreated the DB on my development machine (XP) and tried running it, it should work, it has for months, but it didn't! The same error too! For the life of me I couldn't work out why it would suddenly stop working on both machines, what did they have in common? I uninstalled stuff, reinstalled it, etc, no joy. The answer on my XP box was simple. I used the local server to create the GDB file + generate my DB structure using ECO. What I hadn't thought of was the fact that the firebird server then holds a file handle open on that GDB file in case I want to use it again. Embedded firebird needs an exclusive lock on the file so this was the problem on my XP box. I wish the error had read something like "Error tryin...

Test driven ECO

Here are my latest revelations :-) 01 Instead of having to mock IEcoServiceProvider and IOclPsService in order to avoid DB access simply use PersistenceMapperMemory. This way I can create the objects I want, UpdateDatabase, and then run my tests. It’s much easier to read, and more importantly less typing. 02 My page controllers no longer use an EcoSpace. Instead the code always uses a ServiceProvider property of type IEcoServiceProvider. When I want to test my controller I create an instance and set its ServiceProvider property. Now whenever the controller needs to do anything it will go through the ServiceProvider I specified. This is beneficial for a number of reasons. Firstly it means that I can create an EcoSpace in my test and set its PersistenceMapper to PersistenceMapperMemory before activating it. Secondly I can also opt to pass a mocked IEcoServiceProvider which either returns the real service requested or returns a mocked one. An example of this is that I valida...

ECO, should we mock it?

I watched a video on Rhino Mocks yesterday. What a great framework! Obviously I wanted to know if I could use this with ECO so I thought I'd give it a try. In my website's AccountController there is a method like so public void AttemptLogin(string emailAddress, string password, string redirectUrl) { } Now I could just go ahead and write some OCL to find the user, but instead of doing this I really want to separate the code a bit. So I created a class public class UserRepository {   private readonly IEcoServiceProvider ServiceProvider;   public UserRepository(IEcoServiceProvider serviceProvider)   {     ServiceProvider = serviceProvider;   }   public User GetByEmailAddressAndPassword(string emailAddress, string password)   {     string searchEmail = BusinessClassesHelper.EscapeOcl(emailAddress);     string criteria = string.Format("->select(emailAddress.sqlLi...

Unit testing MonoRail controllers

I spent yesterday finishing off (mostly) my business model, then the end of yesterday + today writing test cases for those classes. Everything was going great, I found at least 3 errors in my code that I hadn’t realised was there and also realised there were a few more things I needed. Then it was time to start testing the controllers in my MonoRail site. What a disaster! Attempt 1: [Test] public void AdminOnly_Home() {   AdminController controller = new AdminController();   controller.Home();   Assert.IsTrue(Controller.Response.WasRedirected, "Should have been redirected"); } The problem with this was pretty obvious, Controller doesn’t have a Response etc set up. So along came attempt 2: [Test] public void AdminOnly_Home() {   AdminController controller = new AdminController();   PrepareController(controller);   controller.Home();   Assert.IsTrue(Controller.Response.WasRedirected, "Shoul...

Validation

I have a model like so Product 1----* ProductVersion ProductVersion 1----* ProductEdition ProductVersion can been in one of two states: UnderDevelopment / Released ProductEdition has a DownloadUrl:string attribute which is only required if self.version.status = #Released The validation for ProductEdition works perfectly, I cannot leave the DownloadUrl blank if the ProductVersion has already been released. Unfortunately when I already have a number of ProductEdition instances with no DownloadUrl and then make my Productversion live the editions are not validated because they are not dirty. So I needed some way to ensure that when ProductVersion is validated all related ProductEdition instances are also validated. Step 01: Add a way to allow ProductVersion to identify other objects to be validated. In the business classes project I added the following interface. public interface IValidationExtender {   IEnumerable GetConstraintedObjects(); } My ProductVersion can do this IEnu...

EcoRail

The whole idea of having a controller and a view is so that the view renders only exactly what it is given, and the controller is able to give it whatever data it likes from wherever it needs to obtain it. After working with ECO and Monorail for a while it has been a real pleasure, but I am starting to think that maybe exposing ECO objects directly to the view is not the right approach. If for example I put an Employee into the PropertyBag the view can easily display $Employee.Salary. This might not be a problem when you develop both the controllers and the view but in my case someone else will ultimately create the views. Do I really want them to be able to have access to this information? In addition, what if the view engine they use has a scripting language that is able to set values? Setting $Employee will merely set the PropertyBag["Employee"] value, but setting $Employee.Salary could see a certain view developer buying a new car next month. I am very tempted to chan...

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="Alt...

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; ...