Tuesday, December 21, 2004

Inferring... or just guessing!?

Yes, Yes, another bug...

We add support for multiple languages to out Web Application, and a lady from the QA asked me solve the following bug:

When inserting Hebrew (or any language other than english) characters to a TextBox and saving to the Database, you get Question Marks ("????????") instead of Hebrew characters.

But is it fun enough? No?

So lets add that
it doesn't happens everytime...

First, I have checked the Database field: [Name] [nvarchar] (50)
It was NVarChar, which is ok.

Then I have looked at the Stored Procedure : @deals ntext
It declared a parameter of the type - nText.
This is fine, because actually this parameter gets an xml string of the whole Dataset, which can become big.

Next, I have checked the SqlCommand's Parameter in the code:

StringWriter writer = new StringWriter();
newDeal.WriteXml( writer , XmlWriteMode.DiffGram );

sqlCmd.Parameters.Add ( "@deals" , writer.ToString() );

You can see that the code uses the overload which doesn't declare the SqlDbType.
So lets check it on Run-Time.

Usually, the SqlDbType was nVarChar, but when the bug occured it was VarChar !!!

But why is it has been set to VarChar?

After a lot of thinking and experiments, I finally got it:

when the value used in the "Add" statement is a string, the framework use nVarChar as its default SqlDbType.


if the string is
longer than 4000 characters (which is the size limit of nVarChar on SQL Server) the framework uses VarVChar instead.


Without checking if
you have any unicode characters in the string.
I won't call it "Inferring"
(microsoft term) - I'll call it "guessing"

Of course, after you know the problem, solving is not an issue.
Just declare the Parameter type explicitly!

And, by the way, after you know the problem you can easily find the Microsoft's document which tell you what you didn't know:

"String - NVarChar. This implicit conversion will fail if the string is greater than the maximum size of an NVarChar, which is 4000 characters. For strings greater than 4000 characters, explicitly set the SqlDbType."

See you soon


Sunday, December 05, 2004

Cruel Bug and the IIS Default Document

Last week, one guy from our QA department called me with a bug he found in one of our Web forms. After a short debugging I have discovered that one of the Session variables has been overwritten by with the wrong data – after been filled with the right data.
The code which causes the problem was not in the requested Web Form. Actually, it was on our "Default Document" - Default.aspx (which we declared in IIS).
But why is this default page been loaded? Who called it?And why does the browser gets the right page and not the default page if it does been called?
The next step was to put a breakpoint on the unwanted code, and watch for the "Call Stack" to see who called this code. This is a dead end. No user code calls this page.
But wait, maybe the application is being redirected to this page by "Response.Redirect" or by "Server.Transfer"?But the answer (after checking all the call to those two functions) is – No.
"Application_BeginRequest" in "Global.asax" is our next station.This is a good place to out a breakpoint, and it works this time too.
My breakpoint is being hit twice, once for the requested page, and again for the Default document page.
So, now I know that the unwanted code runs because the browser requested it.But when looking on the source of the page received by the user's browser, I can't find any redirection to the default page…
And then I got it.
One of the images tags in the html source was:

It was without any file name because there wasn't any image for this item in the DB, and the programmer hasn't checked for empty strings in this field.The browser requests this path from IIS, which in turn translate it to a request for the default document page. This, of course, explains why the browser doesn't show the default document. It asks for it as in image…I have just removed this image from the page to see if it solves the problem…
NO. It still happens.
I have read the html source again and again, searching for another mistake like that…YES!!! I got it!

The browser take the empty string of the "src" attribute as a request to the current path, which IIS answer with the default document again!
Never leave any unspecified "src" attribute. You'll end with the browser requests the default document of the current directry.
After I have finished to write this blog, I have found this blog
I wish I have read it before meeting this bug...