Archive for the ‘ASP.NET’ Category.

ASP.NET MVC select tag does not work unless specifically closed

I found out after a bit of pulling my hair out today that if you want to display a dropdown menu via a select tag inside a .cshtml page in your ASP.NET MVC project, you had better close the tag with </select>, because if you rely on the self closing tag (think <select />), then your asp-items will get eaten, along with other miscellaneous things.

OK, you may have had a tough coach at some point growing up, but you have to let it go…

A co-worker found this nice little nugget in one of our sports web site applications:

Dim isAssHeadCoach As Boolean = Session("IsAssHeadCoach")

I hope it is meant to check for an assistant or associate head coach.

Compound comparison in a LINQ join statement

I’ve been doing pretty much iPhone only postings recently, so this might change it up a bit.

So I am trying to go into our web application’s C# code to make some changes to the administration area of the web site.  (This is usually the only place I feel comfortable making changes, as this is not an area that customers actually use.)  We have a page that uses a store procedure to pull data from our SQL Server database and presents it on the page.

I needed to get more information out of the database than the store procedure was giving me, and I didn’t feel like modifying the procedure and then trying to rebuild the DBML, so I decided to convert it to a LINQ statement and bind to that instead of binding to the results of the stored procedure.

These things never go as planned.  I took a similar LINQ statement that I found in the application, but it did not do exactly what I wanted to do.  Basically, the LINQ statement I found used a simple comparison.  I needed to check for two different things in my comparison, so after a bit of research and trial and error, here is what I came up with:

var p = (from ord in dc.orders
    join ordSt in dc.orderStatus on 
        new { ord.orderID, b = true } equals new { ordSt.orderID, b = ordSt.isDeleted }
    where ord.customerID == custID
    select
        new { ord.orderID, ordSt.deletionDate } );

I had to add the little “b = true” and “b = ordSt.isDeleted” parts because it would not let me use just the “true” in the comparison.  Ah, isn’t it great that LINQ is so simple?

Don’t try, don’t catch

Have you ever had a situation where all of those nested try/catch blocks just get in your way when trying to chase down a problem? I just hate that.

Luckily, in Visual Studio 2008 (and other versions, I am sure), there is a handy dandy way to disable all of the try/catch blocks when you run the application in debug mode from the IDE.  Just go to the Debug menu, select Exceptions, click the box under the Thrown column for Common Language Runtime Exceptions (or others if that is what you are looking for), and click OK.  Now when the code has a problem, you see it right away instead of trying to work backwards through nested try/catch blocks in different classes and modules.

Just don’t forget to put it back to the way it was when you are done. I am not a huge fan of try/catch blocks, but their normal use definitely has its place.

2010 Central Ohio Day of .NET

A co-worker and I attended the Central Ohio Day of .NET on June 5, 2010. There was quite a bit of good content at the conference, which is a real tribute to the organizers, volunteers, and presenters.

The highlights of my day were sitting in on Matt Casto’s regular expressions talk, Phil Japikse’s M-V-VM primer, discussing the etymology of the MongoDB project with Sam Corder (I still say it was named such after the character in Blazing Saddles), Michael Eaton’s talk on WPF, and Parag Joshi’s demonstration of XNA/Windows Phone 7 game development.

Control arrays in VB.NET

One of the things that I really liked (and used quite a bit) in the VB6 IDE was the ability to use the design surface to create a form with a bunch of controls with the same name as a control array. You would create the controls on the design page, give it the same name as another control, and the Index property would automatically be incremented. This would then let me use a loop to manipulate and examine these controls.

This functionality is missing in VB.NET, as I discovered when I tried to do my first .NET Compact Framework application way back when Visual Studio 2003 was shiny and new, and has continued to be missing from the feature set in VS2005 and VS2008.

Microsoft is not much help on this front. Their solution is to create the forms in code, as described in this article:

Not so helpful link (link redacted)

But I like using the design surface to create forms. A co-worker suggested we try to do a test in C# and tamper with the designer.cs file to create an array of controls in there, which worked OK. The big problems there were that the controls showed up on the design surface, but they could not be clicked and modified. Also, when we added a control to the form and saved it, all of the customizations we made to the designer file disappeared. (Oops.)

So instead, what I am now doing is creating my forms in the designer as before, with each control of the set having a different name with a number after it (such as cboName0, cboName1, etc.), referring to the index of the control in the array. At the top of the form’s class I have the arrays defined:

Dim cboName(10) as ComboBox
Dim lblNumber(10) as Label

Then, in the form load event, I am calling this subroutine:

Sub SetUpControlArrays()
 
    For Each cb In Me.Controls.OfType(Of ComboBox)()
        If cb.Name.Contains("cboName") Then
            cboName(CInt(cb.Name.Replace("cboName", ""))) = cb
        End If
    Next
 
    For Each lbl In Me.Controls.OfType(Of Label)()
        If lbl.Name.Contains("lblNumber") Then
            lblNumber(CInt(lbl.Name.Replace("lblNumber", ""))) = lbl
        End If
    Next
 
End Sub

Now I have the ability to address the controls in the same way that I used to do in VB6. The fact that I lived with this missing feature for about 6 years and just now figuring out a decent way around the problem pretty much guarantees that VS2010 will put the control arrays back in.

EDIT: At the request of a Strong Bad fan who shall remain nameless, I changed up the code above to be a bit more friendly. The previous code only extracted the rightmost 1 character from the name of the control on the design surface, which would not work if you had a control name such as cboName10.

Friends don’t let friends reinvent System.Security.Cryptography

A fellow coworker is upgrading one of our long time customer’s ASP.NET web site that was originally created in 2003, and all is going swimmingly. Alas, this project could not go gently into that good night.

He makes the web page and code changes, modifies the database, pushes all the changes up to the web site, and the site is working well. Customers are placing orders on the web site, order e-mails are being sent to the site owners with encrypted credit card information, and all are happy.

But there is always a fly in the ointment. All of a sudden, an order is placed on the web site, but when the site owner tries to run a decrypt on the credit card information in the e-mail, the decryption routine is reporting a failure. So naturally, we assume that we broke the code somehow, so we started to dive into the project to see what we did to destabilize it.

He asked for my opinions on this problem, so I came over and we started to go through the VB.NET Framework v2.0 project. While investigating the area of the code containing the exact message that the customer was getting, my blood pressure started to go up right away as we started to see code that looked like this:

If intNumberLength = 16 Then
    'go through each of the 16 numbers and
    'add the code for them into the return string
    intNumber(0) = CType(Mid(strNumber, 1, 1), Integer)
    intNumber(1) = CType(Mid(strNumber, 2, 1), Integer)
    intNumber(2) = CType(Mid(strNumber, 3, 1), Integer)
    intNumber(3) = CType(Mid(strNumber, 4, 1), Integer)
    intNumber(4) = CType(Mid(strNumber, 5, 1), Integer)
    intNumber(5) = CType(Mid(strNumber, 6, 1), Integer)
    intNumber(6) = CType(Mid(strNumber, 7, 1), Integer)
    intNumber(7) = CType(Mid(strNumber, 8, 1), Integer)
    intNumber(8) = CType(Mid(strNumber, 9, 1), Integer)
    intNumber(9) = CType(Mid(strNumber, 10, 1), Integer)
    intNumber(10) = CType(Mid(strNumber, 11, 1), Integer)
    intNumber(11) = CType(Mid(strNumber, 12, 1), Integer)
    intNumber(12) = CType(Mid(strNumber, 13, 1), Integer)
    intNumber(13) = CType(Mid(strNumber, 14, 1), Integer)
    intNumber(14) = CType(Mid(strNumber, 15, 1), Integer)
    intNumber(15) = CType(Mid(strNumber, 16, 1), Integer)
 
    strCharCodes(0) = encrypt_Char1(intNumber(0), intIndexCode)
    strCharCodes(1) = encrypt_Char2(intNumber(1), intIndexCode)
    strCharCodes(2) = encrypt_Char3(intNumber(2), intIndexCode)
    strCharCodes(3) = encrypt_Char4(intNumber(3), intIndexCode)
    strCharCodes(4) = encrypt_Char5(intNumber(4), intIndexCode)
    strCharCodes(5) = encrypt_Char6(intNumber(5), intIndexCode)
    strCharCodes(6) = encrypt_Char7(intNumber(6), intIndexCode)
    strCharCodes(7) = encrypt_Char8(intNumber(7), intIndexCode)
    strCharCodes(8) = encrypt_Char9(intNumber(8), intIndexCode)
    strCharCodes(9) = encrypt_Char10(intNumber(9), intIndexCode)
    strCharCodes(10) = encrypt_Char11(intNumber(10), intIndexCode)
    strCharCodes(11) = encrypt_Char12(intNumber(11), intIndexCode)
    strCharCodes(12) = encrypt_Char13(intNumber(12), intIndexCode)
    strCharCodes(13) = encrypt_Char14(intNumber(13), intIndexCode)
    strCharCodes(14) = encrypt_Char15(intNumber(14), intIndexCode)
    strCharCodes(15) = encrypt_Char16(intNumber(15), intIndexCode)
 
    'strReturnValue = strCharCodes.ToString
ElseIf intNumberLength = 15 Then
    ' you get the idea

And this…

'first char
Select Case Left(strEncodeCard, 1)
    Case "X"    ' these character constants were originally all different
        strCardNumber(0) = "0"
    Case "X"    ' I have masked them out for this blog posting
        strCardNumber(0) = "1"
    Case "X"
        strCardNumber(0) = "2"
    Case "X"
        strCardNumber(0) = "3"
    Case "X"
        strCardNumber(0) = "4"
    Case "X"
        strCardNumber(0) = "5"
    Case "X"
        strCardNumber(0) = "6"
    Case "X"
        strCardNumber(0) = "7"
    Case "X"
        strCardNumber(0) = "8"
    Case "X"
        strCardNumber(0) = "9"
    Case Else
        blnSuccess = False
End Select

(The above code was repeated 32 times, once for each digit of a potential 16 digit credit card number, and there were two sets of these that were switched if the digit position was odd or even. There was definitely some thought put into this. I’m not saying it was good thought, just thought. Perhaps they were paid by the lines of code written?)

OK, I have done things like this from time to time, usually not to this extent, but the original designers and coders of this project at least had the good sense to encrypt the credit card information that was being e-mailed, so maybe it will get better.

Yeah, I was wrong about that, I should remember a tenet of code maintenance that I learned a long time ago: TWGW. (This stands for Things Will Get Worse.) As we stepped through the order that was confusing the system, we came upon this nugget.

'second, select the expiration year code
Select Case intExpYear
    Case 2003
        cryptoExp_Year = "X"    ' these character constants were originally all different
    Case 2004
        cryptoExp_Year = "X"    ' I have masked them out for this blog posting
    Case 2005
        cryptoExp_Year = "X"
    Case 2006
        cryptoExp_Year = "X"
    Case 2007
        cryptoExp_Year = "X"
    Case 2008
        cryptoExp_Year = "X"
    Case 2009
        cryptoExp_Year = "X"
    Case 2010
        cryptoExp_Year = "X"
    Case 2011
        cryptoExp_Year = "X"
    Case 2012
        cryptoExp_Year = "X"
End Select

Of course, the customer had a credit card that expired in 2013, and as such, no character was begin inserted into the encrypted string for the expiration year, and that was causing the problem.

I don’t even know where to begin, except to say that eventually this code was going to break, and that was the day. (System.Security.Cryptography was in .NET Framework v1.1, so they can’t use that as an excuse.) So the moral of the story is, if you are going to reinvent a Microsoft namespace, at least make it work more than six years.

If at first you don’t succeed, try try (catch catch) again

So I am cruising through the ASP.NET C# MVP web project we are working on, and happened upon this method (again, the names were changed to protect the not so innocent):

private void mView_LoadObjects(object sender, EventArgs e)
{
    try
    {
        try
        {
            BusinessLayer.Class1 bizClass = new BusinessLayer.Class1();
            mView.objects = bizClass.GetObjects(mView.ID1, mView.ID2);
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine(ex.Message);
            throw;
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message);
        throw;
    }
}

However, the fun didn’t stop there.  A little further down the class, I found this:

private void mView_LoadOtherObjects(object sender, EventArgs e)
{
    try
    {
 
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine(ex.Message);
        throw;
    }
}

I am thinking that the catch block on this second example was not hit very often.

ELMAH for ASP.NET

My company has been doing ASP.NET development for a few years now, and we have had varying success in dealing with exceptions. In a Scott Hanselman blog post, I found out about ELMAH (Error Logging Modules and Handlers), which can assist development of ASP.NET web sites.

After some configuration issues in the Web.config file, we were able to get it working fine on my local machine. We have not tried using it in a production environment, but I would guess that it should work fine as long as we create the appropriate folder on the web server to save the XML files.

I suspect that we have only begun to scratch the surface of what is possible with ELMAH, but I would reiterate what many others have said. Anyone doing ASP.NET web development should be using ELMAH.

Here are a couple of links:

ELMAH project home (Edit: link changed)

DotNetSlackersArticle introductory article by Simone Busoli (Edit: link to the page ‘http://code.google.com/p/elmah/wiki/DotNetSlackersArticle’ now shows as dead)