Add .NET Core 2.1 versions

This commit is contained in:
Elton Stoneman
2018-09-21 19:23:31 +01:00
parent e3eb2dbd2a
commit 879e5bc477
86 changed files with 28610 additions and 1 deletions

16
worker/dotnet/Dockerfile Normal file
View 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 .

View File

@ -0,0 +1,7 @@
namespace Worker.Data
{
public interface IVoteData
{
void Set(string voterId, string vote);
}
}

View 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();
}
}
}

View 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; }
}
}

View 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; }
}
}

View 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;
}
}

View 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);
}
}
}

View 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);
}
}
}

View File

@ -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";
}
}

View 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();
}
}
}

View 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();
}
}
}

View 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>

View 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}");
}
}
}
}

View 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": "*"
}