Add .NET Core 2.1 versions
This commit is contained in:
12
vote/dotnet/Vote/Messaging/IMessageQueue.cs
Normal file
12
vote/dotnet/Vote/Messaging/IMessageQueue.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using NATS.Client;
|
||||
using Vote.Messaging.Messages;
|
||||
|
||||
namespace Vote.Messaging
|
||||
{
|
||||
public interface IMessageQueue
|
||||
{
|
||||
IConnection CreateConnection();
|
||||
|
||||
void Publish<TMessage>(TMessage message) where TMessage : Message;
|
||||
}
|
||||
}
|
23
vote/dotnet/Vote/Messaging/MessageHelper.cs
Normal file
23
vote/dotnet/Vote/Messaging/MessageHelper.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using Newtonsoft.Json;
|
||||
using Vote.Messaging.Messages;
|
||||
using System.Text;
|
||||
|
||||
namespace Vote.Messaging
|
||||
{
|
||||
public class MessageHelper
|
||||
{
|
||||
public static byte[] ToData<TMessage>(TMessage message)
|
||||
where TMessage : Message
|
||||
{
|
||||
var json = JsonConvert.SerializeObject(message);
|
||||
return Encoding.Unicode.GetBytes(json);
|
||||
}
|
||||
|
||||
public static TMessage FromData<TMessage>(byte[] data)
|
||||
where TMessage : Message
|
||||
{
|
||||
var json = Encoding.Unicode.GetString(data);
|
||||
return (TMessage)JsonConvert.DeserializeObject<TMessage>(json);
|
||||
}
|
||||
}
|
||||
}
|
35
vote/dotnet/Vote/Messaging/MessageQueue.cs
Normal file
35
vote/dotnet/Vote/Messaging/MessageQueue.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NATS.Client;
|
||||
using Vote.Messaging.Messages;
|
||||
|
||||
namespace Vote.Messaging
|
||||
{
|
||||
public class MessageQueue : IMessageQueue
|
||||
{
|
||||
protected readonly IConfiguration _configuration;
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
public MessageQueue(IConfiguration configuration, ILogger<MessageQueue> logger)
|
||||
{
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Publish<TMessage>(TMessage message)
|
||||
where TMessage : Message
|
||||
{
|
||||
using (var connection = CreateConnection())
|
||||
{
|
||||
var data = MessageHelper.ToData(message);
|
||||
connection.Publish(message.Subject, data);
|
||||
}
|
||||
}
|
||||
|
||||
public IConnection CreateConnection()
|
||||
{
|
||||
var url = _configuration.GetValue<string>("MessageQueue:Url");
|
||||
return new ConnectionFactory().CreateConnection(url);
|
||||
}
|
||||
}
|
||||
}
|
15
vote/dotnet/Vote/Messaging/Messages/Events/VoteCastEvent.cs
Normal file
15
vote/dotnet/Vote/Messaging/Messages/Events/VoteCastEvent.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Vote.Messaging.Messages
|
||||
{
|
||||
public class VoteCastEvent : Message
|
||||
{
|
||||
public override string Subject { get { return MessageSubject; } }
|
||||
|
||||
public string VoterId {get; set;}
|
||||
|
||||
public string Vote {get; set; }
|
||||
|
||||
public static string MessageSubject = "events.vote.votecast";
|
||||
}
|
||||
}
|
16
vote/dotnet/Vote/Messaging/Messages/Message.cs
Normal file
16
vote/dotnet/Vote/Messaging/Messages/Message.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Vote.Messaging.Messages
|
||||
{
|
||||
public abstract class Message
|
||||
{
|
||||
public string CorrelationId { get; set; }
|
||||
|
||||
public abstract string Subject { get; }
|
||||
|
||||
public Message()
|
||||
{
|
||||
CorrelationId = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
}
|
50
vote/dotnet/Vote/Pages/Index.cshtml
Normal file
50
vote/dotnet/Vote/Pages/Index.cshtml
Normal file
@ -0,0 +1,50 @@
|
||||
@page
|
||||
@model Vote.Pages.IndexModel
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>@Model.OptionA vs @Model.OptionB!</title>
|
||||
<base href="/index.html">
|
||||
<meta name="viewport" content="width=device-width, initial-scale = 1.0">
|
||||
<meta name="keywords" content="docker-compose, docker, stack">
|
||||
<meta name="author" content="Docker DevRel team">
|
||||
<link rel="stylesheet" href="~/css/site.css" />
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<div id="content-container">
|
||||
<div id="content-container-center">
|
||||
<h3>@Model.OptionA vs @Model.OptionB!</h3>
|
||||
<form method="POST" id="choice" name='form'>
|
||||
<button id="a" type="submit" name="vote" class="a" value="a">@Model.OptionA</button>
|
||||
<button id="b" type="submit" name="vote" class="b" value="b">@Model.OptionB</button>
|
||||
</form>
|
||||
<div id="tip">
|
||||
(Tip: you can change your vote)
|
||||
</div>
|
||||
<div id="hostname">
|
||||
Processed by container ID @System.Environment.MachineName
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="~/js/jquery-1.11.1-min.js" type="text/javascript"></script>
|
||||
@*<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.js"></script>*@
|
||||
|
||||
<script>
|
||||
var vote = "@Model.Vote";
|
||||
|
||||
if(vote == "a"){
|
||||
$(".a").prop('disabled', true);
|
||||
$(".a").html('@Model.OptionA <i class="fa fa-check-circle"></i>');
|
||||
$(".b").css('opacity','0.5');
|
||||
}
|
||||
if(vote == "b"){
|
||||
$(".b").prop('disabled', true);
|
||||
$(".b").html('@Model.OptionB <i class="fa fa-check-circle"></i>');
|
||||
$(".a").css('opacity','0.5');
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
75
vote/dotnet/Vote/Pages/Index.cshtml.cs
Normal file
75
vote/dotnet/Vote/Pages/Index.cshtml.cs
Normal file
@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Vote.Messaging;
|
||||
using Vote.Messaging.Messages;
|
||||
|
||||
namespace Vote.Pages
|
||||
{
|
||||
public class IndexModel : PageModel
|
||||
{
|
||||
private string _optionA;
|
||||
private string _optionB;
|
||||
|
||||
protected readonly IMessageQueue _messageQueue;
|
||||
protected readonly IConfiguration _configuration;
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
public IndexModel(IMessageQueue messageQueue, IConfiguration configuration, ILogger<IndexModel> logger)
|
||||
{
|
||||
_messageQueue = messageQueue;
|
||||
_configuration = configuration;
|
||||
_logger = logger;
|
||||
|
||||
_optionA = _configuration.GetValue<string>("Voting:OptionA");
|
||||
_optionB = _configuration.GetValue<string>("Voting:OptionB");
|
||||
}
|
||||
|
||||
public string OptionA { get; private set; }
|
||||
|
||||
public string OptionB { get; private set; }
|
||||
|
||||
[BindProperty]
|
||||
public string Vote { get; private set; }
|
||||
|
||||
private string _voterId
|
||||
{
|
||||
get { return TempData.Peek("VoterId") as string; }
|
||||
set { TempData["VoterId"] = value; }
|
||||
}
|
||||
|
||||
public void OnGet()
|
||||
{
|
||||
OptionA = _optionA;
|
||||
OptionB = _optionB;
|
||||
}
|
||||
|
||||
public IActionResult OnPost(string vote)
|
||||
{
|
||||
Vote = vote;
|
||||
OptionA = _optionA;
|
||||
OptionB = _optionB;
|
||||
if (_configuration.GetValue<bool>("MessageQueue:Enabled"))
|
||||
{
|
||||
PublishVote(vote);
|
||||
}
|
||||
return Page();
|
||||
}
|
||||
|
||||
private void PublishVote(string vote)
|
||||
{
|
||||
if (string.IsNullOrEmpty(_voterId))
|
||||
{
|
||||
_voterId = Guid.NewGuid().ToString();
|
||||
}
|
||||
var message = new VoteCastEvent
|
||||
{
|
||||
VoterId = _voterId,
|
||||
Vote = vote
|
||||
};
|
||||
_messageQueue.Publish(message);
|
||||
}
|
||||
}
|
||||
}
|
24
vote/dotnet/Vote/Program.cs
Normal file
24
vote/dotnet/Vote/Program.cs
Normal file
@ -0,0 +1,24 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace Vote
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
CreateWebHostBuilder(args).Build().Run();
|
||||
}
|
||||
|
||||
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
|
||||
WebHost.CreateDefaultBuilder(args)
|
||||
.UseStartup<Startup>();
|
||||
}
|
||||
}
|
27
vote/dotnet/Vote/Properties/launchSettings.json
Normal file
27
vote/dotnet/Vote/Properties/launchSettings.json
Normal file
@ -0,0 +1,27 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:6116",
|
||||
"sslPort": 44316
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": true,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"Vote": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": true,
|
||||
"applicationUrl": "https://localhost:5001;http://localhost:5000",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
45
vote/dotnet/Vote/Startup.cs
Normal file
45
vote/dotnet/Vote/Startup.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Vote.Messaging;
|
||||
|
||||
namespace Vote
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public Startup(IConfiguration configuration)
|
||||
{
|
||||
Configuration = configuration;
|
||||
}
|
||||
|
||||
public IConfiguration Configuration { get; }
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddMvc()
|
||||
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
|
||||
.AddRazorPagesOptions(options =>
|
||||
{
|
||||
options.Conventions.ConfigureFilter(new IgnoreAntiforgeryTokenAttribute());
|
||||
});
|
||||
services.AddTransient<IMessageQueue, MessageQueue>();
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
|
||||
{
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
else
|
||||
{
|
||||
app.UseExceptionHandler("/Error");
|
||||
}
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseMvc();
|
||||
}
|
||||
}
|
||||
}
|
12
vote/dotnet/Vote/Vote.csproj
Normal file
12
vote/dotnet/Vote/Vote.csproj
Normal file
@ -0,0 +1,12 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.App" />
|
||||
<PackageReference Include="NATS.Client" Version="0.8.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
25
vote/dotnet/Vote/Vote.sln
Normal file
25
vote/dotnet/Vote/Vote.sln
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27703.2042
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vote", "Vote.csproj", "{DA159FEC-BE4D-4704-ACB2-E03FFA6F2D3B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{DA159FEC-BE4D-4704-ACB2-E03FFA6F2D3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DA159FEC-BE4D-4704-ACB2-E03FFA6F2D3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DA159FEC-BE4D-4704-ACB2-E03FFA6F2D3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DA159FEC-BE4D-4704-ACB2-E03FFA6F2D3B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {BEABFEFC-9957-41E3-96A1-7F501F69411D}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
12
vote/dotnet/Vote/appsettings.Development.json
Normal file
12
vote/dotnet/Vote/appsettings.Development.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"MessageQueue": {
|
||||
"Enabled": false
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Debug",
|
||||
"System": "Information",
|
||||
"Microsoft": "Information"
|
||||
}
|
||||
}
|
||||
}
|
16
vote/dotnet/Vote/appsettings.json
Normal file
16
vote/dotnet/Vote/appsettings.json
Normal file
@ -0,0 +1,16 @@
|
||||
{
|
||||
"Voting": {
|
||||
"OptionA": "Cats",
|
||||
"OptionB": "Dogs"
|
||||
},
|
||||
"MessageQueue": {
|
||||
"Enabled": true,
|
||||
"Url": "nats://message-queue:4222"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
135
vote/dotnet/Vote/wwwroot/css/site.css
Normal file
135
vote/dotnet/Vote/wwwroot/css/site.css
Normal file
@ -0,0 +1,135 @@
|
||||
@import url(//fonts.googleapis.com/css?family=Open+Sans:400,700,600);
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: #F7F8F9;
|
||||
height: 100vh;
|
||||
font-family: 'Open Sans';
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 0;
|
||||
width: 100%;
|
||||
height: 50%;
|
||||
}
|
||||
|
||||
button[type="submit"] {
|
||||
-webkit-appearance: none;
|
||||
-webkit-border-radius: 0;
|
||||
}
|
||||
|
||||
button i {
|
||||
float: right;
|
||||
padding-right: 30px;
|
||||
margin-top: 3px;
|
||||
}
|
||||
|
||||
button.a {
|
||||
background-color: #1aaaf8;
|
||||
}
|
||||
|
||||
button.b {
|
||||
background-color: #00cbca;
|
||||
}
|
||||
|
||||
#tip {
|
||||
text-align: left;
|
||||
color: #c0c9ce;
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
#hostname {
|
||||
position: absolute;
|
||||
bottom: 100px;
|
||||
right: 0;
|
||||
left: 0;
|
||||
color: #8f9ea8;
|
||||
font-size: 24px;
|
||||
}
|
||||
|
||||
#content-container {
|
||||
z-index: 2;
|
||||
position: relative;
|
||||
margin: 0 auto;
|
||||
display: table;
|
||||
padding: 10px;
|
||||
max-width: 940px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
#content-container-center {
|
||||
display: table-cell;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#content-container-center h3 {
|
||||
color: #254356;
|
||||
}
|
||||
|
||||
#choice {
|
||||
transition: all 300ms linear;
|
||||
line-height: 1.3em;
|
||||
display: inline;
|
||||
vertical-align: middle;
|
||||
font-size: 3em;
|
||||
}
|
||||
|
||||
#choice a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#choice a:hover, #choice a:focus {
|
||||
outline: 0;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
#choice button {
|
||||
display: block;
|
||||
height: 80px;
|
||||
width: 330px;
|
||||
border: none;
|
||||
color: white;
|
||||
text-transform: uppercase;
|
||||
font-size: 18px;
|
||||
font-weight: 700;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
text-align: left;
|
||||
padding-left: 50px;
|
||||
}
|
||||
|
||||
#choice button.a:hover {
|
||||
background-color: #1488c6;
|
||||
}
|
||||
|
||||
#choice button.b:hover {
|
||||
background-color: #00a2a1;
|
||||
}
|
||||
|
||||
#choice button.a:focus {
|
||||
background-color: #1488c6;
|
||||
}
|
||||
|
||||
#choice button.b:focus {
|
||||
background-color: #00a2a1;
|
||||
}
|
||||
|
||||
#background-stats {
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
#background-stats div {
|
||||
transition: width 400ms ease-in-out;
|
||||
display: inline-block;
|
||||
margin-bottom: -4px;
|
||||
width: 50%;
|
||||
height: 100%;
|
||||
}
|
1
vote/dotnet/Vote/wwwroot/css/site.min.css
vendored
Normal file
1
vote/dotnet/Vote/wwwroot/css/site.min.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
body{padding-top:50px;padding-bottom:20px}.body-content{padding-left:15px;padding-right:15px}.carousel-caption p{font-size:20px;line-height:1.4}.carousel-inner .item img[src$=".svg"]{width:100%}#qrCode{margin:15px}@media screen and (max-width:767px){.carousel-caption{display:none}}
|
13
vote/dotnet/Vote/wwwroot/js/jquery-1.11.1-min.js
vendored
Normal file
13
vote/dotnet/Vote/wwwroot/js/jquery-1.11.1-min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user