Add .NET Core 2.1 versions
This commit is contained in:
16
worker/dotnet/Dockerfile
Normal file
16
worker/dotnet/Dockerfile
Normal file
@ -0,0 +1,16 @@
|
||||
FROM microsoft/dotnet:2.1-sdk as builder
|
||||
|
||||
WORKDIR /Worker
|
||||
COPY Worker/Worker.csproj .
|
||||
RUN dotnet restore
|
||||
|
||||
COPY /Worker .
|
||||
RUN dotnet publish -c Release -o /out Worker.csproj
|
||||
|
||||
# app image
|
||||
FROM microsoft/dotnet:2.1-runtime
|
||||
|
||||
WORKDIR /app
|
||||
ENTRYPOINT ["dotnet", "Worker.dll"]
|
||||
|
||||
COPY --from=builder /out .
|
7
worker/dotnet/Worker/Data/IVoteData.cs
Normal file
7
worker/dotnet/Worker/Data/IVoteData.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace Worker.Data
|
||||
{
|
||||
public interface IVoteData
|
||||
{
|
||||
void Set(string voterId, string vote);
|
||||
}
|
||||
}
|
35
worker/dotnet/Worker/Data/MySqlVoteData.cs
Normal file
35
worker/dotnet/Worker/Data/MySqlVoteData.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Worker.Entities;
|
||||
|
||||
namespace Worker.Data
|
||||
{
|
||||
public class MySqlVoteData : IVoteData
|
||||
{
|
||||
private readonly VoteContext _context;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
public MySqlVoteData(VoteContext context, ILogger<MySqlVoteData> logger)
|
||||
{
|
||||
_context = context;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Set(string voterId, string vote)
|
||||
{
|
||||
var currentVote = _context.Votes.Find(voterId);
|
||||
if (currentVote == null)
|
||||
{
|
||||
_context.Votes.Add(new Vote
|
||||
{
|
||||
VoterId = voterId,
|
||||
VoteOption = vote
|
||||
});
|
||||
}
|
||||
else if (currentVote.VoteOption != vote)
|
||||
{
|
||||
currentVote.VoteOption = vote;
|
||||
}
|
||||
_context.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
16
worker/dotnet/Worker/Entities/Vote.cs
Normal file
16
worker/dotnet/Worker/Entities/Vote.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
namespace Worker.Entities
|
||||
{
|
||||
[Table("votes")]
|
||||
public class Vote
|
||||
{
|
||||
[Column("id")]
|
||||
[Key]
|
||||
public string VoterId { get; set; }
|
||||
|
||||
[Column("vote")]
|
||||
public string VoteOption { get; set; }
|
||||
}
|
||||
}
|
19
worker/dotnet/Worker/Entities/VoteContext.cs
Normal file
19
worker/dotnet/Worker/Entities/VoteContext.cs
Normal file
@ -0,0 +1,19 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Worker.Entities
|
||||
{
|
||||
public class VoteContext : DbContext
|
||||
{
|
||||
private static bool _EnsureCreated;
|
||||
public VoteContext(DbContextOptions options) : base(options)
|
||||
{
|
||||
if (!_EnsureCreated)
|
||||
{
|
||||
Database.EnsureCreated();
|
||||
_EnsureCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
public DbSet<Vote> Votes { get; set; }
|
||||
}
|
||||
}
|
12
worker/dotnet/Worker/Messaging/IMessageQueue.cs
Normal file
12
worker/dotnet/Worker/Messaging/IMessageQueue.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using NATS.Client;
|
||||
using Worker.Messaging.Messages;
|
||||
|
||||
namespace Worker.Messaging
|
||||
{
|
||||
public interface IMessageQueue
|
||||
{
|
||||
IConnection CreateConnection();
|
||||
|
||||
void Publish<TMessage>(TMessage message) where TMessage : Message;
|
||||
}
|
||||
}
|
23
worker/dotnet/Worker/Messaging/MessageHelper.cs
Normal file
23
worker/dotnet/Worker/Messaging/MessageHelper.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using Newtonsoft.Json;
|
||||
using Worker.Messaging.Messages;
|
||||
using System.Text;
|
||||
|
||||
namespace Worker.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
worker/dotnet/Worker/Messaging/MessageQueue.cs
Normal file
35
worker/dotnet/Worker/Messaging/MessageQueue.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NATS.Client;
|
||||
using Worker.Messaging.Messages;
|
||||
|
||||
namespace Worker.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);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Worker.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
worker/dotnet/Worker/Messaging/Messages/Message.cs
Normal file
16
worker/dotnet/Worker/Messaging/Messages/Message.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace Worker.Messaging.Messages
|
||||
{
|
||||
public abstract class Message
|
||||
{
|
||||
public string CorrelationId { get; set; }
|
||||
|
||||
public abstract string Subject { get; }
|
||||
|
||||
public Message()
|
||||
{
|
||||
CorrelationId = Guid.NewGuid().ToString();
|
||||
}
|
||||
}
|
||||
}
|
38
worker/dotnet/Worker/Program.cs
Normal file
38
worker/dotnet/Worker/Program.cs
Normal file
@ -0,0 +1,38 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System;
|
||||
using Worker.Data;
|
||||
using Worker.Entities;
|
||||
using Worker.Messaging;
|
||||
using Worker.Workers;
|
||||
|
||||
namespace Worker
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddJsonFile("appsettings.json")
|
||||
.Build();
|
||||
|
||||
var loggerFactory = new LoggerFactory()
|
||||
.AddConsole();
|
||||
|
||||
var services = new ServiceCollection()
|
||||
.AddSingleton(loggerFactory)
|
||||
.AddLogging()
|
||||
.AddSingleton<IConfiguration>(config)
|
||||
.AddTransient<IVoteData, MySqlVoteData>()
|
||||
.AddTransient<IMessageQueue, MessageQueue>()
|
||||
.AddSingleton<QueueWorker>()
|
||||
.AddDbContext<VoteContext>(builder => builder.UseMySQL(config["VoteData:ConnectionString"]));
|
||||
|
||||
var provider = services.BuildServiceProvider();
|
||||
var worker = provider.GetService<QueueWorker>();
|
||||
worker.Start();
|
||||
}
|
||||
}
|
||||
}
|
30
worker/dotnet/Worker/Worker.csproj
Normal file
30
worker/dotnet/Worker/Worker.csproj
Normal file
@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp2.1</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Remove="appsettings.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Include="appsettings.json">
|
||||
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</Content>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.3" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging" Version="2.1.1" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.1.1" />
|
||||
<PackageReference Include="MySql.Data.EntityFrameworkCore" Version="8.0.12" />
|
||||
<PackageReference Include="NATS.Client" Version="0.8.1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
62
worker/dotnet/Worker/Workers/QueueWorker.cs
Normal file
62
worker/dotnet/Worker/Workers/QueueWorker.cs
Normal file
@ -0,0 +1,62 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using NATS.Client;
|
||||
using Worker.Data;
|
||||
using Worker.Messaging;
|
||||
using Worker.Messaging.Messages;
|
||||
|
||||
namespace Worker.Workers
|
||||
{
|
||||
public class QueueWorker
|
||||
{
|
||||
private static ManualResetEvent _ResetEvent = new ManualResetEvent(false);
|
||||
private const string QUEUE_GROUP = "save-handler";
|
||||
|
||||
private readonly IMessageQueue _messageQueue;
|
||||
private readonly IConfiguration _config;
|
||||
private readonly IVoteData _data;
|
||||
protected readonly ILogger _logger;
|
||||
|
||||
public QueueWorker(IMessageQueue messageQueue, IVoteData data, IConfiguration config, ILogger<QueueWorker> logger)
|
||||
{
|
||||
_messageQueue = messageQueue;
|
||||
_data = data;
|
||||
_config = config;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
_logger.LogInformation($"Connecting to message queue url: {_config.GetValue<string>("MessageQueue:Url")}");
|
||||
using (var connection = _messageQueue.CreateConnection())
|
||||
{
|
||||
var subscription = connection.SubscribeAsync(VoteCastEvent.MessageSubject, QUEUE_GROUP);
|
||||
subscription.MessageHandler += SaveVote;
|
||||
subscription.Start();
|
||||
_logger.LogInformation($"Listening on subject: {VoteCastEvent.MessageSubject}, queue: {QUEUE_GROUP}");
|
||||
|
||||
_ResetEvent.WaitOne();
|
||||
connection.Close();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveVote(object sender, MsgHandlerEventArgs e)
|
||||
{
|
||||
_logger.LogDebug($"Received message, subject: {e.Message.Subject}");
|
||||
var voteMessage = MessageHelper.FromData<VoteCastEvent>(e.Message.Data);
|
||||
_logger.LogInformation($"Processing vote for '{voteMessage.Vote}' by '{voteMessage.VoterId}'");
|
||||
try
|
||||
{
|
||||
_data.Set(voteMessage.VoterId, voteMessage.Vote);
|
||||
_logger.LogDebug($"Succesffuly processed vote by '{voteMessage.VoterId}'");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError($"Vote processing FAILED for '{voteMessage.VoterId}', exception: {ex}");
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
14
worker/dotnet/Worker/appsettings.json
Normal file
14
worker/dotnet/Worker/appsettings.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"MessageQueue": {
|
||||
"Url": "nats://message-queue:4222"
|
||||
},
|
||||
"VoteData": {
|
||||
"ConnectionString": "Server=mysql;Port=4000;Database=votes;User=root;SslMode=None"
|
||||
},
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
Reference in New Issue
Block a user