Wednesday, May 27, 2009

Spawning a new window when a form is posted using Html.BeginForm

While it is not immediately evident, the following usage will spawn a new window displaying the results of a form post.


<%Using Html.BeginForm("Print", "Secure", Nothing, FormMethod.Post , New With {.target="_blank"})%>



Turns out that the form tag always included the target attribute, you just need to instruct the BeginForm helper to use it.

Tuesday, May 5, 2009

Determining the run time of a process.

I have had several cases through my professional career where I have developed background processes that handle recurring tasks, such as renewing subscriptions or retrieving history for a batch of customers. These are normally implemented as Windows Services, which means I generally log the status of the process, as well as any summary data for its last execution, to the Application Event Log.

One piece of data I like to include in my summary log entry is how long a processing cycle took to execute. This data point is helpful for routine benchmarking, as well as determining if a process has gone rogue and is taking unusually long to complete (possibly due to a remote service latency or something like that.)

Using the provide Date related objects in .NET makes it easy to determine and report this execution time.

First, define some variables for the summary report:


Dim startTime As DateTime = DateTime.Now()
Dim recordsToProcess As Integer = 0
Dim recordsProcessed As Integer = 0
Dim recordsErrored As Integer = 0


I typically am pulling records to process from a database query, and so setting up the processing loop is pretty straight forward.


recordsToProcess = dataSetWithRecords.Tables(0).Rows.Count

For Each drCurrentRecord As DataRow In dataSetWithRecords.Tables(0).Rows

'do processing here
Try
'execute task
.
.
.
'update success counter
recordsProcessed += 1
Catch ex as Exception
'handle error state
'update error counter
recordsErrored += 1
End Try
Next

Now I can capture and calculate the processing time. I use the DateDiff() method to determine the number of seconds between the start and end timestamps. Then, using the TimeSpan object I have an easy to use representation of the time elapsed that I can put in my summary message.


Dim endTime As DateTime = DateTime.Now
Dim timeElapsedSeconds As Double = DateDiff(DateInterval.Second, startTime, endTime)
Dim timeElapsedSpan As TimeSpan = New TimeSpan(0, 0, timeElapsedseconds)

Dim sbSummary As New System.Text.StringBuilder
sbSummary.AppendLine("Agent Results:")
sbSummary.AppendFormat("Total records to process:{0}", recordsToProcess.ToString)
sbSummary.AppendLine()
sbSummary.AppendFormat("Records processed Successfully: {0}",recordsProcessed.ToString)
sbSummary.AppendLine()
sbSummary.AppendFormat("Records with errors: {0}", recordsErrored.ToString)
sbSummary.AppendLine()
sbSummary.AppendFormat("Processing Time: {0} Hours, {1} Minutes, {2} Seconds", timeElapsedSpan.Hours, timeElapsedSpan.Minutes, timeElapsedSpan.Seconds)
sbSummary.AppendLine()

LogMessage(sbSummary.ToString)

This approach is reliable, accurate, and keeps me from having to manually calculate the elapsed time.

Monday, May 4, 2009

Namespaces and Partial Classes

This post goes in the 'finally figured out why my code wasn't working like I expect it' category.

More and more, Visual Studio and various .NET project items use the .designer file as a partial class to put code generated by VS. A lot of time, you never need to worry about the .designer file.

I encountered a situation recently while creating a Windows Service in VS2008. In my Service class (which has a .designer file) I changed the Namespace. Everything compiled great, and the Windows Service installer would successfully deploy and register the service. But when I would try to start the service, nothing would happen. My code would never run.

In the end, I remembered that the Main() method of the Service is located in the .designer file. As soon as I added the matching Namespace to the .designer file, rebuilt and redeployed, the service started up without any problem.

I personally like to use Namespace entries on every class rather than using the Root Namespace entry on the Project properties. I now know that I need to make sure any Partial classes also have the matching Namespace designation. Lesson learned.