Skip to content

Commit d03820a

Browse files
authored
Merge pull request #25 from NiceOneFox/develop
Sprint 2
2 parents b67b392 + b68e618 commit d03820a

40 files changed

+508
-68
lines changed

README.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,20 @@ Input parameters:
2222
* Amount of requests
2323
* Modeling time (max time)
2424
* SimulationType (Type of buffer modeling, FIFO, LIFO etc.)
25-
* Lambda (amount of flow) parameter for Poissonian flow
25+
* Lambda for devices (amount of flow) parameter for Poissonian flow
26+
* Lambda for sources
2627

2728
## Technologies
2829
- ASP .NET 6
2930
- C# 10
3031
- AutoMapper
32+
- FluentValidation
33+
- CORS
34+
- NLog
35+
36+
### For testing
37+
- NUnit
38+
- Moq
3139

3240
## Architecture
3341
N-Layer Web API

backend/ServiceSimulation/Api/Api.csproj

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,14 @@
88

99
<ItemGroup>
1010
<PackageReference Include="AutoMapper" Version="11.0.1" />
11-
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.0" />
11+
<PackageReference Include="FluentValidation" Version="10.4.0" />
12+
<PackageReference Include="FluentValidation.AspNetCore" Version="10.4.0" />
13+
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="10.4.0" />
14+
<PackageReference Include="Microsoft.AspNetCore.Cors" Version="2.2.0" />
15+
<PackageReference Include="NLog" Version="4.7.15" />
16+
<PackageReference Include="NLog.Schema" Version="4.7.15" />
17+
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
18+
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.3.1" />
1219
</ItemGroup>
1320

1421
<ItemGroup>

backend/ServiceSimulation/Api/Configuration/ApiMapperConfigurator.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Api.Entities;
22
using AutoMapper;
3-
using Bll.Domain.Entities;
3+
using Bll.Domain.Models;
44
using Bll.Domain.Interfaces;
55

66
namespace Api.Configuration;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using Microsoft.AspNetCore.Cors.Infrastructure;
2+
3+
namespace Api.Configuration;
4+
5+
public static class CorsPolicies
6+
{
7+
public static readonly (string Name, Action<CorsPolicyBuilder> ConfigurePolicy) AllowRemoteFrontendWithCredentials =
8+
(
9+
"AllowRemoteFrontendWithCredentials",
10+
builder =>
11+
{
12+
var host = Environment.GetEnvironmentVariable("REMOTE_FRONTEND_HOST");
13+
var port = Environment.GetEnvironmentVariable("REMOTE_FRONTEND_PORT");
14+
var scheme = Environment.GetEnvironmentVariable("REMOTE_FRONTEND_SCHEME");
15+
var origin = $"{scheme}://{host}:{port}";
16+
builder
17+
.WithOrigins(origin)
18+
.AllowAnyHeader()
19+
.AllowAnyMethod()
20+
.AllowCredentials();
21+
}
22+
);
23+
}

backend/ServiceSimulation/Api/Controllers/Simulation.cs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
using Api.Entities;
2-
using Api.enums;
2+
using Api.Validation;
33
using AutoMapper;
4-
using Bll.Domain.Entities;
54
using Bll.Domain.Interfaces;
5+
using Bll.Domain.Models;
6+
using FluentValidation;
67
using Microsoft.AspNetCore.Mvc;
78

89
namespace Api.Controllers;
@@ -31,6 +32,8 @@ public Simulation(ISimulationService simulationService,
3132
[HttpGet("/start")]
3233
public IActionResult Start(InputParameters parameters)
3334
{
35+
new InputParametersValidator().ValidateAndThrow(parameters);
36+
3437
_simulationService.StartSimulation(parameters);
3538
var endResultsOfModeling = _resultManager.CalculateResultsOfModeling();
3639
var apiResults = _mapper.Map<ApiResults>((endResultsOfModeling, _results));
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Microsoft.AspNetCore.Cors.Infrastructure;
2+
3+
namespace Api.Extensions;
4+
5+
public static class CorsOptionsExtensions
6+
{
7+
public static void AddPolicy(this CorsOptions options, (string Name, Action<CorsPolicyBuilder> ConfigurePolicy) arg)
8+
{
9+
options.AddPolicy(arg.Name, arg.ConfigurePolicy);
10+
}
11+
12+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using Api.Middlewares;
2+
3+
namespace Api.Extensions
4+
{
5+
public static class CustomExceptionHandlerMiddlewareExtensions
6+
{
7+
public static IApplicationBuilder UseCustomExceptionHandler(this IApplicationBuilder builder)
8+
{
9+
return builder.UseMiddleware<CustomExceptionHandlerMiddleware>();
10+
}
11+
}
12+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
using System.Net;
2+
using System.Text.Json;
3+
using FluentValidation;
4+
5+
namespace Api.Middlewares
6+
{
7+
public class CustomExceptionHandlerMiddleware
8+
{
9+
private readonly RequestDelegate _next;
10+
11+
private readonly ILogger _logger;
12+
public CustomExceptionHandlerMiddleware(RequestDelegate next,
13+
ILogger<CustomExceptionHandlerMiddleware> logger)
14+
{
15+
_next = next;
16+
_logger = logger;
17+
}
18+
19+
public async Task Invoke(HttpContext context)
20+
{
21+
try
22+
{
23+
await _next(context);
24+
}
25+
catch (Exception ex)
26+
{
27+
await HandleExceptionAsync(context, ex);
28+
}
29+
}
30+
31+
private Task HandleExceptionAsync(HttpContext context, Exception ex)
32+
{
33+
var statusCode = HttpStatusCode.InternalServerError;
34+
var result = string.Empty;
35+
36+
switch (ex)
37+
{
38+
case ValidationException validationException:
39+
statusCode = HttpStatusCode.BadRequest;
40+
result = JsonSerializer.Serialize(validationException.Errors);
41+
_logger.LogDebug(validationException.Message);
42+
break;
43+
44+
default:
45+
statusCode = HttpStatusCode.NotFound;
46+
break;
47+
48+
}
49+
context.Response.ContentType = "application/json";
50+
context.Response.StatusCode = (int)statusCode;
51+
52+
if (result == string.Empty)
53+
{
54+
result = JsonSerializer.Serialize(new { error = ex.Message });
55+
}
56+
return context.Response.WriteAsync(result);
57+
}
58+
}
59+
}

backend/ServiceSimulation/Api/Program.cs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,57 @@
11
using Api.Configuration;
2+
using Api.Extensions;
3+
using Api.Validation;
24
using Bll.Domain.Entities;
35
using Bll.Domain.Factories;
46
using Bll.Domain.Interfaces;
7+
using Bll.Domain.Models;
58
using Bll.Domain.Services;
9+
using FluentValidation;
10+
using FluentValidation.AspNetCore;
11+
using NLog.Web;
612

713
var builder = WebApplication.CreateBuilder(args);
814

9-
builder.Services.AddControllers();
15+
builder.Services.AddControllers().AddFluentValidation(fv =>
16+
{
17+
fv.RegisterValidatorsFromAssemblyContaining<InputParametersValidator>();
18+
});
19+
20+
#region Logger
21+
builder.Logging.ClearProviders();
22+
builder.Logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
23+
builder.Host.UseNLog();
24+
#endregion
1025
builder.Services.AddEndpointsApiExplorer();
1126
builder.Services.AddSwaggerGen();
1227

1328
#region servicesDI
1429
builder.Services.AddTransient<ISimulationService, SimulationService>();
1530

1631
builder.Services.AddScoped<ITimeProvider, TimeProvider>();
32+
builder.Services.AddScoped<IFlowProvider, PoissonianFlowProvider>();
33+
1734
builder.Services.AddScoped<IResults, Bll.Domain.Entities.Results>();
1835
builder.Services.AddScoped<IResultManager, ResultManager>();
19-
builder.Services.AddScoped<IResultManager, ResultManager>();
20-
//builder.Services.AddTransient<IBufferManager, StandardBufferManager>();
36+
2137
builder.Services.AddTransient<IBufferManagerFactory, BufferManagerFactory>();
2238
builder.Services.AddTransient<IDeviceManager, DeviceManager>();
2339
builder.Services.AddTransient<ISourceManager, SourceManager>();
24-
//builder.Services.AddScoped<StandardBufferManager>()
25-
// .AddScoped<IBufferManager, StandardBufferManager>(s => s.GetRequiredService<StandardBufferManager>());
2640

27-
//builder.Services.AddScoped<IBufferManager>(s =>
28-
// ActivatorUtilities.CreateInstance<StandardBufferManager>(s));
41+
builder.Services.AddTransient<IValidator<InputParameters>, InputParametersValidator>();
2942
#endregion
3043

44+
#region Mapper
3145
builder.Services.AddMapper();
46+
#endregion
47+
48+
#region CORS
49+
builder.Services.AddCors(opts =>
50+
{
51+
opts.AddPolicy(CorsPolicies.AllowRemoteFrontendWithCredentials);
52+
});
53+
#endregion
54+
3255

3356
var app = builder.Build();
3457

@@ -38,6 +61,8 @@
3861
app.UseSwaggerUI();
3962
}
4063

64+
app.UseCustomExceptionHandler();
65+
4166
app.UseHttpsRedirection();
4267

4368
app.UseAuthorization();
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
using FluentValidation;
2+
using Bll.Domain.Models;
3+
using Api.enums;
4+
5+
namespace Api.Validation
6+
{
7+
public class InputParametersValidator : AbstractValidator<InputParameters>
8+
{
9+
public InputParametersValidator()
10+
{
11+
RuleFor(p => p.NumberOfSources).NotEmpty().InclusiveBetween(1, 100);
12+
RuleFor(p => p.NumberOfDevices).NotEmpty().InclusiveBetween(1, 100);
13+
RuleFor(p => p.AmountOfRequests).NotEmpty().InclusiveBetween(1, 5000);
14+
RuleFor(p => p.BufferSize).NotEmpty().InclusiveBetween(1, 100);
15+
RuleFor(p => p.LambdaForDevice).NotEmpty().ExclusiveBetween(0, 10000);
16+
RuleFor(p => p.NumberOfSources).NotEmpty().ExclusiveBetween(0, 10000);
17+
RuleFor(p => p.ModelingTime).NotEmpty().ExclusiveBetween(0, 10000);
18+
RuleFor(p => p.BufferType).IsInEnum();
19+
}
20+
}
21+
}

0 commit comments

Comments
 (0)