Posts tagged ‘ASP.NET’

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.

Stir Trek: Avengers Edition (May 4, 2012)

It was a fun time today attending the Stir Trek Avengers Edition developer event in Columbus, Ohio. I especially enjoyed the Scott Hanselman sessions on becoming more productive and on ASP.NET. And the movie was real loud.

Also, I would like to thank all the people who downloaded my Stir Trek 2012 app (link redacted, app has been removed from the App Store) for the iPhone. Yesterday’s download count was almost larger than the entire download count for the Stir Trek app I did in 2011.

BTW, to continue the movie theme, Happy Star Wars day to everyone.

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.

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.

Subversion operations on Visual Studio 2008 solution take forever

Well, not literally, just a very very long time.

Our Subversion source repository has grown to be quite sizable over the past couple of years. We have always used TortoiseSVN and VisualSVN to tame this beast, and it has usually not let us down.

However, a while back, something bad happened to a VS 2008 solution in the repository. When launching the solution, the refresh of the version control status indicators next to the files in the solution take a very long time to appear and/or refresh, and any kind of operation done on the solution file (such as update, repo browser, etc.) goes back to the root of the whole repository instead of working with the folder where the solution file lives.

Strangely enough, operations done on any of the components inside of the solution does the right thing. In other words, if I update a project in the solution from Visual Studio, it works lightning fast.

I finally got tired of wasting 2 to 10 minutes per operation on the solution and studied this problem by comparing this malfunctioning solution with one that appears to do what you would expect it to. One thing I noticed right away was that the speedy project contained the following lines at the bottom of the solution file (opened in your favorite text editor, of course):

    GlobalSection(ExtensibilityGlobals) = postSolution
        VisualSVNWorkingCopyRoot =
    EndGlobalSection
    GlobalSection(SubversionScc) = preSolution
        Svn-Managed = True
        Manager = AnkhSVN - Subversion Support for Visual Studio
    EndGlobalSection

I added these lines to the bottom of my sluggish solution file and re-opened it, and I now predict explosive advances in my productivity. Or at least more time for tweeting.

Now all I need to do is figure out how to remove these disabled “DSL Tools”, “Text Transformation”, “Workflow”, and “ANTS 4” menu items from my VS 2008. Anyone have any ideas? (EDIT: John Boker has found the solution, see the comments.)

EDIT, PART DEUX: I tried this fix on a different existing Visual Studio project on 9/23/2009, and of course it didn’t work. I studied the problem a bit more, and found that if I added the GlobalSection(SubversionSCC) section that I have already inserted into the code block above, it did the trick for me. (Even though I am not actually using AnkhSVN, I am using TortoiseSVN, so I am guessing the Manager line is not important. However, I have left it in there for completeness.)

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.

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)