Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Tuesday, February 2, 2010

A way to resolve bugs

I just found a nice blog post by Chris Missal titled "How I Approach a Defect" via a tweet by Elijah Manor.
Chris outlines the systematic approach he takes when solving programming bugs (defects, as he calls them). He underlines the fundamental notion that you should actually fix the problem not just get the right answer for a particular case.
Like Five Ws (5Ws) Chris Missal's defect solving framework tries to ascertain that proper solution has been applied to remove defect by answering following questions:

Does This Solve the Problem? 

Is This Flexible, Maintainable, Clear and Simple?

Does This Leave the Code Better Than I Found It?

Is It Covered with Tests to be Future-Proof?

Is There Any Code that was Commented Out or Stale?

Do Any Named Variables or Classes Exist that Aren't Clear?

Are All Changes Relevant to the Fix?

Please read his post for details of what these questions mean.
Happy Coding!

Tuesday, October 13, 2009

Dealing with TimeStamp columns with SubSonic 3 and MS Sql Server

Today someone asked a question at StackOverflow
regarding problem with SubSonic, not allowing to update record in table with "TimeStamp" typed column. I've been SS enthusiastic since long. I was quick to reply:

You don't need to worry about this. SubSonic is intelligent enough to handle this! Just create new object and assign values to properties and save it.
I then created a table to test it and it worked like charm.




User commented back that he is not able to make it work. It then occurred to me that he might be using SubSonic 3. I tested with SS3 and he was right there was something funny. I got following error:



What is this? SubSonic failed to take into account that a TimeStamp datatyped column should not be explicitly set in Insert or Update statements.

I fired .Net Reflector and opened SubSonic.Core.dll. It took me to the following method in SubSonic.Extensions.Database class:
public static ISqlQuery ToInsertQuery(this T item, IDataProvider provider) where T: class, new()
{
    Type type = typeof(T);

    ITable tbl = provider.FindOrCreateTable();

    Insert query = null;

    if (tbl != null)
    {
        Dictionary hashed = item.ToDictionary();

        query = new Insert(provider).Into(tbl);

        foreach (string key in hashed.Keys)
        {
            IColumn col = tbl.GetColumn(key);

            if ((col != null) && !(col.AutoIncrement || col.IsReadOnly))
            {
                query.Value(col.QualifiedName, hashed[key], col.DataType);
            }
        }
    }
    return query;

As you can see in this line:

It was checking if column was null or auto-increment, and was omitting it from column list for query. By default TimeStamp typed column should be readonly. But even if it was readonly the line above is not checking for ReadOnly property. I also tried to set it to null but it did not work.

I went to GitHub and forked subsonic source code. I was sure putting another check in if statement above will work:

if ((column != null) && !column.AutoIncrement && !column.IsReadOnly)

But when I opened the code the above method read something like this:
public static ISqlQuery ToInsertQuery(this T item, IDataProvider provider) where T : class, new()
{
    Type type = typeof(T);
    ITable tbl = provider.FindOrCreateTable();
    Insert query = null;
    if(tbl != null)
    {
        var hashed = item.ToDictionary();

        query = new Insert(provider).Into(tbl);

        foreach(string key in hashed.Keys)
        {
            IColumn col = tbl.GetColumn(key);
            if(col != null)
            {
                if(!col.AutoIncrement && !col.IsReadOnly)
                    query.Value(col.QualifiedName, hashed[key], col.DataType);
            }
        }
    }
    return query;
}
Hmm, the problem is already sorted out. The questioner is also using dll from some old build. I compiled, added reference and re-ran the test code. No luck. It confronted me with same error. I put break point at save statement to delve deeper. The column was never set as ReadOnly :(

I scourged the generated code and saw what it generated for TestTimeStamp table. It read:

public class TestTimeStampTable: DatabaseTable {
    public TestTimeStampTable(IDataProvider provider):base("TestTimeStamp",provider){
    ClassName = "TestTimeStamp";
    SchemaName = "dbo";
    ………………
    ………………

    Columns.Add(new DatabaseColumn("RowVersion", this)
    {
        IsPrimaryKey = false,
        DataType = DbType.Binary,
        IsNullable = false,
        AutoIncrement = false,
        IsForeignKey = false
    });
}

So problem was somewhere here! When creating column, SS was not putting if the column is readonly or not. I checked structs.tt T4 template.

It has following code:
<# foreach(var col in tbl.Columns){#>
    Columns.Add(new DatabaseColumn("<#=col.Name#>", this) {
         IsPrimaryKey = <#=col.IsPK.ToString().ToLower()#>,
         DataType = DbType.<#=col.DbType.ToString()#>,
         IsNullable = <#=col.IsNullable.ToString().ToLower()#>,
         AutoIncrement = <#=col.AutoIncrement.ToString().ToLower()#>,
         IsForeignKey = <#=col.IsForeignKey.ToString().ToLower()#>
    });

<# }#>

It is not even bothering to check if column is readonly or not :( I put following line after IsForeignKey line:
IsReadOnly = <#=col.DataType.ToLower().Equals("timestamp").ToString().ToLower() #>

On saving the file the code was regenerated. TestTimeStamp class now read:

Columns.Add(new DatabaseColumn("RowVersion", this) {
    IsPrimaryKey = false,
    DataType = DbType.Binary,
    IsNullable = false,
    AutoIncrement = false,
    IsForeignKey = false,
    IsReadOnly = true
});

I tried my luck again. It ran without any error. I ran it again, opened SQL Server Management Studio and executed SQL Query:

Select * From TestTimeStamp

Now it returned:

RowIDRowDescriptionRowVersion
---------------------------------------------------------
1Hello world!0x00000000000007D1
2Hello world, Again!0x00000000000007D2
(2 row(s) affected)
Happy Coding!

Friday, October 17, 2008

Showing HTML Content over Flash Movie - quick and dirty way!

I had faced a nasty problem few days ago. I was to show user a modal-popup (in html page) for Terms and Conditions for registration on a site. Popup was coming okay, but There was a flash movie at top of the page which was hidding upper portion of the dialog. The tested and widely used method is to put an Iframe at place where you want to show your content and absolute position your content and IFrame. For example, if you want to show a div above a flash movie, then place a IFrame like follows:
        <iframe style="position:absolute;top:250;left:150;"></iframe>
Then position the div exactly above this iframe like:
        <div style="position:absolute;top:250;left:150;"></div>

I was using jquery on the page to show dialog using ui.dialog plugin.
After fooling around sometime I devised following simple solution.

1)  put id attribute on movie element to uniquely identify the movie object. Like,
<object id="movie1"></object>
2)  before showing the dialog (or other content for that matter) call a javascript function to hide the movie. Like,
$("#movie1").css("display","none");

3)  now show dialog. Like,
$("#dialog").dialog("open");

4)  after closing the dialog, show the movie again. Like,
     $("#dialog").dialog("close");
$("#movie1").css("display","inline"); 

that's all folks, Happy Coding

Monday, January 28, 2008

Working with Anthem.NET and AJAXControlToolkit CalendarExtender

I've wasted almost complete day to debug what now seems very trivial. I'm using Anthem.NET in my project. I almost exclusively use Anthem.NET in my ASP.Net applications for AJAX. Almost because I've to rely on AjaxControlToolkit for some capabilities, like Calendar and ListSearchExtender.
I'm using Anthem ListBox box, and some textboxes on a page. Listbox generates a callback and textboxes are populated async'ly. One of the textboxes is for date input. I've used CalendarExtender control to show dropdown (I just love it for this thing) calendar. When page first loads calendar shows nicely, but as soon as callback is generated, it stops working.
After looking at generated page, I found code responsible for creating client side calendar. It is this one:
Sys.Application.add_init(function() {
$create(AjaxControlToolkit.CalendarBehavior, {"format":"dd/MMM/yyyy","id":"MyCal"}, null, null, $get("ctl00_ContentPlaceHolder1_txtPurchaseDate"));


So, it seemed very simple register a PostCallback function for ListBox, with $create method in it, to recreate calendar everytime a callback occured.

So far so good, but it cropped up control with duplicate id problem. I tried $dispose method from ajax.net library, but it told me that element I'm looking for is unavailable. Then I tried prototype to remove the said element from the DOM tree, but it was also not able to find element.

Then after googling many times for many things (in the meantime reading scripts in AjaxControlToolkit source code, using reflector to go through System.Web.Extensions.dll and using firebug extensively) I got to Ajax.NET reference on asp.net (now, don't laugh at me that it is not in my delicious, as I've been relying mostly on Anthem.NET).

There I found the whole story at page for Sys class [here]. I used $find method to get my element and used removeComponent to remove previous instance before creating new one.
Sys.Application.removeComponent($find("MyCal"));

Monday, August 27, 2007

Running Firebird Embeded Database in .NET 2

I wanted to create a small application to keep track of my daily expenses. Me and my friend (we are also room mates) think that we are expending too much because we are unstructured. So I thought to give it time this Sunday.

I decided to use embedded Firebird server for easy portability.

Go to Firebird site and it says that embedding Firebird is a breeze. Me to thought so. But it might be little cumbersome as many things have changed in Firebird version 2.
I downloaded Firebird embedded package. Copied fbembed.dll and Firebird.Data.FirebirdClient to my executable directory, but every time I tried to execute
FbConnection.CreateDatabase()
I got 'Unable to load DLL "fbembed"' error.

Googling for it yielded no results except advice for copying fbembed.dll and FirebirdClient assembly to the folder where executable is.

I copied everything from embedded package and it worked. But time and again it is mentioned that every thing from package is not needed. So now again I removed the embedded stuff and started things one-by-one.

  • First fbembed.dll and FirebirdClient assembly --> It did not work.


  • Then I added all the dlls (i*.dll) from embedded package with firebird.msg --> It did not work.<.li>
  • Then I added intl folder --> It worked!!!



No I coppied these files to bin folder and added the intl folder and the dlls to my .NET Project and set their build action as content and Copy to Output Directory as Copy Always.

It is working fine and I don't have to copy it to release or debug folders.

Happy Codding ;-)