Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Voting Control using MVC5 and Razor

0.00/5 (No votes)
14 May 2014 1  
Simple voting control for MVC5 projects, using a partial view

Introduction

This is a simple voting control for MVC projects. It is implemented as a partial view, and so can be included wherever required. It was created in Visual Studio 2013 using MVC5.

Background

I originally wrote an article describing a voting control using MVC2. I decided it would be a good idea to update it to use MVC5 and Razor. I started by creating a new ASP.NET web application project in Visual Studio 2013. I opened the original MVC2 project in Visual Studio 2008 (it failed to convert in VS2013) and copied the files across as required. To start with assume that I have done all the changes, and everything works. That way I can show you how to use the code, and see what it looks like. Later in the article I'll describe how it all works and how I ported it from the MVC2 version.

Using the code

In the default Index.aspx page I removed the existing contents of the main div and replaced it with the following:

<div class="row">
    <div style="float:left">
        @{
            VoteDataModel petModel = (VoteDataModel)ViewData[VoteDataModel.GetViewDataName("Pet")];
            petModel.ControlWidth = 200;
            Html.RenderPartial("VoteControl", petModel);
        }
    </div>
    <p style="width:300px;padding-left:10px;overflow:hidden">
        This is a simple control with a width of 200px. Click on the button to vote,
        or click <b>Skip to Results</b> to see the results without voting.
    </p>
    <div style="clear:both"></div>
    <p>
        This next control has a long question and long answers. The width has been set
        to 400px.
    </p>
    @{
        VoteDataModel longQuestionModel = (VoteDataModel)ViewData[VoteDataModel.GetViewDataName("LongQuestionsAndAnswers")];
        longQuestionModel.ControlWidth = 400;
        Html.RenderPartial("VoteControl", longQuestionModel);
    }
    <p>
        You can get back to the questions by clicking on the <b>Back to Voting</b>
        link, or see the actual number of votes (instead of the percentages) by
        clicking on <b>Show Counts</b>
    </p>
</div>

In this example we are displaying two voting controls. You can see that we specify how the control appears (in this case just the width, but we could add any customisations that we wanted) and where to get the data from. The data - questions, answers and voting counts are all stored in a single XML file.

We need to add a reference to the model namespace at the top of the file:

@using VoteControlWebApp.Models

The controller (in this case HomeController.cs) needs to be modified in order to create the models:

public ActionResult Index()
{
    VoteDataModel model = new VoteDataModel("Pet", Request.PhysicalApplicationPath + "App_Data\\");
    model.Open();
    ViewData[model.ViewDataName] = model;
    model = new VoteDataModel("LongQuestionsAndAnswers", Request.PhysicalApplicationPath + "App_Data\\");
    model.Open();
    ViewData[model.ViewDataName] = model;

    return View();
} 

The entire page (having voted on both polls) then looks like:

So having seen how to use it, lets get back to how I implemented it.

The Voting Control Implementation

The control itself is implemented as a partial view in the Views::Shared folder - VodeControl.cshtml. All the data is passed in as the model - VoteModel.cs in the Models folder.

The XML files containing the data for each instance of the voting control are in the App_Data folder. There is one XML file per voting control instance.

There is a controller - VoteController.cs, in the Controllers folder. It's sole purpose is to process the incoming request when the Vote button is clicked. In order to route the request through to the VoteController, the following route was added to the RouteConfig.cs file:

routes.MapRoute(
    "VoteButton", // Route name
    "DoVote/{uniqueName}/{voteId}", // URL with parameters
    new { controller = "Vote", action = "DoVote" },
    new { voteId = @"\d{1,3}" } // voteId can only be numeric, and less than 1000
);

The voting control requires a style sheet and javascript (in the Content and Scripts folders), so I added references to them in _Layout.cshtml.

The entire list of files that I had to create or modify is shown below:

Under The Hood

The bulk of the code is in the model (as it should be).

The VodelDataModel object contains a list of answers (List<AnswerItem>) and IP addresses (List<IpAddressItem>). There is one AnswerItem for each answer, and one entry is added for each unique client IP address. This is how we make sure the user only votes once. It's not perfect - see the "Points of Interest" in the MVC2 article for more details about this.

The following public methods are available in the model:

static string GetViewDataName(string uniqueName) and string ViewDataName

This gets a name that will be used for the view data. We use this in the controller and in the view - there is a static method that is used in the view, and a instance property that is used in the controller.

public VoteDataModel(string name, string path)

Object constructor.

public bool Open()

Open should always be called after constructing the object. This reads the data from the XML file.

public bool DoVote(int voteId, string ipAddr)

Thread safe - see last section.

This updates the object and the file. Returns true if vote was accepted or false if the ip address was found - i.e., the user has already voted.

public int GetPercentage(int index)

This is used in the partial view to display the percentage.

public int GetBarLength(int index, int controlWidth)

This is used in the partial view to display the percentage bar.

Points of Interest

Converting the code from MVC2 was relatively straightforward. The views required the most work - converting to Razor syntax, and there were some style sheet issues. The model required no modification.

History

  • May 2014 - Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here