Building a PASS Voting Solution – Part 6

Today we’ll try to finish up by looking at a couple of the semi-interesting parts of the code in this one page application. We’ll start with the page load event. On the first run of the page (not postback) I’m grabbing the two keys I need if they exist and calling the MyBallot.Validate method (show you that next). From there I show some various bits of text and load the choices if appropriate, and then move on to deciding what to show them based on what we know.

‘only do on first page load
If Not Page.IsPostBack Then

    Try
        ‘try to load from query string
        MyBallot.BallotID = New Guid(Request.QueryString(“BallotID”))
        MyBallot.VoterID = New Guid(Request.QueryString(“VoterID”))
    Catch ex As Exception
    End Try

    MyBallot.Validate()

    ‘load the list if all is good
    If MyBallot.EligibleToVote And MyBallot.HasVoted = False Then
        MyBallot.LoadListBox(lstAvailable)
    End If

    ‘set this regardless
    lblBallotTitle.Text = Me.MyBallot.Title
    lblBallotDescription.Text = Me.MyBallot.Description
    lblBallotItem.Text = MyBallot.Title
    lblMin.Text = MyBallot.MinSelection.ToString
    lblMax.Text = MyBallot.MaxSelection.ToString
    lblClosing.Text = MyBallot.ClosingDate.tostring
End If

‘various cases, all mutually exclusive
pnlVote.Visible = False
If MyBallot.EligibleToVote And MyBallot.HasVoted = False Then
    pnlVote.Visible = True
ElseIf MyBallot.HasVoted = True Then
    ShowMessage(“You have already completed your vote in this ballot.”, displaymessage.IconToDisplay.InformationIcon)
ElseIf MyBallot.BallotID = Guid.Empty Then
    ShowMessage(“To vote on a ballot you must provide the ballotid in the URL – contact PASS HQ for assistance”, displaymessage.IconToDisplay.InformationIcon)
Else
    pnlLookup.Visible = True
End If

Validate is where we call the proc GetBallotDetails, which you may recall returns both output parameters and a result set.

‘remove any old items
Me.BallotDetails.Clear()
Me.EligibleToVote = False
Me.Title = “Unknown”
Me.Description = “”
Me.MinSelection = 1
Me.MaxSelection = 1
Me.HasVoted = False

Dim dr As SqlDataReader
Using cmd As New SqlCommand()
    With cmd
        .Connection = OpenDBConnection()
        .CommandType = CommandType.StoredProcedure
        .CommandText = “Voting.GetBallotDetails”
        .Parameters.Add(New SqlParameter(“@BallotID”, DbType.Guid))
        .Parameters(“@BallotID”).Value = ballotID
        .Parameters.Add(New SqlParameter(“@VoterID”, DbType.Guid))
        .Parameters(“@VoterID”).Value = VoterID
        .Parameters.Add(New SqlParameter(“@IsEligibleToVote”, DbType:=SqlDbType.Bit))
        .Parameters(“@IsEligibleToVote”).Direction = ParameterDirection.Output
        .Parameters.Add(New SqlParameter(“@HasVoted”, DbType:=SqlDbType.Bit))
        .Parameters(“@HasVoted”).Direction = ParameterDirection.Output

        dr = .ExecuteReader
        Do While dr.Read

            ‘just assign these each time, shouldn’t change
            Me.Title = dr!ItemTitle
            Me.MinSelection = dr!MinSelection
            Me.MaxSelection = dr!maxSelection
            Me.Description = dr!Description
            Me.ClosingDate = dr!ClosingDate

            ‘next we add the details
            Dim oDetail As New BallotDetail() With {.BallotDetailID = dr!BallotDetailID, .Title = dr!DetailTitle}
            Me.BallotDetails.Add(oDetail)

        Loop
        dr.Close()

        HasVoted = cmd.Parameters(“@HasVoted”).Value
        EligibleToVote = cmd.Parameters(“@IsEligibleToVote”).Value

        dr = Nothing

    End With
End Using

Here is the code called when they finally vote. We check our local state to see if they have voted, and then we’ll check again within the proc to make sure! ExecuteProc is a helper method that handles calling a proc when it just takes parameters.

If Me.EligibleToVote = False Then
          Throw New Exception(“We have not identified you as an eligible voter for this ballot.”)
      ElseIf Me.HasVoted = True Then
          Throw New Exception(“You have already cast your vote for this ballot.”)
      End If

      ‘trim leading comma
      If SelectedDetails.Substring(0, 1) = “,” Then
          SelectedDetails = SelectedDetails.Substring(1, SelectedDetails.Length – 1)
      End If

      Dim Params(0 To 2) As SqlParameter

      Params(0) = VarcharParam(“@Details”, 8000, SelectedDetails, False)
      Params(1) = New SqlParameter(“@BallotID”, SqlDbType.UniqueIdentifier)
      Params(1).Value = BallotID
      Params(2) = New SqlParameter(“@VoterID”, SqlDbType.UniqueIdentifier)
      Params(2).Value = VoterID
      ExecuteProc(“Voting.CastVote”, Params)

      Me.HasVoted = True

There’s not much else that is interesting. It’s set up with a master page containing the logo, and the main page is a content page. I’m storing a Ballot object in session and it’s also set up to be accessible as a property of the page, making it easy to reference as a strongly typed object.

I came in right at 10 hours. Lost a little time thinking through how to handle multiple items on each ballot, couldn’t see a way to do that without adding a lot more complexity to the UI. It still needs some testing by someone other than me, and it’s a project where I think unit tests would be appropriate, lots of different cases that could be verified (eligible, not eligible, has/not voted, etc), but I think we can do most of that with UI testing that will be needed anyway.

By the time you read this I’ll have sent the bits off to HQ for install and testing. We’ll try it on a few board votes, and we may send out a test vote in the Connector too.