Thursday, January 31, 2008

Seattle Code Camp: Kick Your Hash

This was Wayne Berry's presentation about real-world crypto coding for web sites. The presentation was identical to his asp.net user group presentation. He stayed calm with 15 minutes of Digipen equipment not working and two room switches. But it was a great presentation and the level of detail and code was just right. He said he will post the presentation here at some point.

Wednesday, January 30, 2008

Seattle Code Camp: Advanced Query and Modeling Capabilities with Entity Framework

This presentation was given by Zlatko Michailov & Asad Khan, PMs, Microsoft ADO.NET. The best thing said in the entire presentation was that if your model is well built you shouldn't have to do any group bys or joins. Drink the kool-aid, swallow the pill, enjoy that illusion in a real-world situation. Especially some piece of $%^@ database that is mission critical and the data is 10 years old, not normalized, and some one else's baby. But if you are going to dream, dream big, right?

Their blogs can be found at: http://blogs.msdn.com/esql/. E for entity. Why be normal? right?

 

 

Tuesday, January 29, 2008

Seattle Code Camp: Top Open Source .NET Tools

Rod Paddack gave this session wearing a great geek shirt. His enthusiasm for open source was reciprocated by many in the audience. Here is the list:

Mentions during session included http://code.google.com/

What are your top tools?

 

Did Someone Forget A WHERE Clause?

Charter Communications officials believe a software error during routine maintenance caused the company to delete the contents of 14,000 customer e-mail accounts.

http://www.foxnews.com/story/0,2933,325338,00.html

I am glad today that I didn't do this and force my company to give a $50 credit to each customer.  Ouch.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Monday, January 28, 2008

Seattle Code Camp: Entity Framework Essentials

From https://seattle.codecamp.us/ 

Jonathan Carter, Microsoft Developer Evangelist, gave an introductory talk about the Entity Framework which has just had a Community Preview release. It is basically a middle layer framework driven by Domain Driven Design for creating and extending objects on top of a data source. The data source presented was SQL Server but you could imagine all sorts of layers. There are two parts, the Entity Model and the framework for asp.net. A simple but nowhere complete comparison could be drawn to CodeSmith. Open Visual Studio, create a "file". You are asked for a data source and data objects to include. The framework displays an Entity Relationship diagram which you can dink with to create the objects the way they will work for the upstream code and not the downstream DB.

While the presentation was a tad buggy, the framework looks like it is going someplace cool.

The best part was the intellisense to your objects you just created via the framework as well as the underlying data. This was best represented by a URI demonstation to get at the data - similar to a web service test page. Type in your URI for an object called customer with a customerid of 23 to get the Title of the customer: http://server/page.x?customer(23)/Title/ displays the result.

 

Community Preview Download http://www.microsoft.com/downloads/info.aspx?na=47&p=3&SrcDisplayLang=en&SrcCategoryId=&SrcFamilyId=e9ba57aa-2a27-4658-ad04-4380a2df836c&u=details.aspx%3ffamilyid%3dD8AE4404-8E05-41FC-94C8-C73D9E238F82%26displaylang%3den

ADO.NET Team Blog http://www.microsoft.com/downloads/info.aspx?na=40&p=1&SrcDisplayLang=en&SrcCategoryId=&SrcFamilyId=d8ae4404-8e05-41fc-94c8-c73d9e238f82&u=http%3a%2f%2fblogs.msdn.com%2fadonet%2f

Sunday, January 27, 2008

Seattle Code Camp 2008 at Digipen

Wayne, Rusty, Andy, and I went to code camp yesterday. The speakers were good, and there was a lot of code. I focused on the asp.net and core .net sessions. I attended two talks on Entity Framework, one on top 10 open source .net tools, one on crypography given by Wayne, and one on xUnit. By far the most interesting one was the xUnit discussion with it's dev team.

I'll give sessions reviews and related links in the following days.

 

Friday, January 25, 2008

The Beauty of LINQ

I was recently working with an RDP settings file and its myriad of settings and corresponding lines. I couldn’t find what I needed so I thought it would be nice to sort the lines. I am sure there are utilities out there that can quickly sort a bunch of text lines but like most programmers, I thought it best that I develop my own solution. So I fired up VS and created a new Windows Forms project, added a standard TextBox and Button control to my form and wired up the following OnClick event:

private void ButtonSort_Click(object sender, EventArgs e)

{

    TextBoxMain.Lines = TextBoxMain.Lines

        .OrderBy(s => s)

        .ToArray();

}

Just too simple. Man I love LINQ!

What is {6230289B-5BEE-409e-932A-2F01FA407A92}?

I have been adding {6230289B-5BEE-409e-932A-2F01FA407A92} at the bottom of my posts.  What posts you ask?  Well every post I am doing on the internet.  MSDN Managed Newsgroup forms, woodworking forums, and this blog are just some of the places.  Why you ask?  Well I want to be able to find all my posts that are unique to me.  It just so happens I share my name with several other people on the Internet so I wanted a unique name that was anonymous that would find only my stuff.  I will be adding to my BIOs when I write articles, and my web sites.  This way I can go to Google and search for my GUID and find everthing on the Internet that I have done.  You can do the same, just generate yourself a GUID at: http://www.guidgen.com/ and get started.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

Seattle Code Camp

Will be presenting at the Seattle Code Camp https://seattle.codecamp.us/ this Saturday.  My talk is entitled "Kick Your Hash" and I will attempt to bridge the cryptography gap between code and theory by showing SQL Server and .NET code, real life examples, and practical correct uses for Hashing.

Example 1:

SELECT HashBytes('MD5','password')

SELECT HashBytes('MD5',CONVERT(varchar(max),'password'))

SELECT HashBytes('MD5',CONVERT(nvarchar(max),'password'))

Example 2a:

ALTER PROC CheckLogin
@Login varchar(50),
@Password varchar(50),
@Valid bit OUTPUT
AS

SET NOCOUNT ON

SELECT *
FROM [User]
WHERE @Login = [User].[Login] AND [User].Hash = 
    HashBytes('MD5',CONVERT(varchar(max),[User].Prefix) + @Password)

IF (@@ROWCOUNT>0)
    SET @Valid = 1
ELSE 
    SET @Valid = 0

Example 2b:

CREATE TABLE [dbo].[User](
    [UserId] [uniqueidentifier] NOT NULL CONSTRAINT [DF_User_UserId]  DEFAULT (newid()),
    [Login] [varchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
    [Hash] [varbinary](16) NOT NULL,
    [Prefix] [uniqueidentifier] NOT NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED 
(
    [UserId] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Example 2c:

DECLARE @Prefix uniqueidentifier
SET @Prefix = NewId()

INSERT INTO [User]
(
    [Login],
    Hash,
    Prefix )
VALUES(
    'wayne',
    HashBytes('MD5',CONVERT(varchar(max),@Prefix) + 'password'),
    @Prefix)

Example 3:

CREATE PROC ChangePassword
@Login varchar(50),
@OldPassword varchar(50),
@NewPassword varchar(50)
AS

UPDATE [User]
SET Hash = HashBytes('MD5',CONVERT(varchar(max),[User].Prefix) + @NewPassword)
WHERE @Login = [User].[Login] AND [User].Hash = 
    HashBytes('MD5',CONVERT(varchar(max),[User].Prefix) + @OldPassword)

Example 4a:

CREATE PROC AddData
@Data varbinary(max)
AS

INSERT INTO Data
(
    Data,
    Hash,
    [Size]
)
VALUES
(
    @Data,
    HashBytes('MD5',@Data),
    DATALENGTH(@Data)
)

Example 4b:

CREATE PROC FindData
@Data varbinary(max),
@Id uniqueidentifier OUTPUT
AS

DECLARE @Hash varbinary(16)
SET @Hash = HashBytes('MD5',@Data)

DECLARE @Length bigint
SET @Length = DATALENGTH(@Data)

SELECT @Id = DataId
FROM Data
WHERE @Hash = Hash AND @Length = Size
{6230289B-5BEE-409e-932A-2F01FA407A92}
 

Wednesday, January 23, 2008

When Is null not true?

In C# we can have nullable types, like this:

Boolean? isValid;

Which means that isValid can be true, null, or false.  It is like a three way switch.  I use it to represent a bit field in SQL Server that can have a null value.  For example I might have this table:

CREATE TABLE Account (IsValid bit)

Which creates me a table with a bit column that can be NULL.  I usually don't like to do this -- in fact I never do, however I am working with some people that don't bother to check the NOT NULL when they use the designer so I have to deal with it in my C# code.  So I ask the table designer what NULL means in the IsValid coulmn and he tells me it means false (not valid).

So I query the database and set the result to isValid, in the C# class above.  So now I need to check to see if the account is valid.  It might seem like this would work:

if (isValid) {...}

However, that throws a compiler error, becuase you can't have Nullable type default expression.  So I have to do this:

if (isValid == true) { }

Notice that the second statement is really saying that the expresion fails if the IsValid is false or null.  This is also the same but weak:

If ((isValid!=null) && (((Boolean)isValid)==true)) { }

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

#1 Faster Coding

I was reading this article from a http://www.digg.com link (sorry I lost the link to the article) about how to be a faster developer and at the top of the list is becoming very good at your editor.  The author pointed out that the hot keys (the ability to navigate and execute commands without using your mouse) where essential.  I agree with him, the more you have to move your mouse the less you can type and it is a real waste of time going between the mouse and the keyboard.  However, he was ranting about EMACS and of course the Windows programmer's editor of choice is Visual Studio.

My favorite hot keys right now in Visual Studio:

Ctrl K-D : To reformat the code.  Type whatever I want, not tabs, no enter. Ctrl K-D and it is formatted correctly.

Ctrl M-O : To collapse all the regions.  Finish a bug fix, Ctrl M-O to collapse, Run Unit Test, Handle Exception in Code (automatically expands) and ignore all the collapsed code.

Ctrl F : For Quick Find.  I use find so much -- just have to hot key.

Ctrl-Atl-F : For Find in Files.

Ctrl H : For Quick Replace

Ctrl-Atl H: For Replace in Files.

Home / Ctrl-Shift-End : For Selecting All.  This works in most Microsoft products.

Ctrl -Arrows : For moving by expression as compared to the arrows which move my character.  Walk the XML quickly scanning for what I want to edit.  Press the control key to highlight (while Ctrl-Arrowing), and then delete to remove that whole word.

Ctrl-J: Reactivate Intellisense.  I use this all the time, cut and paste some text into a case sensitive language like C#, Ctrl-J to find the class with the same name -- different case, and press Enter to select it from the Intellisense list.

/// : For adding comments to method and properties. Thanks Andy.

However, this one: Ctrl-Tab is awesome.  I read about it in this MSDN Blog: http://blogs.msdn.com/vbteam/archive/2008/01/09/3-did-you-know-ctrl-tab-to-navigate-windows-in-vs-lisa-feigenbaum.aspx.  It allows you to select any open window (much like Atl-Tab in Windows).

{6230289B-5BEE-409e-932A-2F01FA407A92}

Tuesday, January 22, 2008

Yet Another Interview Question

"When you program by yourself do you use source control?"

What I want to hear is that they use source control.  Source control -- even by yourself -- is an important tool that helps you backtrack out of coding tangents that fail.  Hosted on another server it is a valuable form of backup off your own box.  It also shows that the person has programmed in a shop where source control was enforced (rightfully so) and understand how it beneficial it is.

 

Saturday, January 19, 2008

Clearing My Inbox

Another programming tip in the article I read was to keep a task list for the work left in your programming project and work off it.  Most projects are so large that you can't keep track of all the loose ends.  I have never had trouble keeping track of the loose ends of a project when my head is in it -- however I know the day is coming soon.

Being a former Microsoft employee and Microsoft being an email culture (at least when I was there in 1997), I use my Inbox to keep track of all my tasks.  Ten years ago it was around 200 emails -- all that needed action.   I was alright with that since I got 100-400 emails a day I was keeping them under 200 and everything was good.  About 5 years ago the inbox topped 300 emails and I was still alright with that -- keeping them paired down and knowing I would never clear it completely -- remember all 300 required action.  At the end of 2007 I had 400 emails in the inbox and I knew there was a problem -- so I set about clearing my inbox.  I have only cleared my inbox once in the past.

I just got done today.  It took me 40 hours to clear all the emails, about 10 emails and hour.  40 hours performing the email task, replying or just making tough decisions and deleting them. 

My typical daily process: my inbox usually has newest at the top and everyday I work from the top down.  Most of the time I reach the last email I didn't take action on yesterday and then work ten or so farther down.  However most of those require a reply from someone and I get discourage.  On Monday I try to follow-up or work all of last weeks emails and all of Mondays. 

So here is my tip list for clearing your inbox:

  1. Start at the oldest email and work up.  The newer emails are ones that you are waiting for a reply.  The oldest ones (in my case a year old) are ones you are never getting a reply on, i.e. easier to delete.
  2. If you have a customer question you didn't answer within a month -- they are no longer a customer, delete the email.
  3. Delete all the emails forward by your mother-in-law which you didn't think of something witty to reply back.  Following up after 6-months will not earn you any points.
  4. Sort by subject -- sometimes there is a ten email thread that you already handled which you can delete.  It also allows you to easily scan for the same types of emails which you missed deleting the first time they came by.  It also breaks the reply mental block
  5. Delete the email you sent to yourself with articles you wanted to read -- you just don't have time obviously.
  6. If you really can't decide to delete it -- leave it for the end -- the more you do this the more you want to delete it.
  7. Finish the small tasks you meant to do however put off -- they are small will not take you long, and you can delete that task email.
  8. It is never to late to reply to a friend and go to lunch.  Reply with dates that work and delete -- you don't have to handle that task until they write back.
  9. Make well named folder and move the email.  If it is a reference article, customer feedback, or FAX you need to save get it organized.

Good Luck

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

 

Friday, January 18, 2008

Control.ClientID Extremely Useful for Creating Client-Side Functionality

The ClientID property is my favorite property this week and will definitely reshape how I write asynchronous functionality in the future.  I learned about this while adding some functionality to a client's site earlier this week.  The original site was created off-shore and people like me are the ones who get to take care of it.  It's been fun so far and had I not been working on this site this week I would've totally overlooked this wonderful property.

First off, ClientID is a readonly property (as it should be!) that does nothing more than get you the id of the control that is rendered.  Take the following rendered RequiredFieldValidator.

<span id="datalistContent_ctl05_requiredDescription" style="color:Red;visibility:hidden;">I saw what you did there.</span> 

Not quite the same as my original "requiredDescription" ID set in the .aspx.  When this control was processed this original ID was appended to the UniqueID created for this control. ASP.NET does this to make sure that there are unique id's for controls and this process is especially prevalent in Repeaters, DataLists, and GridViews.  Most of you probably knew that.  As you can tell from the HTML above my "requiredDescription" was in my DataList called "datalistContent" in the 5th generated table cell ("ctl05").

So how will this help me with asynchronous programming, cleaner UI's, etc, etc?  If you're familiar with the ItemDataBound event of the Repeater, DataList, Gridview controls then you can probably see why. Let's say I have a DataList that contains a TextBox and a HyperLink.  The Description property of my object is displayed in a multi-line textbox with a CSS style attribute (see below) that makes it appear to be normal text (i.e. can't see the border, scrollbars, etc..).  The link that reads "Change Description" should enable the already-disabled textbox, hide the link, apply a TextBox-like style, and focus the cursor on this newly-enabled TextBox.  After editing the text the onblur event triggers a client-side function that disables the textbox and adds the disabled, plain-ole-text feeling CSS, then display the link again for changing the description.  It's actually easier than it sounds (demo below). Take the following example (ps. If this were production code I would use e.Item.FindControl("string") as Foo and check for null before adding attributes):

protected void ItemDataBound(object sender, DataListItemEventArgs e)
{
   TextBox text = (TextBox) e.Item.FindControl("textDescription");
   HtmlAnchor link = (HtmlAnchor) e.Item.FindControl("linkChangeDescription");

   text.Attributes.Add("style", "border: none 0px #fff; overflow: hidden; width: 250px;");   
   text.Attributes.Add("onblur", string.Format("Blur('{0}', '{1}');", text.ClientID, link.ClientID));   
   link.Attributes.Add("onclick", string.Format("Edit('{0}', '{1}');", text.ClientID, link.ClientID));
}

Those JavaScript functions consist of a whopping 6 lines so I won't paste here.  If you are curious, leave a comment and I will send you a download link to AspNetAjaxLolSike.csproj. Quick tangent, if you are into Internet memes check out LOLCode.  Chances are you you have been on the receiving end of an image such as this or this.  Think of a programming language with that vernacular. Try-Catch = Hai-KThnxBye.  ANYWAY, that's where the LolSike project name came from as I spent a good 2-3 hours laughing uncontrollably at the user-submitted codebase at LOLCode.  Some guys at Microsoft actually created a compiler for it, which I have yet to track down.

Anyway, that code will render as follows with the appropriate client-side id of the ASP.NET Control from our code-behind:

<a href="#" id="datalistContent_ctl04_linkChangeDescription" onclick="Edit('datalistContent_ctl04_textDescription', 'datalistContent_ctl04_linkChangeDescription');">Change Description</a><br />
<textarea name="datalistContent$ctl04$textDescription" rows="2" cols="20" id="datalistContent_ctl04_textDescription" disabled="disabled" class="hidden" onblur="Blur('datalistContent_ctl04_textDescription', 'datalistContent_ctl04_linkChangeDescription');" style="border: none 0px #fff; overflow: hidden; width: 250px;">Hai 5</textarea><br /> 

Moving on, I came across exploring this functionality after getting tired of finding solutions requiring a Postback (i.e. asp:LinkButton control).  This, as far as I'm concerned: sucks.  The next best option was to wrap the datalist in an UpdatePanel.  That is wrong on so many levels.  My general attitude towards the UpdatePanel is that it generally sucks 80% - 90% of the time.  80% - 90% may seem like a large number and I will explain my feelings.  The UpdatePanel is a slippery slope of bad practices (imho) for those that want to start with asynchronous technologies.  I say this because most of those that use it (80% - 90%) don't know WHEN to use it.  I can't tell you how many times I've seen someone wrap a DataGrid of 100+ records (with update, add, delete functionality) in an UpdatePanel.  Set up a project in Visual Studio that has a textbox and button in an update panel.  On "postback" set the textbox to the current date time (DateTime.Now) and use Firebug or Fiddler to check out the size of the response.  It will probaby surprise you.  I'm not saying that if you use an UpdatePanel you suck at AJAX.  By no means do I consider myself the authority figure on asynchronous programming.

You can add a button to this (hidden if there are no records in your IEnumerable<T>) to give your application "Update" functionality.  Your button OnClick event would then check all the DataListItem's in the DataList, cast your DataListItem.Item.DataItem to type T, interpret the data, and process accordingly by way of some class library. Easy.

Notice that there are no postbacks when I edit the descriptions in my DataList.

ClientID Demo

When I get some more time I will explore the avenue of asynchronous GridView paging.  I have never used the GridView so I'll have to be REALLY motivated to try.  I only used this in the DataList because I needed to display columns based on user input and treated the DataList as a Repeater with Columns functionality.

Source Control Pet Peeves

There is no reason, NONE WHATSOEVER, for updating SVN (or any other source code repository) with code that does not compile.  There are 2 rules for version control that are both #1:

1. Check code in frequently
1. Don't check projects in unless they compile

Some argue that this isn't a good practice (1 #2 above) but let me explain.  Let's say you are working on a distributed team and there are 3 people working on a project.  Team members 1 & 2 are working on a class library for a web project.  They figure they are done for the day and check in the code that they worked on. Team member 3 (me) wants to check out this class library when working on a new & unrelated project.

I add this library to my project, do my thing, build. WTF? 57 Errors and 2 warnings.  I should see 0 Errors and 2 warnings.  Warnings are usually harmless and a lot that I have seen lately stem from converting 1.x websites to 2.0, 3.5 projects and usually have something to do with obsolete code (which is still compatibile).  So now there are a couple of problems.  First of all, I have to get my project to compile, which means fixing YOUR code.  Then, I have to check the code in that I fixed. Then, I  have to recompile my project and continue to try and be in a good mood while I am pissed that I had to waste anywhere from 5 minutes to sometimes an hour or more (then I get really pissed!).

"Well I didn't want to write the method that reflects my object and creates an instance of T."

You don't have to. This will do:

public static T GetRecord<T>(List<IDbDataParameter> parameters, string commandText)
{
   return Activator.CreateInstance<T>();

Or the following if you don't want the possibility of bugs slipping through the cracks due to incomplete data (which will never happen if you implement some sort of Unit Testing Framework but that is a whole other topic).

public static T GetRecord<T>(List<IDbDataParameter> parameters, string commandText)
{
   throw new NotImplementedException("Not done yet");

Another beef is when people add references to .DLL's that will break the build.  Adding .DLL references is commonplace, especially if you use 3rd party solutions or existing class libraries.  This can break builds also.  I learned this after making a mistake once where I downloaded a control to my desktop and added the reference from there.  The next person to check out my code didn't have that assembly on his desktop and it broke his build.  A workaround for this is to have a Dependencies folder within a project that is the central location for all these add-on assemblies.  That way when a developer adds a reference the next person who checks the code out (or updates their existing codebase) will be able to hit the ground running.

Again, code doesn't have to be bug-free or work like it's supposed to.  As long as it compiles when I update my code I am happy.  It is impossible to check in code that works as it should every day (i.e. conversion projects).

Thursday, January 17, 2008

Side by Side Databases

Let's say you forgot a WHERE clause and want to restore your backup database to recover the lost data.  However, you don't want to override the data that has accumulated since the last back-up.  What you need to do is restore the backup along side the newer database.  Here is how to do it:

RESTORE DATABASE backup
   FROM 'C:\temp\lastbackup.bak'
   WITH MOVE 'mydb_Data' TO 'C:\MySQLServer\backupdb.mdf',
   MOVE 'mydb_Log' TO 'C:\MySQLServer\backupdb.ldf';

This statement tells the SQL server to create a database called "backup", from the lastbackup.bak file and not to use the files stored in the back-up, but instead use: backupdb.mdf and backupdb.ldf.  Unless you remap your backup files, the RESTORE will try to override the old files that are in use by the newer database -- which will cause a SQL Server error (not data loss).


{6230289B-5BEE-409e-932A-2F01FA407A92}

System.ArgumentException: An item with the same key has already been added

Intermitently my code was getting this Exception: "System.ArgumentException: An item with the same key has already been added."  The code looked like this:

if (!_roleTypeNameDict.ContainsKey(roleTypeName))
_roleTypeNameDict.Add(roleTypeName, ...)

Since I have done a lot of C++ programming right away I realized that I had a threading issue, however the question was why? It just so happens this was a static method, calling a static property, which means that more then one thread might be accessing _roleTypeNameDict at a time:

private static Dictionary<String, RoleTypes> _roleTypeNameDict
   = new Dictionary<string, RoleTypes>();

public static RoleTypes FindCachedRoleTypesFromRoleTypeName(String roleTypeName)
{

if (!_roleTypeNameDict.ContainsKey(roleTypeName))
       _roleTypeNameDict.Add(roleTypeName, ...);
...
}

To solve the issue you need to create a lock to protect the check to add from the add like this:

private static Dictionary<String, RoleTypes> _roleTypeNameDict
   = new Dictionary<string, RoleTypes>();
private
static object _roleTypeNameDictLock = new object(); public static RoleTypes FindCachedRoleTypesFromRoleTypeName(String roleTypeName) {    lock (_roleTypeNameDictLock) {    if (!_roleTypeNameDict.ContainsKey(roleTypeName))       _roleTypeNameDict.Add(roleTypeName, ...); }
   ...
}

However, you can make the code slightly faster if you assume that the ContainKey is less expense then the lock from a performance stand point:

private static Dictionary<String, RoleTypes> _roleTypeNameDict
   = new Dictionary<string, RoleTypes>();
private static object _roleTypeNameDictLock = new object();

public static RoleTypes FindCachedRoleTypesFromRoleTypeName(String roleTypeName)
{
   if (!_roleTypeNameDict.ContainsKey(roleTypeName))
   {
      lock (_roleTypeNameDictLock)
      {
         if (!_roleTypeNameDict.ContainsKey(roleTypeName))
            _roleTypeNameDict.Add(roleTypeName, ...);
      }
   }
   ...
}

What we are doing here is checking to see if we need to add, then locking, then checking again, then adding.  This prevents us from locking if we don't need to add-- the majoirty of the cases, however it also prevents two threads from trying to add at the same time.

I was just thinking the other day that threading, caching, and memory management skills where still needed in .NET even though the Microsoft PR machines is making C# out to be much easier then C++.  At the same time VBScript programmers in classic ASP don't have to worry about threading issues.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 
 

Wednesday, January 16, 2008

TreeView Control with Ajax Slide Show

Just finished a little app to have a treeview control the file system navigation for images to be displayed in the AJAX Slide Show provided in the Microsoft AJAX Control toolkit. A www.15seconds.com articles about the application will be posted soon.

Just so you know...

Detaching a database in SQL Server doesn't delete the files (.ldf, .mdf, .ndf) where the data is stored.  Deleting a database is different then detaching a database.  Detaching allows you to move the files and reattach them to a different SQL Server.  However, once you detach a database it is not available to query.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Tuesday, January 15, 2008

Interview Question #3

My brother called, he had forgotten a WHERE clause and had lost some data.  I felt really bad for him -- the kind of sinking feeling you get when someone you know has a death in the family.  I can relate -- I have forgotten a few WHERE clauses in the past couple of years.  Right after he called I checked my database backups to make sure they where still running every night.

This reminded me of one of my favorite interview questions: "Tell me about the last time you forgot a WHERE clause?"  I am looking for that sinking recognition that takes place when someone knows the question and can relate.  And if they have never forgotten a WHERE clause -- I just know they haven't programmed much T-SQL, cause we all do it from time to time.  I also want to hear how they recovered their data and what they are doing differently to prevent the problem.  A developer I know at work always writes the WHERE clause before he writes the DELETE or UPDATE line just to prevent the aforementioned.

Maybe SQL Management tool should have an optional warning that makes you confirm that you want to run a DELETE or UPDATE when there is no WHERE clause?

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

Friday, January 11, 2008

Use T-SQL's NULLIF To Fix Divide By Zero Errors

Lately I have doing a lot of SSRS and overall SQL work for a project.  In returning some data to process server-side my data retrieval method was returning null* which means that an exception was thrown. I did a little digging around and then decided to execute the stored procedure manually (i.e. Management Studio).  After debugging in Visual Studio and seeing what the values were and that they were in fact getting passed to the stored procedure I used the same signature to execute the proc in Management Studio.  Hmm, no dice.   My error message was of a "Divide-By-Zero" fashion.  This is the first time that I have ever seen this.  A little reading on the subject and I come to find out that the field used as the denominator allowed nulls.

Enter NULLIF. This is what saved the day.  This function will compare two values and return a null value if the expressions are equal.  For example, take the following dummy stored procedure.

CREATE Procedure SharesCalculateSharePrice
(
   
@shareId int,
   
@numberOfUnits decimal
)

AS

DECLARE @totalPrice decimal

SET @totalPrice = ( SELECT TotalPrice FROM Shares WHERE ShareId = @shareId )
DECLARE @returnValue decimal

SET @returnValue = ( @numberOfUnits / @totalPrice )
SELECT @returnValue 

Pretty basic. I'm selecting the total price from a table and using as the denominator.  I pass in number of units. To get price per unit (share price) I divide one by the other. What if the @totalPrice is 0? Then I get the dreaded Divide-By-Zero error.  Using NULLIF, we can make a trivial aleration to the above procedure and return a NULL value instead.

CREATE Procedure SharesCalculateSharePrice
(
   
@shareId int,
   
@numberOfUnits decimal
)

AS

DECLARE @totalPrice decimal

SET @totalPrice = ( SELECT SUM(TotalPrice) FROM Shares WHERE ShareId = @shareId )
DECLARE @returnValue decimal

SET @returnValue = ( @numberOfUnits / NULLIF(@totalPrice, 0) )
SELECT @returnValue 

Easy. If @totalPrice is 0 we will substitute with a null value.  This way the returnValue will be NULL and we can process accordingly from our .NET application.

public static object ExecuteScalar(List<IDbDataParameter> parameters, string commandText)
{
   using (DBManager manager = new DBManager(_provider, _connectionString))
   {
      manager.Open();
      manager.CreateParameters(parameters.Count);

      for (int i = 0; i < parameters.Count; ++i)
         manager.AddParameters(i, parameters[i].ParameterName, parameters[i].Value);

      object returnValue = manager.ExecuteScalar(CommandType.StoredProcedure, commandText);

      return returnValue == DBNull.Value || returnValue == null ? -1 : returnValue;
   }

There could be even more useful ways to use NULLIF but for me this has worked out fine.

Generic Session Wrapper Class for Session Object Maintenance

I've been reading a couple of renditions of this SessionWrapper class via DotNetKicks over the past couple of days.  While I must admit that this code isn't 100% original, I can say that I have given it a more generic feel and added a little bit of functionality.  With my implementation you can not only use any class, you can specify a name for the session object.  That way if you want to store say the Account and Order objects in Session you could use the same method without creating a wrapper for each type.

using System.Web;

namespace NamespaceNameGoesHere
{
   public class Session<T> where T: class
   
{
      private string _name = string.Empty;

      public string Name
      {
         get { return _name; }
         set { _name = value; }
      }

      public T Object
      {
         get { return HttpContext.Current.Session[Name] as T ?? null; }
         set { HttpContext.Current.Session[Name] = value; }
      }

      public Session(string name)
      {
         _name = name;
      }

      public Session()
      {
      }
   }
}

Pretty straight-forward. Here's how you would use it from a Page_Load for example:

Session<Foo> session = new Session<Foo>("Foo");

if (session.Object == null)
   session.Object = new Foo(-1, "hai guyz!");
else
{
   Foo foo = session.Object;

Not cutting-edge but could be useful if you want a type-safe session state.

Converting Legacy Tables From Int Primary Keys To UniqueIdentifiers

If you have some legacy tables you where you want to convert from having a primary key of int to a primary key of uniqueidentifier, you need to do a lot of work.  Here are the steps:

1) Drop all forigen keys contraints that points to the table being modified.

2) Drop all views that reference the table being modified.

3) Drop all indexes that use the primary key or any forigen key column that points to the table being modified.

4) Rename all the old forigen key column that points to the table being modified, so that we can add a new column with the original name of type uniqueidentifier.

5) Drop the primary key contraints on the table being modified.

6) Add a new forigen key column to all tables where there was a forigen key column that points to the table being modified of the same name with a type of uniqueidentifier.  Make then NULL

7) Rename the primary key of the table being modified -- the int column.

8) Add a new column with the original primary key name of type of uniqueidentifier.

9) Fill all rows with the new primary key column using the function NewId()

10) Update all the new forigen key column with the new primary key using the old forigen key column bound to the old primary key on the new table.

11) Alter all the new forigen key column to NOT NULL where the original forigen key column was NULL.

12) Rebuild all indexes, including the primary key index on the new columns

13) Rebuild all forigen keys.

14) Rebuild all views.

Good Luck

{6230289B-5BEE-409e-932A-2F01FA407A92}

Wednesday, January 9, 2008

Starting to Use GUIDS in SQL

When you start to use GUIDs (uniqueidentifiers) as primary keys in T-SQL one of the first questions is how to replace @@IDENITY in your primary key column.  A typical table with int as a primary key might look like this:

CREATE T1(ID int PRIMARY KEY IDENTITY, Name varchar(50))

When you insert into this table and want the primary key of the row that you inserted you typically do this:

DECLARE @ID int

INSERT INTO T1 (Name) values ('Tom Smith')

SET @ID = @@IDENTITY

However, when you use uniqueidentifiers as primary keys you don't declare them as IDENTITY, here is how you would build this table:

CREATE T1(ID uniqueidentifier PRIMARY KEY , Name varchar(50))

And here is what the INSERT looks like:

DECLARE @Id uniqueidentifier

SET @Id = NewId()

INSERT INTO T1 (ID, Name) VALUES (@Id, 'Tom Smith')

When using uniqueidentifiers you create them ahead of the insertion and SQL Server doesn't keep track of the process for you.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Tuesday, January 8, 2008

I Just Finished My First VB.NET Project in Over 2 Years

I just finished my first VB.NET project and it was pretty interesting. Some of you might be wondering why I did a project in VB.NET.  There are actually 3 reasons:

  1. Client's money is still green
  2. Site was the first .NET application by someone straight out of classic ASP
  3. Client won't pay to upgrade to C#

Now that we've cleared that up, I'd like to say how awkward it was.  First of all, it took me probably twice as long to write this as it would if it were in C#.  This is due to my not knowing the in's and out's of VB.NET 2.0 and not necessarily something I can blame on VB.  While there are some great additions to VB.NET such as Generics (even though the syntax isn't very intuitive), the Using construct (about time!) there is one feature that is still not there that I use day-to-day when writing applications in C#. I am talking about collapsible regions within methods.

Take the following code example:

Protected Sub ButtonClick(ByVal sender As Object, ByVal e As EventArgs)

   
Dim button As Button = sender

   If Not button Is Nothing Then

      Dim stringVariable As String = String.Empty

      Select Case button.ID

         Case "foo"
            stringVariable = "foo"

         Case "bar"
            stringVariable = "bar"

         Case "asdf"
            stringVariable = "bar"

         Case "qwert"
            stringVariable = "qwert"

      End Select

   End If

   If Not String.IsNullOrEmpty(stringVariable) Then
      
DataAccessOrBLL.DoSomethingCoolWithThisString(stringVariable)
   End If

End Sub

Given the opportunity to start from scratch I like to setup my event handlers like this.  One method that handles everything I need. To me, it makes for cleaner code and much easier to read.  If something goes wrong with an event handler, I can look in one place. In a C# environment I would setup a collapsible region like so:

Protected Sub ButtonClick(ByVal sender As Object, ByVal e As EventArgs)

   
Dim button As Button = sender

   If Not button Is Nothing Then

      Dim stringVariable As String = String.Empty

#Region "button switch"

      Select Case button.ID

         Case "foo"
            stringVariable = "foo"

         Case "bar"
            stringVariable = "bar"

         Case "asdf"
            stringVariable = "bar"

         Case "qwert"
            stringVariable = "qwert"

      End Select

#End Region "button switch" 'C# would actually be #endregion

   End If

   If Not String.IsNullOrEmpty(stringVariable) Then
      
DataAccessOrBLL.DoSomethingCoolWithThisString(stringVariable)
   End If

End Sub

The reason I would do that is because when I am writing code I view monitor space as real estate. On each screen I like to see as much code as possible. In the example above I could add a collapsible region outside of this sub routine but that wouldn't work (at least for me).  In scanning through the code I'd still want to see the section where I call DoSomethingCoolWithThisString because it's an action item so to speak.  In scanning this code-behind I could see that in my handler method I am setting a string based on the button that was clicked and then calling that method in my DAL / BLL.  Even though the code segment is collapsed I can still see what it is doing and if I need to fix that section (i.e. add a case for a new button added to the page) I could just uncollapse that region.

Quick tangent: Is it just me or does Intellisense seem a little slow and different than C#?  Also, what's up with not being able to hightlight a segment of code, right-click, 'Surround With' when in the VB.NET environment?  The 'Surround With' functionality is great for using constructs and try-catch blocks amongst other things.

At the end of the day it's all .NET and I'm kind of glad I came across this project.  As a software developer in the consulting world it's nice to be dextrous when it comes to writing / reading code but I'm still partial to C#.

T-SQL Performance With INNER JOINs

Lets take a quick look at INNER JOINs in T-SQL.  This select statement is a very typical:

SELECT *
FROM Products
   INNER JOIN Category ON Products.CategoryId = Category.CategoryId
WHERE Products.AccountId = @AccountId

However, it can be rewritten to be much faster:

SELECT *
FROM Category
   INNER ON Products JOIN Products.CategoryId = Category.CategoryId AND
      Products.AccountId = @AccountId

Here is why: In the first statement all the rows in the products table are being joined to all the rows in the category table, producing a bigger table, that is then walked to find the correct account.  This might make a very large table after the join if there are many accounts and the category table is very wide.  SQL Server has to deal with this large in query table being produced.  However, in the second statement only the products that are in the required account are joined to the category table -- significantly reducing the join. 

It is important to note you can only reduce the size of the join on the tables you are joining too (not the first table).  So you might need to rotate the first table.  In the case above the category table is likely smaller then the products table and doesn't have accounts so I rotated it up.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

 

Monday, January 7, 2008

Another Interview Question

One question I ask when interviewing is what types of T-SQL statements are the worst for performance, I am looking for answers like the below (not in any order):

  • Cursors
  • IN clauses
  • Large INNER JOINs

What this tells me about the person is that they are conscience of the code impact they have on the server.  Someone that doesn't know the answer will write anything that works just to get their job done -- which means that I will later have to clean-up their stuff.

{6230289B-5BEE-409e-932A-2F01FA407A92}

Sunday, January 6, 2008

Removing Duplicate Rows In T-SQL

Been doing some interviewing lately and finding that people think they are really good at T-SQL (claiming they are a 6 out of 10), however almost none of them write their T-SQL by hand.  If you are using the WYSIWYG query builder you are a 3 out of 10, or less.  Here is one of my favorite interview problems that comes up in real life (my life) a lot.

Given a table like this:

CREATE T1 (ID int PRIMARY KEY, Name varchar(50))

That has duplicate rows in the name column, write a query to "clean" the duplicates leaving only on row per name.  So if "Tom Smith" shows up in two rows (ID: 2, and 4), the query would delete either rows with ID 2 or 4 and leave the other one.  My favorite answer is:

DELETE T1
WHERE NOT T1.ID IN (SELECT MIN(T1.ID) FROM T1 GROUP BY Name)

This includes an IN clause where is terrible for performance -- however the best solution I know.  Most people try it with a cursor which is much harder.

Note:  This is how you "clean" a table of duplicates before you add a unique index to the name column.  A typical scenario when you have a lookup table that has some extra data and you are normalizing the database.

{6230289B-5BEE-409e-932A-2F01FA407A92}

 

Saturday, January 5, 2008

MSDN Managed Newsgroups

MSDN Managed Newsgroups might be one of Microsoft's best kept secrets for development resources.  If you have an MSDN subscription you can post a development question on the Managed Newsgroups and a Microsoft support person will answer it within 24 hours.  For me this is an invaluable resource -- much easier then calling on the phone.  You can also post as many times as you like.  There are a few hoops to jump through to tie your MSDN subscription to your passport login, which take about 10-15 minutes to figure out.  If you don't have a MSDN subscription getting help is hit and miss - Sometimes you get a response and sometimes it is correct.

Too bad all their products are not supported this way.

http://msdn2.microsoft.com/en-us/subscriptions/aa974230.aspx

{6230289B-5BEE-409e-932A-2F01FA407A92}

Friday, January 4, 2008

TreeView.FindNode returns null when PathSeparator is not set

I'm writing a web app that connects a treeview control with a ajax slide show. Tons of feature creap but what is new.

I don't get a chance to program as often as I would like so when problems pop up like FindNode returning null on a valid ValuePath, I assume it's me, my programming, my install, my whatever.

I look at the docs, I look at sample code. I even look for other people having the problem but I don't see any solutions but others definitely having the problem. In one forum, the poster mentions that he figured out his path separator can't be a symbol in the valuepath. Hmmm. If you don't set the PathSeparator, it defaults to "/" which is the same thing as the directory structure I'm using in the valuepath. So problem is solved when I explicitly set the PathSeparator to "|".

-Dina

 

 

 

 

 

Hierarchical Structure

Still working on treeview with ajax slide show. I had to write 2 expandnode functions: one based on file system ("/dir/dir1/dir2") and one based on treeview with PathSeparator as "|" ("/dir/|/dir/dir1/|/dir/dir1/dir2/"). This is so that the currently selected node (ie directory) can be expanded and highlighted regardless if the web page is opening for first time, on postback, on querystring, etc.

It should be as easy as filling in a datatable-ish structure where the structure automatically resolved down the hierarchy based on a given path. But I can't figure out how to get two very similar structure into a single container without doing alot of work myself. If you know where I'm going wrong - let me know.

-Dina

 

 

Wednesday, January 2, 2008

SQL Server Hole #1

In my opinion SQL Server 2005 is full of holes, and my definition is functionality that is available doesn't span the whole gamete of the server.  For example, aggregates don't work with GUIDs (call uniqueidentifiers in SQL).  Here is non-working code that I would like to see work:

CREATE #Temp(Id uniqueidentifier, Name varchar(50))

SELECT MAX(Id)
FROM #Temp

DROP TABLE #Temp

Why doesn't this work?  GUIDs are just 128-bit numbers, they are all unique and one comes before the other, there should be a MAX and MIN.  This does work:

CREATE #Temp(Id uniqueidentifier, Name varchar(50)) 

SELECT MAX(CONVERT(varchar(41),Id))
FROM #Temp

DROP TABLE #Temp

However, I don't want the extra overhead of converting each GUID to a String.