Добавьте файлы проекта.

This commit is contained in:
Yevgeniy Ulyantsev 2024-02-02 17:36:06 +03:00
parent e787cd8afd
commit f034e41c07
27 changed files with 495 additions and 0 deletions

17
Data/Data.csproj Normal file
View File

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Services\Services.csproj" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,13 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Services.Tickets;
namespace Data.Extentions;
public static class ServiceCollectionExtentions
{
public static void TyAddFakeTicketRepository(this IServiceCollection services)
{
services.TryAddScoped<ITicketRepository, FakeTicketRepository>();
}
}

View File

@ -0,0 +1,21 @@
using Services.Tickets;
using Services.Tickets.Models;
namespace Data;
internal class FakeTicketRepository : ITicketRepository
{
private readonly List<LotteryTicket> _lotteryTickets = new List<LotteryTicket>();
public Task<long> AddNewTicket(LotteryTicket ticket)
{
var id =(long)Random.Shared.Next(1, 100);
ticket.Id = id;
_lotteryTickets.Add(ticket);
return Task.FromResult(id);
}
public Task<List<LotteryTicket>> GetAllTickets()
{
return Task.FromResult(_lotteryTickets);
}
}

View File

@ -0,0 +1 @@
global using NUnit.Framework;

View File

@ -0,0 +1,24 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
<PackageReference Include="NUnit.Analyzers" Version="3.6.1" />
<PackageReference Include="coverlet.collector" Version="6.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Services\Services.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,36 @@
using Services.Numbers;
using Services.Tickets;
namespace Lottery.Tests;
public class NumbersServiceTests
{
[SetUp]
public void Setup()
{
}
[Test]
public void ShouldGenerateUniqNumbers()
{
var numbersService = new NumbersService();
for (int i = 0; i < 1000; i++)
{
var t = numbersService.GetNumbers(35);
CollectionAssert.AllItemsAreUnique(t);
}
}
[Test]
public void ShouldGenerateRandomNumbers()
{
var numbersService = new NumbersService();
List<byte[]> numbers = new List<byte[]>();
for (int i = 0; i < 1000; i++)
{
numbers.Add(numbersService.GetNumbers(6));
}
CollectionAssert.AllItemsAreUnique(numbers);
}
}

View File

@ -0,0 +1,6 @@
namespace Lottery.Tickets;
public class Class1
{
}

View File

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

43
Lottery.sln Normal file
View File

@ -0,0 +1,43 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34330.188
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Services", "Services\Services.csproj", "{E53B4797-FCFE-418E-B412-E08381A144E3}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WorkerService1", "WorkerService1\WorkerService1.csproj", "{0A24B96A-7B80-486A-9546-B82FC5F99675}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Lottery.Tests", "Lottery.Tests\Lottery.Tests.csproj", "{BCBB643F-C468-4EE6-B186-6E2084B644DE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E53B4797-FCFE-418E-B412-E08381A144E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E53B4797-FCFE-418E-B412-E08381A144E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E53B4797-FCFE-418E-B412-E08381A144E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E53B4797-FCFE-418E-B412-E08381A144E3}.Release|Any CPU.Build.0 = Release|Any CPU
{1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1D5D5D3E-2D9A-4AAB-896E-E0957CD75E9A}.Release|Any CPU.Build.0 = Release|Any CPU
{0A24B96A-7B80-486A-9546-B82FC5F99675}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0A24B96A-7B80-486A-9546-B82FC5F99675}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0A24B96A-7B80-486A-9546-B82FC5F99675}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0A24B96A-7B80-486A-9546-B82FC5F99675}.Release|Any CPU.Build.0 = Release|Any CPU
{BCBB643F-C468-4EE6-B186-6E2084B644DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BCBB643F-C468-4EE6-B186-6E2084B644DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BCBB643F-C468-4EE6-B186-6E2084B644DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BCBB643F-C468-4EE6-B186-6E2084B644DE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {F98A62EA-62A5-4385-9709-B488076B1543}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Services.Tickets.Extentions;
namespace Services.Games.Extentions;
public static class ServiceCollectionExtentions
{
public static void TyAddGamesService(this IServiceCollection services)
{
services.TyAddTicketService();
services.TryAddScoped<IGameService, GameService>();
}
}

View File

@ -0,0 +1,49 @@
using Microsoft.Extensions.Logging;
using Services.Numbers;
using Services.Tickets;
using Services.Tickets.Models;
using System.Net.Sockets;
namespace Services.Games;
internal class GameService : IGameService
{
private readonly INumbersService _numbersService;
private readonly ITicketService _ticketService;
public GameService(ILogger<GameService> logger, INumbersService numbersService, ITicketService ticketService)
{
_numbersService = numbersService;
_ticketService = ticketService;
}
public async Task<List<(List<LotteryTicket> winTickets, int matches)>> GetWinnersTickets(byte[] winNumbers)
{
List<LotteryTicket> tickets = await _ticketService.GetAllTickets();
return CalculateWinners(tickets, winNumbers);
}
private List<(List<LotteryTicket> winTickets,int matches)> CalculateWinners(List<LotteryTicket> tickets, byte[] bytes)
{
List<(List<LotteryTicket> winTickets,int matches)> results = new();
for (int i = 0; i < bytes.Length; i++)
{
List<LotteryTicket> winners = new List<LotteryTicket>();
for (int j = 0; j < tickets.Count; j++)
{
if (bytes.Except(tickets[j].Numbers!).Count() == i)
{
winners.Add(tickets[j]);
tickets.RemoveAt(j);
}
}
results.Add((winners, bytes.Length - i));
}
return results;
}
public byte[] GetWinNumbers()
{
return _numbersService.GetNumbers(6);
}
}

View File

@ -0,0 +1,9 @@
using Services.Tickets.Models;
namespace Services.Games;
public interface IGameService
{
byte[] GetWinNumbers();
Task<List<(List<LotteryTicket> winTickets, int matches)>> GetWinnersTickets(byte[] winNumbers);
}

View File

@ -0,0 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
namespace Services.Numbers.Extentions;
public static class ServiceCollectionExtentions
{
public static void TyAddNumbersService(this IServiceCollection services)
{
services.TryAddScoped<INumbersService, NumbersService>();
}
}

View File

@ -0,0 +1,6 @@
namespace Services.Numbers;
public interface INumbersService
{
byte[] GetNumbers(byte count);
}

View File

@ -0,0 +1,49 @@
namespace Services.Numbers;
internal class NumbersService : INumbersService
{
public byte[] GetNumbers(byte count = 6)
{
byte[] init =
[
1,
2,
3,
4,
5,
6,
7,
8,
9,
10,
11,
12,
13,
14,
15,
16,
17,
18,
19,
20,
21,
22,
23,
24,
25,
26,
27,
28,
29,
30,
31,
32,
33,
34,
35,
36
];
Random.Shared.Shuffle(init);
return init.Take(count).ToArray();
}
}

20
Services/Services.csproj Normal file
View File

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
<PackageReference Include="Serilog" Version="3.1.1" />
</ItemGroup>
<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>Lottery.Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>
</Project>

View File

@ -0,0 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Services.Numbers.Extentions;
namespace Services.Tickets.Extentions;
public static class ServiceCollectionExtentions
{
public static void TyAddTicketService(this IServiceCollection services)
{
services.TyAddNumbersService();
services.TryAddScoped<ITicketService, TicketService>();
}
}

View File

@ -0,0 +1,8 @@
using Services.Tickets.Models;
namespace Services.Tickets;
public interface ITicketRepository
{
Task<long> AddNewTicket(LotteryTicket ticket);
Task<List<LotteryTicket>> GetAllTickets();
}

View File

@ -0,0 +1,9 @@
using Services.Tickets.Models;
namespace Services.Tickets;
public interface ITicketService
{
Task<List<LotteryTicket>> GetAllTickets();
Task<LotteryTicket> GetNewTicket();
}

View File

@ -0,0 +1,8 @@
namespace Services.Tickets.Models;
public class LotteryTicket
{
public long? Id { get; set; }
public byte[]? Numbers { get; set; }
public string? Owner { get; set; }
public string? PhoneNumber { get; set; }
}

View File

@ -0,0 +1,36 @@
using Microsoft.Extensions.Logging;
using Services.Numbers;
using Services.Tickets.Models;
namespace Services.Tickets;
internal class TicketService : ITicketService
{
private readonly ILogger<TicketService> _logger;
private readonly ITicketRepository _ticketRepository;
private readonly INumbersService _numbersService;
public TicketService(ILogger<TicketService> logger, ITicketRepository ticketRepository, INumbersService numbersService)
{
_logger = logger;
_ticketRepository = ticketRepository;
_numbersService = numbersService;
}
public Task<List<LotteryTicket>> GetAllTickets()
{
return _ticketRepository.GetAllTickets();
}
public async Task<LotteryTicket> GetNewTicket()
{
LotteryTicket ticket = new()
{
Numbers = _numbersService.GetNumbers(6)
};
var id = await _ticketRepository.AddNewTicket(ticket);
ticket.Id = id;
//_logger.LogInformation("New ticket created");
return ticket;
}
}

13
WorkerService1/Program.cs Normal file
View File

@ -0,0 +1,13 @@
using WorkerService1;
using Data.Extentions;
using Services.Tickets.Extentions;
using Services.Games.Extentions;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddHostedService<Worker>();
builder.Services.TyAddTicketService();
builder.Services.TyAddGamesService();
builder.Services.TyAddFakeTicketRepository();
var host = builder.Build();
host.Run();

View File

@ -0,0 +1,12 @@
{
"$schema": "http://json.schemastore.org/launchsettings.json",
"profiles": {
"WorkerService1": {
"commandName": "Project",
"dotnetRunMessages": true,
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}

32
WorkerService1/Worker.cs Normal file
View File

@ -0,0 +1,32 @@
using Services.Games;
using Services.Tickets;
namespace WorkerService1;
public class Worker : BackgroundService
{
private readonly ILogger<Worker> _logger;
private readonly IServiceScopeFactory _serviceScopeFactory;
public Worker(ILogger<Worker> logger, IServiceScopeFactory serviceScopeFactory)
{
_logger = logger;
_serviceScopeFactory = serviceScopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using (var scope = _serviceScopeFactory.CreateScope())
{
var ticketService = scope.ServiceProvider.GetRequiredService<ITicketService>();
for (int i = 0; i < 100000; i++)
{
var ticket = await ticketService.GetNewTicket();
}
var gameService = scope.ServiceProvider.GetRequiredService<IGameService>();
var winNumbers = gameService.GetWinNumbers();
var winners = await gameService.GetWinnersTickets(winNumbers);
}
}
}

View File

@ -0,0 +1,18 @@
<Project Sdk="Microsoft.NET.Sdk.Worker">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UserSecretsId>dotnet-WorkerService1-a5282c60-3d37-46ee-983b-990e33b39645</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Data\Data.csproj" />
<ProjectReference Include="..\Services\Services.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}

View File

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}