Monday, June 25, 2007

Dict.cn

I have been using this English-Chinese dictionary website for a while, and I am really amazed with all the functionalities it provides. Traditionally, if you look up a word in the dictionary, you may forget it in the next day and have to look it up again, and the dict.cn allows you to save all your unfamiliar words into the profile. This is particular useful if you are in a learning process, you can always come back to review the words you have marked before.

Another impressive feature is that the site has collected all the words for a particular subject, say, if you want to review all the GMAT words, you can go there and review that particular subject:



When you review a particular test, you can track all your progress in your profile, this is very cool..



Thursday, May 17, 2007

SQL Reporting Service could get a little bit frustrated. (Invalid Object about temporary table.)


I am starting to use the SQL reporting service to generate a couple of reports for the project I am working on right now, and it could get a little bit frustrated for a newbie.


In my process, I need to generate a report based on a stored procedure.


Then, I got the following error which complains that the temporary table is invalid.

What you can do, the temporary table should be perfectly fine in the stored procedure. I just clicked OK.


Since the dataset was not generated successfully, it won’t automatically generate a list of report parameters for you.



The good thing is that unlike Crystal report which the underlying format is in binary, sql report is all xml based, which gives a lot of flexibility in editing the report manually.


You can simply manually add a list of report parameters like this in the rdl file (open it in any text editing software).


<ReportParameters>

<ReportParameter Name="countyID">

<DataType>String</DataType>

<DefaultValue>

<Values>

<Value>e12b5415-de73-4751-b2cb-2e98740c4460</Value>

</Values>

</DefaultValue>

<Prompt>County ID</Prompt>

</ReportParameter>

<--- other report parameters>

</ReportParameters>


This will generate a list of report parameters


But how do you pass those reporting parameters to the sql query parameters. If you put a table control on the report, and set the underlying data source to the previous dataset, and try to preview it. It will give you another error like this:




There are two ways to address this issue:

  1. one way is that you go back to the dataset, set the Parameters manually there.

  1. The other option is that you can still edit in the xml file, which is the way I preferred. Under the DataSets, looking for the DataSet interested, and set the QueryParameters there…

<DataSets>

<DataSet Name="ComplianceMissing">

<Query>

<DataSourceName>EarlyTrack</DataSourceName>

<CommandType>StoredProcedure</CommandType>

<CommandText>rptGetComplianceMissingChild</CommandText>

<QueryParameters>

<QueryParameter Name="@countyID">

</QueryParameter>

</QueryParameters>

</Query>

</DataSet>

</DataSets>



The whole process is not that trival…

Integrate Visual Studio 2003 with the Team Foundation Server Process


The Team foundation server is release by Microsoft after Visual studio 2003, so the visual studio 2003 has to go through a couple of manual configuration process to be able to work with Team Foundation Server.


  1. Download “Visual Studio 2005 Team Foundation Server MSSCCI Provider” from Microsoft Website. (The download link could change in the future, it’s best to download a copy and store it on some place on the server).

  2. The prerequisite to this installation is that you must already have:

    1. Visual Studio 2005 Team Foundation Server

    2. Visual Studio 2005 Team Explorer

    3. .NET Framework 2.0


If you already work with Team Foundation Server with the Visual Studio 2005, you should already have those program installed.


  1. To add an existing project to the Team Foundation Server, Right Click the Solution you want to add to the Team Foundation Server, and click “Add solution to source control”.


  1. Select the Tfs server you want to connect to: (If it’s the first time you connect to the Tfs server, you have to type in the Tfs server name you want to connect to.)


  1. Add the project to the Tfs Server.


  1. After adding the project, you can see all the icons turned to “checked in” status.

  1. You can also go to File -> Source Control to add an existing project to the solution.

Saturday, May 05, 2007

What Http Modules are configured in the machine.config .

I am looking into an issue what happens if you forgot to put any session configuration in the web.config file. The session state is one of the http modules configured in the machine.config file, there are a few besides the session state module. The following is what I found in my machine.config file.


<httpModules>
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />
<add name="Session" type="System.Web.SessionState.SessionStateModule" />
<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />
<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />
<add name="AnonymousIdentification" type="System.Web.Security.AnonymousIdentificationModule" />
<add name="Profile" type="System.Web.Profile.ProfileModule" />
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</httpModules>

Basically, when the Http application starts, it will loop through all the http modules which are configured.

And SessionStateModule is one of them, and if you look into what SessionStateModule.Init() actually does. which in turn will call InitModuleFromConfig.



Notice that SessionStateSection config = RuntimeConfig.GetAppConfig().SessionState;

And here is what it does in RuntimeConfig.GetAppConfig().SessionState.

internal SessionStateSection SessionState
{
get
{
return (SessionStateSection) this.GetSection("system.web/sessionState", typeof(SessionStateSection));
}
}

Here is what it actually tried to read the section from "system.web/sessionState", but what if this section is missing, it will default all its values to default value of SessionStateSeciton. This is just my guessing, I tried to verify it through reflector, but the code is kind of confusing to me. When you cannot step through the code through debugger, you can only step through your code through your head. It becomes a little bit confusing..

Here is what I see the SessionStateSection in the reflector..


Wednesday, April 25, 2007

Set up the Database Trace Listener in Enterprise Library.

I am getting very interested in Microsoft Enterprise Library lately for a couple of reasons:
  • It addresses a couple of common issues you will normally face, like logging, caching, and you really don't want to do those plumbing code if possible.
  • It gives you a nice configuration tool ( you can open this tool within visual studio for the Enterprise Library 3) .
  • It gives you all the source code, so you can see what's under the hood.
I am playing with the Logging application block in last two days, the best way to learn those tools is always to check the QuickStart source code. I found the quick start doesn't provide an example to show you how you can log the error into the database, which I believe is the most used cases in the system.

I did a brief research, and you actually have to reference another dll (Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll) in order to be able to log into the database.

Basically, you have to do the following steps :
1. The "Microsoft.Practices.EnterpriseLibrary.Logging.Database.dll" has to be referenced.
2. The scripts under "C:EntLib3SrcApp BlocksSrcLoggingTraceListenersDatabaseScripts" has to be run against the database to create the necessary tables and objects.
3. The "Database Trace Listener" has to be added to the "Trace Listeners". For the trace listener, you have to specify the Formatter, otherwise, you will get an error.
4. Put the "Trace Listener" under the Category you want to log.

Here is a screenshot of the configuration file..


Saturday, April 21, 2007

Try to avoid sql generated names if you want to use change scripts to do the database upgrade.

Sometime, if you don't explicitly name an object when you create an object in sql server, the sql server will create a default name for you. It is not too bad if you have some sophisticated tool to migrate your database. But if you want to run your change scripts manually , it's best that you name every object you created, not relying on the system generated name.

One way to create an object in the sql server is normally dropping it firstly, that's where I got hit when relying on the system generated name.

I have an sql script like this:

IF dbo.ColumnAlreadyExists('BusinessCategory','IsActive')=1
BEGIN
ALTER TABLE BusinessCategory DROP COLUMN IsActive
END

ALTER TABLE BusinessCategory ADD IsActive Bit DEFAULT 1

It's fine when I ran it the first time, it generated the new column for me, but when I ran it again, it complains there is a default constraint object on the IsActive column which needed to be dropped firstly. The issue is the system generated a long name for my default constraint. The name is long, hard to remember, and could be changing, so it makes the changes scripts hard to write.

So, the better way is to use a named object instead like this:


ALTER TABLE BusinessCategory ADD IsActive Bit
GO
ALTER TABLE BusinessCategory ADD CONSTRAINT BusinessCategory_Default DEFAULT 1 FOR IsActive
GO

That way, you can always drop the named constraint if you want to drop it like this:

IF dbo.ColumnAlreadyExists('BusinessCategory','IsActive')=1
BEGIN
ALTER TABLE BusinessCategory DROP CONSTRAINT BusinessCategory_Default
ALTER TABLE BusinessCategory DROP COLUMN IsActive
END

Wednesday, April 11, 2007

The debugger may cheat you on cache.

Cache is pretty tricky to work with. On one side, you have to use it to improve the performance of your application, On the other side, cache is very tricky to work with and needs careful consideration when putting it into your application.

I recently works on a state government project which uses a lot of cache in the application. Simply put, it uses a static class to cache a lot of lookup tables. One simple example is like this:

public static class Cache
{
public LookupTable TestTypes
{
if(HttpRunTime.Cache["TestTypes"]==null)
{
HttpRunTime.Cache.Insert("TestTypes", CreateTestTypes(), SqlDependency);
}
return HttpRunTime.Cache["TestTypes"];
}
}

This code looks perfect, but it throws out mysterious exceptions a lot of times.

There are two issues here:

1> Don't run HttpRunTime.Cache["TestTypes"] twice, even HttpRunTime.Cache["TestTypes"]==null returns false, when you actually gets the value from HttpRunTime.Cache["TestTypes"], it could be reevaluated and return null.
2> Even you insert HttpRunTime.Cache.Insert("TestTypes", CreateTestTypes(), SqlDependency) here, the insertion may fail, say, there is an out of memory situation, you cannot gurantee HttpRunTime.Cache["TestTypes"] is not null.

LookupTable lookupTable=Cache.TestTypes; If you assert the value returned by the lookupTable is not equal to null, like this: Debug.Assert(lookupTable!=null), you will see a strange phenomena when the debugger stops at this point: the lookupTable is null, but the right side of the expression is NOT null.

This is because the Cache.TestTypes is reevaluated by the debugger, and its value is not the same value when the code executes, which was NULL. I know it's a little bit confusing. When you put the Cache.TestTypes in the watcher window, the debugger actually checks if HttpRunTime.Cache["TestTypes"] is null again. And if it is, it will insert the value into the cache again.

A more robust way is handle the cache like this:

public static class Cache
{
public LookupTable TestTypes
{
TestTypes testTypes= HttpRunTime.Cache["TestTypes"];
if(testTypes==null)
{
testTypes=CreateTestTypes();
HttpRunTime.Cache.Insert("TestTypes", testTypes, SqlDependency);
}
return testTypes;
}
}

References:
1. K. Scott Allen Wierd Caching
2. Peter Johnson HttpRuntime.Cache vs. HttpContext.Current.Cache
3. 蝈蝈俊.net HttpRuntime.Cache vs. HttpContext.Current.Cache





Sunday, April 08, 2007

As you know, you have to go to war with the Army you have, not the Army you want,"

This is what Rumsfeld said. I am sure this infamous saying also played a rule for his step down as Secretary of Defense. But I guess it also applies to a lot of developers like us. As a developer, you normally don't have the option to choose the best tools you have because you are the money maker, but NOT the money decision maker.

In the company worked before, we use visual studio professional to develop some performance sensitive application (GIS). The application involves a lot of graphics rendering, geometry processing, some real hard-core algorithm. We encounter some performance issue, and really would like some professional tools to profile it. But again, we cannot make the decision, because the visual studio team edition costs much more than the professional edition.

Now, I am working on Team Edition for software developer on my new job, but my current job uses so much database functionality, and I really hope I can have Team Suite, which contains the database piece of the Team edition. But again, I cannot make that decision.

Sometimes, as a developer, you just have to work the best with what you have. If you cannot make a decision or persuade the management to make a decision to offer sophisticated tools for you, just try to find some open source, or free tools.

Sometimes, you may have to go back to use some old fashion command way to finish your stuff.

I really hope I, as a developer, have more right in the company to decide what tools I want to use.

Saturday, April 07, 2007

Another google impressive product-google pin yin.

For people who don't type chinese , it may be a little bit hard to understand. A lot of chinese people had hard time to input chinese like me. It's not because there is no good input tools, I know, there are a few very good input tools available. But to use those tools efficiently, you have to be very good at "pin yin". A lot of people like me spoke a dialect which is far away from standard mandarin, which is most input methods are based upon. The following is a fuzzy logic that google uses to make sure those non-standard speaker could have a decent input speed.


For myself, I am terrible at mixing some of them, like those pairs (an-ang, en=eng).

Another good feature is that you can have google store your selection patter on the server, so, it can automatically retrieve your selection next time. A good example, when I type my name, I put jianwei, and it will put my name as the first choice, because it remembered my choice of the last time.


I am waiting for another impressive product from google...



Thursday, March 22, 2007

Visual Studio Database Project.

Visual studio 2005 has a lot of project templates when you choose to create a new project. I used mostly library project, windows form project, web project.

The one I used today is visual studio database project. I worked on a state government project which uses a lot of tables, stored procedures.

The database project will allow me to organize all my queries, scripts, stored procedures into one project. It's very neat. Before I started to use that project, I cannot organize all my database scripts very well.  I normally keep all my scripts in one file, and copy one or another to the sql query analyzer. Then I get confused when I have a lot of scripts.

Tuesday, March 20, 2007

Stored procedure debugging error.

I keep getting the following error when debugging a stored procedure.

The strange thing is, every time, when I start the first debug session in visual studio, it's fine, but when I tried the second, third time, it's failing.

I have to restart the Visual studio 2005 Remote Debugger service manually every time I want to step from the code into the stored procedure.









Thursday, March 01, 2007

Finished reading another book.

I just finished reading another asp.net book ASP.NET 2.0 Illustrated. This book is a very comprehensive coverage of Asp.net, but really didn't get into many details. It gives a lot of screen captures, with a lot of MSDN style figures, diagrams explaining different configuration settings.  I would use it more like a reference book.  It doesn't cover more updated features like ajax, which alone probably deserves another book.

If you are a beginner in asp.net, this is probably the book for you, but if you have known the asp.net very well, you probably will look for another advanced book.

Wednesday, February 28, 2007

The ASP.NET process identity does not have read permissions to the global assembly cache.

I am trying to run the default website installed by the CLSA.net, but it keeps giving me this error until I reinstalled the asp.net on my development box.

The step I follow is :

  1. Open a command prompt
  2. Stop IIS: iisreset /stop
  3. Change to the .NET Framework 2.0 root directory: C:\winnt\Microsoft.Net\Framework\v2.0.50727\
  4. Reinstall ASP.NET 2.0 by using the following command: aspnet_regiis -i command.
  5. Start IIS again after it has been run: iisreset /start

"Timeout expired" error message when the sql debugging is on.

Following yesterday's post, now, I am able to debug into the stored procedure from my windows application or web application. But after a couple of times, I start to receive annoying "Timeout expired" error message when the program tries to open a connection to the server.

Finally, I have to find another KB830118,  and the status of this issue is "This behavior is by design".  I am start to doubt if "step into stored procedure" will cause the web site hanging in debug session, what is the real use of it.

Interesting..., maybe all those KBs are existing to address those stupid bugs.

Tuesday, February 27, 2007

Magic EXEC SP_SDIDEBUG 'legacy_on'

In my previous job, I don't have to do too many stored procedures and those stored procedures are generally simple. The project I am working on right now involves a lot of stored procedures, and I need a good way to debug it. It's pretty easy if I am working in visual studio 2005 and SQL server 2005. Everything works right out of box.

But when I started to use visual studio 2003 to debug a stored procedure on SQL server 2005, it complained that the sp_sdidebug cannot be found. It's true, this particular debug procedure is not in the "Extended Stored Procedures" of the master database of the SQL server 2005, but it is in the master database of the SQL server 2000.

So, I moved the database to the SQL server 2000. It's getting much better, it can allow me to debug into the stored procedure from the server explorer.  It at least proved that the SQL debugger is working. But every time, when I tried to debug into the stored procedure from the vb.net code, it never stepped into the code.

I searched a lot of posts, and a lot of posts pointing to this KB328151. I tried this magic statement EXEC SP_SDIDEBUG 'legacy_on'  , no , it didn't work. I rebooted the server machine, tried this statement again, it seemed it worked finally. 

In the KB, it mentioned it's only an issue of SQL server sp3, actually, my SQL server is sp4 , and it still applys.

Monday, February 26, 2007

Visual studio 2005 Class Designer

I am not a big fan of UML, or any diagram in the development process.  The biggest issue I found is the inconsistency between those nice diagrams and the actual codes.  I just found it's too difficult to think over every possible situations at the beginning stage of the project, not just the developers. The clients also have the same issue, they are not very clear what they want too at the beginning. I find out unless you are a real guru in making those nice diagrams, and you can always make changes to those diagrams very fast ( I am NOT), it's so hard to keep those diagrams consistent with your code when the project requirements change.

 

The visual studio class design is a different story. The changes you made to the designer can be applied to the code instantly, on the other hand, the changes you made to the code can be applied to the designer instantly too. You don't have to worry about two pieces any more, you can just worry about one piece.

 

There is a power toy for the enhancement here too.

Thursday, February 22, 2007

Scrollable DataGrid with Sorting - ExtremeExperts

Scrollable DataGrid with Sorting - ExtremeExperts

I am working on a project which uses a lot of datagrid, and yes, it's still based on .Net 1.1 framework. The annoying issue is the scrolling, all the headers are scrolled with the grid when the datagrid is scrolled. Asp.Net renders all the datagrid to one table, and it's not surprising that the header will be scrolled.

I found a solution here, but the issue is the aligning of the columns between the header tables and the content tables rendered by the grid.

I ends up writing some javascript code.


function AdjustTable(firstTableId, secondTableId)
{
if(document.getElementsByTagName)
{
var firstTable = document.getElementById(firstTableId);
var secondTable = document.getElementById(secondTableId);
if(firstTable!=null && secondTable!=null)
{
var firstTableRows = firstTable.getElementsByTagName("tr");
var secondTableRows=secondTable.getElementsByTagName("tr");
if(firstTableRows!=null && secondTableRows!=null)
{
if(firstTableRows.length>0 && secondTableRows.length>0)
{
if(firstTableRows[0].cells.length==secondTableRows[0].cells.length)
{
for(i = 0; i < secondTableRows[0].cells.length; i++)
{
secondTableRows[0].cells[i].style.width=firstTableRows[0].cells[i].clientWidth;
}
}
}
}
}//if(firstTable!=null && secondTable!=null)
}
}

This will loop through all the table cells in the first row for the second table, and set the width to be the same with the table cells in the first row of the first table.

Tuesday, February 20, 2007

SQL Server 2005 Compact Edition and SQL Server 2005 Express Edition

I have been using the Express Edition for a while, but are not aware the difference between the compact edition and the express edition. Here is a white paper.

Monday, February 12, 2007

Design time rendering and run time rendering.

I was doing some work on the GMap.Control over the weekend. On thing I found is that whenever I drop the control on the form, it always gives me an error on rendering, error to create control, error to render a control.

The problem is , when the visual studio render a control on the form, it will look for the DesignerAttribute, if it's not available, it will look for the default ControlDesigner. The ControlDesigner has a default method called GetDesignTimeHtml() , It will render the view on the form.

Use the reflector, here is what GetDesignTimeHtml() will do by default:

public virtual string GetDesignTimeHtml()
{
StringWriter writer1 = new StringWriter(CultureInfo.InvariantCulture);
DesignTimeHtmlTextWriter writer2 = new DesignTimeHtmlTextWriter(writer1);
string text1 = null;
bool flag1 = false;
bool flag2 = true;
Control control1 = null;
try
{
control1 = this.ViewControl;
flag2 = control1.Visible;
if (!flag2)
{
control1.Visible = true;
flag1 = !this.UsePreviewControl;
}
control1.RenderControl(writer2);
text1 = writer1.ToString();
}
catch (Exception exception1)
{
text1 = this.GetErrorDesignTimeHtml(exception1);
}
finally
{
if (flag1)
{
control1.Visible = flag2;
}
}
if ((text1 != null) && (text1.Length != 0))
{
return text1;
}
return this.GetEmptyDesignTimeHtml();
}
Actaully, at the design time, a lot of objects are not initialized properly, so it will cause an exception.
So, I made an easy approach, I override the GetDesignTimeHtml() method to let it simply draw a string. Of course, there are a lot of more interesting stuff you can do here.
 



public override string GetDesignTimeHtml()
{
try
{
StringBuilder sb
= new System.Text.StringBuilder();
sb.Append(
"GMap2 Server Control");
return sb.ToString();
}
catch (Exception ex)
{
return GetErrorDesignTimeHtml(ex);
}
}



It at lease won't give me any error anymore.

Sunday, February 11, 2007

DataReader vs DataSet

A very good article about Data Access in .Net

Enterprise .NET Community: Designing Performance - Optimized ADO.NET Applications

This is also a question I was asked in an interview..

Choosing Between a DataSet and a DataReader

A critical choice when designing your application is whether to use a DataSet or a DataReader to retrieve data. If you need to retrieve many records rapidly, use a DataReader. The DataReader object is fast, returning a fire hose of read-only data from the server, one record at a time. In addition, retrieving results with a DataReader requires significantly less memory than a creating a DataSet. The DataReader does not allow random fetching, nor does it allow for updating the data. However, .NET data providers optimize their DataReaders for efficiently fetching large amounts of data.

In contrast, the DataSet object is a cache of disconnected data stored in memory on the client. In effect, it is a small database in itself. Because the DataSet contains all of the data that has been retrieved, you have more options in the way you can process the data. You can randomly choose records from within the DataSet and update/insert/delete records at will. You can also manipulate relational data as XML. This flexibility provides impressive functionality for any application, but comes with a high cost in memory consumption. In addition to keeping the entire result set in memory, the DataSet maintains both the original and the changed data, which leads to even higher memory usage. Do not use DataSets with very large result sets as the scalability of the application will be drastically reduced.