How to Build a Real-time Voting App with .NET and C#

PubNub Developer Relations - Mar 5 - - Dev Community

You can easily build a live real-time voting app in the browser with C# and .NET, enabling users to vote and see results, updated in real time. It's a web application that brings in the functionality of real-time voting system. Given the rapid technological advancements, it's essential to keep pace and for that, I would like to mention that throughout this tutorial, we are using C# 9, ASP.NET 5.0, and PubNub C# SDK version 4.4.0.

In this tutorial, we’re showcasing how to create a web-based real-time voting application using the C# PubNub API, and ASP.NET MCV4, a part of Microsoft's ASP.NET Core Web API. This will enable users to vote, and the results will be automatically tallied and displayed in real-time, thanks to the PubNub C# SDK. We'll specifically leverage the publish()\, Subscribe()\ and DetailedHistory\ methods to power our real-time voting app. You can find the source code on GitHub.

In any real-time application, we envisage the question and the choice of answers/responses to originate from a backend like an SQL server database using entity framework. To narrow down our focus in this tutorial, I’ll be hard coding the questions and answer options in the GetActivePollQuestion()\ method of the SampleData\ class, rendering these as xml strings. In a real-world scenario, you would want to return dynamic data as xml string.

Schemas for a Real-time Voting App

In this context, schemas pave the way for organized and structured data storage, enabling efficient data handling operations. To accomplish our objectives, two schemas, PollQuestion.xsd and PollUserAnswer.xsd were created. These provide a blueprint for our data, outlining the structure and type of information stored.

The corresponding class files, PollQuestion.cs and PollUserAnswer.cs, were generated using the following commands in the Visual Studio terminal via the xsd.exe tool:

XSD.EXE PollQuestion.xsd /c /l:cs /n:ePoll.Types

XSD.EXE PollUserAnswer.xsd /c /l:cs /n:ePoll.Types
Enter fullscreen mode Exit fullscreen mode

Take a look at the formats of these schemas:

<xs:schema id="PollQuestion"
    targetNamespace="pubnub-csharp-demo-epoll-1.0"
    elementFormDefault="qualified"
    xmlns="pubnub-csharp-demo-epoll-1.0"
    xmlns:mstns="pubnub-csharp-demo-epoll-1.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="PollQuestion">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="ID" type="xs:string"></xs:element>
        <xs:element name="Question" type="xs:string"></xs:element>
        <xs:element name="Active" type="xs:boolean"></xs:element>
        <xs:element name="AnswerGroup">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="Answer" type="xs:string" maxOccurs="unbounded" minOccurs="2"></xs:element>
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>
</xs:schema>
Enter fullscreen mode Exit fullscreen mode
<xs:schema id="PollUserAnswer"
    targetNamespace="pubnub-csharp-demo-epoll-1.0"
    elementFormDefault="qualified"
    xmlns="pubnub-csharp-demo-epoll-1.0"
    xmlns:mstns="pubnub-csharp-demo-epoll-1.0"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="PollUserAnswer">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="QuestionID" type="xs:string"></xs:element>
        <xs:element name="Question" type="xs:string"></xs:element>
        <xs:element name="UserAnswer" type="xs:string"></xs:element>
      </xs:sequence>
    </xs:complexType>
  </xs:element>

</xs:schema>
Enter fullscreen mode Exit fullscreen mode

Publishing Messages over WebSockets for Real-time Voting

The Publish()\ method plays a crucial role in our real-time voting application as it is used to send the poll answers to a specified PubNub channel. This message is then received by all instances subscribed to that channel in real time, facilitating an interactive voting experience. You can easily configure this operation with the following C# code segment.

public bool SaveAnswer(PollUserAnswer answer)
{
    bool ret = false;

    string pubnubChannel = answer.QuestionID;
    mrePublish.AddOrUpdate(pubnubChannel, new ManualResetEvent(false), (key, oldState) => new ManualResetEvent(false));
    messagePublished[pubnubChannel] = false;

    pubnub.Publish().Channel(pubnubChannel).Message(answer.UserAnswer)
        .Execute(new PNPublishResultExt(
            (result, status) => {
                if (!status.Error && result != null)
                {
                    messagePublished[pubnubChannel] = true;
                    mrePublish[pubnubChannel].Set();
                }
            }));

    mrePublish[pubnubChannel].WaitOne(TimeSpan.FromSeconds(10));

    return messagePublished[pubnubChannel];
}
Enter fullscreen mode Exit fullscreen mode

Subscribing to Real-time Voting User Submissions over WebSockets

On the other side of the equation, the Subscribe()\ method is used for receiving poll answers in real time. This enables our application to provide real-time updates. The PubNub SDK can auto-recover any message/link that is dropped using long polling among other protocols. To get the functionality of this in your C# code you can add the following code snippet.

pubnub.Subscribe<string>()
    .Channels(new List<string> { pubnubChannel })
    .WithPresence() // If you need presence feature
    .Execute();

// Handling messages, presence, and status within the subscription listener
pubnub.AddListener(new SubscribeCallbackExt(
    (pubnubObj, message) => {
        if (message != null)
        {
            Console.WriteLine("VOTE RECEIVED!");
            Console.WriteLine(message.Message);
            Console.WriteLine();
        }
    },
    (pubnubObj, presence) => {
        // Handle presence event if needed
    },
    (pubnubObj, status) => {
        if (status != null)
        {
            if (status.Category == PNStatusCategory.PNConnectedCategory)
            {
                Console.WriteLine("SUBSCRIBE CONNECT CALLBACK:");
                Console.WriteLine(status.Category.ToString());
                Console.WriteLine();
            }
            else if (status.Error)
            {
                Console.WriteLine();
                Console.WriteLine(status.ErrorData.Information);
                Console.WriteLine();
            }
        }
    }
));
Enter fullscreen mode Exit fullscreen mode

Loading History of Messages over WebSockets for Real-time Voting Dashboard

The DetailedHistory\ method fetches historical messages from a channel. This method fetches these messages asynchronously, allowing us to see the history of voting data from a specified PubNub channel. Here's the code segment demonstrating this:

public async Task<List<string>> GetPollResultsAsync(string questionID)
{
    List<string> ret = new List<string>();

    string pubnubChannel = questionID;
    long startTimetoken = 0; // For fetching all messages. Adjust as needed.

    try
    {
        PNHistoryResult result = await pubnub.History()
            .Channel(pubnubChannel)
            .Start(startTimetoken)
            .Count(100) // Adjust based on how many messages you expect to fetch. Max usually 100.
            .IncludeTimetoken(true)
            .ExecuteAsync();

        if (result != null && result.Messages != null)
        {
            foreach (var message in result.Messages)
            {
                // Assuming the messages are strings. Adjust as necessary for your data format.
                ret.Add(message.Entry.ToString());
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"An error occurred: {ex.Message}");
        // Handle errors or exceptions as necessary.
    }

    return ret;
}
Enter fullscreen mode Exit fullscreen mode

Wrapping Up

By now, you should have a good understanding of how to build a real-time voting application using C#, .NET, and the PubNub C# SDK. If you have followed the tutorial thoroughly, you would have noticed how simple it is to integrate real-time features into your applications using PubNub.

In the next blog post, we'll take this a notch further by incorporating additional features such as Angular on the front-end, add user authentication, configure data encryption, and much more. Stay tuned to our playlist of web development tutorials!

Getting Started

Our platform helps developers build, deliver, and manage real-time interactivity for web apps, mobile apps, and IoT devices. It's particularly useful for building a real-time voting application like the one we'll be discussing in this tutorial.

The foundation of our platform is the industry's largest and most scalable real-time edge messaging network. And you can depend on us for robust, high-performance solutions.

Experience PubNub

Live Tour

Get Setup

To start creating your own real-time applications, sign up for a PubNub account.

Get Started

The PubNub docs are there to help you, no matter what you're building. We offer extensive guides for different use cases and SDKs, including C# which we used in this tutorial.

Contents

Schemas for a Real-time Voting AppPublishing Messages over WebSockets for Real-time VotingSubscribing to Real-time Voting User Submissions over WebSocketsLoading History of Messages over WebSockets for Real-time Voting DashboardWrapping UpGetting StartedExperience PubNubGet SetupGet Started

How can PubNub help you?

This article was originally published on PubNub.com

Our platform helps developers build, deliver, and manage real-time interactivity for web apps, mobile apps, and IoT devices.

The foundation of our platform is the industry's largest and most scalable real-time edge messaging network. With over 15 points-of-presence worldwide supporting 800 million monthly active users, and 99.999% reliability, you'll never have to worry about outages, concurrency limits, or any latency issues caused by traffic spikes.

Experience PubNub

Check out Live Tour to understand the essential concepts behind every PubNub-powered app in less than 5 minutes

Get Setup

Sign up for a PubNub account for immediate access to PubNub keys for free

Get Started

The PubNub docs will get you up and running, regardless of your use case or SDK

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .