How to debug your code

Dec 8, 2011 at 10:10 AM

With two specific entities we receive this message when saving: "Edit was unsuccessful. Please correct the errors and try again." There's no other clue on what went wrong so we need to debug our code but we've been quite unsuccesful. Perhaps anyone can share a good practice?

Coordinator
Dec 8, 2011 at 4:06 PM

I can only share a few tips:

1) If you have any kind of customisation of views at all (though I'm assuming you don't here), I recommend that you create a parallel run project that has only the generic views with no customisation  - and revert to that one for debugging.  (For example, in custom views it is easy to accidentally obscure or omit some of the feedback information).

2) In this particular case:

- Are you editing a persistent object, or attempting to save a transient one?  If the latter, then this kind of issue can arise if you have any associated transient objects that are not complete (or not saveable for other reasons). That said, you still ought to be getting some kind of feeback about it.

- Are you using any complex types? (Though, again, more specific feedback should be there).

3) Sometimes it can be helpful to switch off the entity persistor and use the in-memory persistor to see if you get the errors with both  -  this is a one line change in the Run class.

Dec 9, 2011 at 1:42 PM

Thanks for the tips. I did exactly what you suggested:

  • removed custom custom views;
  • use in-memory persistor (great for testing in combination with fixtures);
  • not using complex types;
  • testing on both transient and persistent objects;

The error keeps occurring so we will continue our investigation.

Coordinator
Dec 9, 2011 at 2:56 PM

This may be related to issue #10 where we were returning an inadequate error message in certain circumstances. 

If so you may find that if you build a more recent version of the code including the fix for issue #10 you get a better error message.

Generally also the symbols have been uploaded to symbolsource.org so you should be able to debug into the code. Eg you should be able to put a breakpoint in one of the methods in GenericController and then step through the code from there.

Dec 12, 2011 at 3:43 PM

Thanks for the tips Stef. Debugging this issue is a nice deep dive into the framework ;-)

The ValidateChanges in the NakedObjectsController class tries to validate an (already persistent and valid) associated object here:

if (ModelState.IsValid) {
    foreach (INakedObjectAssociation assoc in usableAndVisibleFields.Where(a => a.IsInline || form.AllKeys.Where(k => k.StartsWith(a.Id)).Any())) {
        INakedObject inlineNakedObject = assoc.GetNakedObject(nakedObject);
        ValidateChanges(inlineNakedObject, form, assoc);
    }
}

End then on the first field of the associated object which is mandatory it doesn't find a new value :

foreach (var pair in fieldsAndMatchingValues) {
    if (pair.Item1.IsMandatory && string.IsNullOrEmpty(pair.Item2)) {
        AddErrorAndAttemptedValue(nakedObject, pair.Item2, pair.Item1, MvcUi.Mandatory, parent);
    }
}
I'm puzzeled by the fact that it tries to validate this associated object, perhaps someone has a clue?

 

 

Coordinator
Dec 13, 2011 at 8:17 AM

I'm wondering if this is the same problem as issue #11 - which has had a fix checked in - perhaps you could apply it and see if it helps ?

Dec 13, 2011 at 12:53 PM

I think I found the cause for this problem:

We have two enities, Lease and LeaseItem and the StartsWith method is true for all keys in this part of the NakedObjectsController.cs:

if (ModelState.IsValid) {
    foreach (INakedObjectAssociation assoc in usableAndVisibleFields.Where(a => a.IsInline || form.AllKeys.Where(k => k.StartsWith(a.Id)).Any())) {
        INakedObject inlineNakedObject = assoc.GetNakedObject(nakedObject);
        ValidateChanges(inlineNakedObject, form, assoc);
    }
}

After making sure we match against the object part it works fine:

foreach (INakedObjectAssociation assoc in usableAndVisibleFields.Where(a => a.IsInline || form.AllKeys.Where(k => k.Split("-".ToCharArray())[0].Equals(a.Id)).Any())) {
I don't know if the Split function is the best way to return the first part before the dash but it works for me ;-)

-Jeroen

Coordinator
Dec 13, 2011 at 3:27 PM

This is issue #3 which has been fixed. Apologies for you having to find and fix a bug which has already been fixed in the code but not released. 

We've been busied out since the last release but will put out a bug fix release soon - probably just after Christmas. 

Dec 13, 2011 at 4:19 PM

I used the source code (also to test if issue #11 solved the case) and apperently you didn't fix issue #3 completely since there are two "k.StartsWith" comparisons in the code. You've changed only one into "IdHelper.StartsWith", it got stuck at the other one. Do you think "StartsWith" is a good function to do an exact comparison? Anyway, here's my patch using a Split:

# HG changeset patch
# User jvanderwal@ams-7-nl19.ECP.LOC
# Date 1323780376 -3600
# Node ID f644636bb5b6b12deae9957fabcac3a58b78ccf1
# Parent  db8076b50848945a605fdb77a709a820f7a41fb5
fixed issue with validation

diff -r db8076b50848 -r f644636bb5b6 MVC/NakedObjects.Mvc/Controllers/NakedObjectsController.cs
--- a/MVC/NakedObjects.Mvc/Controllers/NakedObjectsController.cs	Tue Nov 08 17:25:49 2011 +0000
+++ b/MVC/NakedObjects.Mvc/Controllers/NakedObjectsController.cs	Tue Dec 13 13:46:16 2011 +0100
@@ -352,7 +352,7 @@
             }

 

             if (ModelState.IsValid) {

-                foreach (INakedObjectAssociation assoc in usableAndVisibleFields.Where(a => a.IsInline || form.AllKeys.Where(k => k.StartsWith(a.Id)).Any())) {

+                foreach (INakedObjectAssociation assoc in usableAndVisibleFields.Where(a => a.IsInline || form.AllKeys.Where(k => k.Split("-".ToCharArray())[0].Equals(a.Id)).Any())) {

                     INakedObject inlineNakedObject = assoc.GetNakedObject(nakedObject);

                     ValidateChanges(inlineNakedObject, form, assoc);

                 }

Coordinator
Dec 13, 2011 at 4:48 PM

Then I'm doubly sorry - 1. for not fixing it in both places and 2. if it needed fixing in two places it was poor code (quite apart from the bug). I'll get a fix checked in - thanks for the patch.  

Dec 13, 2011 at 5:08 PM

No worries, I'm not pretending that my code is any better ;-). Perhaps a helper method returning a specific part of the key would be more descriptive eg IdHelper(k).GetEntityName.Equals(a.Id).