add currency converter service and integrated it with vehicle enrollment management
This commit is contained in:
parent
5ee8c9c5df
commit
b1aceac750
@ -0,0 +1,12 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
|
||||||
|
public interface CurrencyConverterService
|
||||||
|
{
|
||||||
|
Task<decimal> ConvertAsync(decimal amount, Currency from, Currency to,
|
||||||
|
CancellationToken cancellationToken);
|
||||||
|
|
||||||
|
Task<decimal> ConvertAsync(decimal amount, Currency from, Currency to,
|
||||||
|
DateTimeOffset time, CancellationToken cancellationToken);
|
||||||
|
}
|
@ -0,0 +1,8 @@
|
|||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
|
||||||
|
public interface SessionCurrencyService
|
||||||
|
{
|
||||||
|
public Currency Currency { get; }
|
||||||
|
}
|
@ -2,6 +2,8 @@ using MediatR;
|
|||||||
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
||||||
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
using cuqmbr.TravelGuide.Application.Common.Exceptions;
|
||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
namespace cuqmbr.TravelGuide.Application.VehicleEnrollments
|
namespace cuqmbr.TravelGuide.Application.VehicleEnrollments
|
||||||
.Queries.GetVehicleEnrollment;
|
.Queries.GetVehicleEnrollment;
|
||||||
@ -12,12 +14,19 @@ public class GetVehicleEnrollmentQueryHandler :
|
|||||||
private readonly UnitOfWork _unitOfWork;
|
private readonly UnitOfWork _unitOfWork;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
private readonly SessionCurrencyService _sessionCurrencyService;
|
||||||
|
private readonly CurrencyConverterService _currencyConverterService;
|
||||||
|
|
||||||
public GetVehicleEnrollmentQueryHandler(
|
public GetVehicleEnrollmentQueryHandler(
|
||||||
UnitOfWork unitOfWork,
|
UnitOfWork unitOfWork,
|
||||||
IMapper mapper)
|
IMapper mapper,
|
||||||
|
SessionCurrencyService sessionCurrencyService,
|
||||||
|
CurrencyConverterService currencyConverterService)
|
||||||
{
|
{
|
||||||
_unitOfWork = unitOfWork;
|
_unitOfWork = unitOfWork;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
|
_sessionCurrencyService = sessionCurrencyService;
|
||||||
|
_currencyConverterService = currencyConverterService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<VehicleEnrollmentDto> Handle(
|
public async Task<VehicleEnrollmentDto> Handle(
|
||||||
@ -51,6 +60,23 @@ public class GetVehicleEnrollmentQueryHandler :
|
|||||||
.First(ra => ra.Id == rad.RouteAddressId);
|
.First(ra => ra.Id == rad.RouteAddressId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert currency
|
||||||
|
|
||||||
|
// TODO: Replace with AutoMapper Resolver
|
||||||
|
|
||||||
|
if (!_sessionCurrencyService.Currency.Equals(Currency.Default))
|
||||||
|
{
|
||||||
|
foreach (var rad in entity.RouteAddressDetails)
|
||||||
|
{
|
||||||
|
rad.CostToNextAddress = await _currencyConverterService
|
||||||
|
.ConvertAsync(rad.CostToNextAddress, entity.Currency,
|
||||||
|
_sessionCurrencyService.Currency, cancellationToken);
|
||||||
|
}
|
||||||
|
entity.Currency = _sessionCurrencyService.Currency;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
_unitOfWork.Dispose();
|
_unitOfWork.Dispose();
|
||||||
|
|
||||||
return _mapper.Map<VehicleEnrollmentDto>(entity);
|
return _mapper.Map<VehicleEnrollmentDto>(entity);
|
||||||
|
@ -3,6 +3,8 @@ using cuqmbr.TravelGuide.Application.Common.Interfaces.Persistence;
|
|||||||
using AutoMapper;
|
using AutoMapper;
|
||||||
using cuqmbr.TravelGuide.Application.Common.Models;
|
using cuqmbr.TravelGuide.Application.Common.Models;
|
||||||
using cuqmbr.TravelGuide.Application.Common.Extensions;
|
using cuqmbr.TravelGuide.Application.Common.Extensions;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
namespace cuqmbr.TravelGuide.Application.VehicleEnrollments
|
namespace cuqmbr.TravelGuide.Application.VehicleEnrollments
|
||||||
.Queries.GetVehicleEnrollmentsPage;
|
.Queries.GetVehicleEnrollmentsPage;
|
||||||
@ -13,12 +15,19 @@ public class GetVehicleEnrollmentsPageQueryHandler :
|
|||||||
private readonly UnitOfWork _unitOfWork;
|
private readonly UnitOfWork _unitOfWork;
|
||||||
private readonly IMapper _mapper;
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
private readonly SessionCurrencyService _sessionCurrencyService;
|
||||||
|
private readonly CurrencyConverterService _currencyConverterService;
|
||||||
|
|
||||||
public GetVehicleEnrollmentsPageQueryHandler(
|
public GetVehicleEnrollmentsPageQueryHandler(
|
||||||
UnitOfWork unitOfWork,
|
UnitOfWork unitOfWork,
|
||||||
IMapper mapper)
|
IMapper mapper,
|
||||||
|
SessionCurrencyService sessionCurrencyService,
|
||||||
|
CurrencyConverterService currencyConverterService)
|
||||||
{
|
{
|
||||||
_unitOfWork = unitOfWork;
|
_unitOfWork = unitOfWork;
|
||||||
_mapper = mapper;
|
_mapper = mapper;
|
||||||
|
_sessionCurrencyService = sessionCurrencyService;
|
||||||
|
_currencyConverterService = currencyConverterService;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<PaginatedList<VehicleEnrollmentDto>> Handle(
|
public async Task<PaginatedList<VehicleEnrollmentDto>> Handle(
|
||||||
@ -55,13 +64,15 @@ public class GetVehicleEnrollmentsPageQueryHandler :
|
|||||||
(request.ArrivalTimeGreaterThanOrEqual != null
|
(request.ArrivalTimeGreaterThanOrEqual != null
|
||||||
?
|
?
|
||||||
e.DepartureTime.AddSeconds(e.RouteAddressDetails
|
e.DepartureTime.AddSeconds(e.RouteAddressDetails
|
||||||
.Sum(rad => rad.TimeToNextAddress.TotalSeconds + rad.CurrentAddressStopTime.TotalSeconds)) >=
|
.Sum(rad => rad.TimeToNextAddress.TotalSeconds +
|
||||||
|
rad.CurrentAddressStopTime.TotalSeconds)) >=
|
||||||
request.ArrivalTimeGreaterThanOrEqual
|
request.ArrivalTimeGreaterThanOrEqual
|
||||||
: true) &&
|
: true) &&
|
||||||
(request.ArrivalTimeLessThanOrEqual != null
|
(request.ArrivalTimeLessThanOrEqual != null
|
||||||
?
|
?
|
||||||
e.DepartureTime.AddSeconds(e.RouteAddressDetails
|
e.DepartureTime.AddSeconds(e.RouteAddressDetails
|
||||||
.Sum(rad => rad.TimeToNextAddress.TotalSeconds + rad.CurrentAddressStopTime.TotalSeconds)) <=
|
.Sum(rad => rad.TimeToNextAddress.TotalSeconds +
|
||||||
|
rad.CurrentAddressStopTime.TotalSeconds)) <=
|
||||||
request.ArrivalTimeLessThanOrEqual
|
request.ArrivalTimeLessThanOrEqual
|
||||||
: true) &&
|
: true) &&
|
||||||
(request.TravelTimeGreaterThanOrEqual != null
|
(request.TravelTimeGreaterThanOrEqual != null
|
||||||
@ -141,6 +152,25 @@ public class GetVehicleEnrollmentsPageQueryHandler :
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Convert currency
|
||||||
|
|
||||||
|
// TODO: Replace with AutoMapper Resolver
|
||||||
|
|
||||||
|
if (!_sessionCurrencyService.Currency.Equals(Currency.Default))
|
||||||
|
{
|
||||||
|
foreach (var ve in paginatedList.Items)
|
||||||
|
{
|
||||||
|
foreach (var rad in ve.RouteAddressDetails)
|
||||||
|
{
|
||||||
|
rad.CostToNextAddress = await _currencyConverterService
|
||||||
|
.ConvertAsync(rad.CostToNextAddress, ve.Currency,
|
||||||
|
_sessionCurrencyService.Currency, cancellationToken);
|
||||||
|
}
|
||||||
|
ve.Currency = _sessionCurrencyService.Currency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
var mappedItems = _mapper
|
var mappedItems = _mapper
|
||||||
.ProjectTo<VehicleEnrollmentDto>(paginatedList.Items.AsQueryable());
|
.ProjectTo<VehicleEnrollmentDto>(paginatedList.Items.AsQueryable());
|
||||||
|
|
||||||
|
@ -11,6 +11,7 @@ using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using cuqmbr.TravelGuide.Identity.Exceptions;
|
using cuqmbr.TravelGuide.Identity.Exceptions;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
|
||||||
namespace cuqmbr.TravelGuide.Configuration.Identity;
|
namespace cuqmbr.TravelGuide.Configuration.Identity;
|
||||||
|
|
||||||
@ -38,6 +39,8 @@ public static class Configuration
|
|||||||
"ef_migrations_history",
|
"ef_migrations_history",
|
||||||
configuration.Datastore.PartitionName);
|
configuration.Datastore.PartitionName);
|
||||||
});
|
});
|
||||||
|
options.ConfigureWarnings(w => w.Ignore(
|
||||||
|
RelationalEventId.PendingModelChangesWarning));
|
||||||
});
|
});
|
||||||
|
|
||||||
services
|
services
|
||||||
|
@ -1,19 +1,21 @@
|
|||||||
// using Microsoft.Extensions.Configuration;
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
// using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
//
|
|
||||||
// namespace cuqmbr.TravelGuide.Configuration.Infrastructure;
|
namespace cuqmbr.TravelGuide.Configuration.Infrastructure;
|
||||||
//
|
|
||||||
// public static class Configuration
|
public static class Configuration
|
||||||
// {
|
{
|
||||||
// public static IServiceCollection ConfigureInfrastructure(
|
public static IServiceCollection ConfigureInfrastructure(
|
||||||
// this IServiceCollection services,
|
this IServiceCollection services)
|
||||||
// IConfiguration configuration)
|
{
|
||||||
// {
|
services
|
||||||
// services
|
.AddHttpClient();
|
||||||
// .AddIdentity(configuration)
|
|
||||||
// .AddAuthenticationWithJwt(configuration)
|
services
|
||||||
// .AddServices();
|
.AddScoped<
|
||||||
//
|
CurrencyConverterService,
|
||||||
// return services;
|
ExchangeApiCurrencyConverterService>();
|
||||||
// }
|
|
||||||
// }
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -6,6 +6,7 @@ using cuqmbr.TravelGuide.Persistence.Exceptions;
|
|||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using cuqmbr.TravelGuide.Persistence.PostgreSql;
|
using cuqmbr.TravelGuide.Persistence.PostgreSql;
|
||||||
using cuqmbr.TravelGuide.Persistence.InMemory;
|
using cuqmbr.TravelGuide.Persistence.InMemory;
|
||||||
|
using Microsoft.EntityFrameworkCore.Diagnostics;
|
||||||
|
|
||||||
namespace cuqmbr.TravelGuide.Configuration.Persistence;
|
namespace cuqmbr.TravelGuide.Configuration.Persistence;
|
||||||
|
|
||||||
@ -34,6 +35,8 @@ public static class Configuration
|
|||||||
"ef_migrations_history",
|
"ef_migrations_history",
|
||||||
configuration.PartitionName);
|
configuration.PartitionName);
|
||||||
});
|
});
|
||||||
|
options.ConfigureWarnings(w => w.Ignore(
|
||||||
|
RelationalEventId.PendingModelChangesWarning));
|
||||||
});
|
});
|
||||||
|
|
||||||
services
|
services
|
||||||
|
@ -495,13 +495,23 @@
|
|||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "ACtnvl3H3M/f8Z42980JxsNu7V9PPbzys4vBs83ZewnsgKd7JeYK18OMPo0g+MxAHrpgMrjmlinXDiaSRPcVnA=="
|
"contentHash": "ACtnvl3H3M/f8Z42980JxsNu7V9PPbzys4vBs83ZewnsgKd7JeYK18OMPo0g+MxAHrpgMrjmlinXDiaSRPcVnA=="
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Diagnostics": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "1bCSQrGv9+bpF5MGKF6THbnRFUZqQDrWPA39NDeVW9djeHBmow8kX4SX6/8KkeKI8gmUDG7jsG/bVuNAcY/ATQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.1",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
|
"contentHash": "IAucBcHYtiCmMyFag+Vrp5m+cjGRlDttJk9Vx7Dqpq+Ama4BzVUOk0JARQakgFFr7ZTBSgLKlHmtY5MiItB7Cg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
"Microsoft.Extensions.Options": "8.0.2"
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": {
|
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||||
@ -539,6 +549,19 @@
|
|||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Http": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "ezelU6HJgmq4862YoWuEbHGSV+JnfnonTSbNSJVh6n6wDehyiJn4hBtcK7rGbf2KO3QeSvK5y8E7uzn1oaRH5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Identity.Core": {
|
"Microsoft.Extensions.Identity.Core": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
@ -696,6 +719,11 @@
|
|||||||
"System.Security.Principal.Windows": "4.5.0"
|
"System.Security.Principal.Windows": "4.5.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Newtonsoft.Json": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "13.0.3",
|
||||||
|
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
|
||||||
|
},
|
||||||
"Npgsql": {
|
"Npgsql": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.3",
|
"resolved": "9.0.3",
|
||||||
@ -832,7 +860,9 @@
|
|||||||
"infrastructure": {
|
"infrastructure": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Application": "[1.0.0, )"
|
"Application": "[1.0.0, )",
|
||||||
|
"Microsoft.Extensions.Http": "[9.0.4, )",
|
||||||
|
"Newtonsoft.Json": "[13.0.3, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"persistence": {
|
"persistence": {
|
||||||
|
@ -3,16 +3,23 @@ namespace cuqmbr.TravelGuide.Domain.Enums;
|
|||||||
// Do not forget to update the schema of your database when changing
|
// Do not forget to update the schema of your database when changing
|
||||||
// this class (if you use it with a database)
|
// this class (if you use it with a database)
|
||||||
|
|
||||||
// ISO-4217 Country Codes dated 2025-03-31
|
// ISO-4217 Currency Codes dated 2025-03-31
|
||||||
|
|
||||||
public abstract class Currency : Enumeration<Currency>
|
public abstract class Currency : Enumeration<Currency>
|
||||||
{
|
{
|
||||||
|
public static readonly Currency Default = new DefaultCurrency();
|
||||||
public static readonly Currency USD = new USDCurrency();
|
public static readonly Currency USD = new USDCurrency();
|
||||||
public static readonly Currency EUR = new EURCurrency();
|
public static readonly Currency EUR = new EURCurrency();
|
||||||
public static readonly Currency UAH = new UAHCurrency();
|
public static readonly Currency UAH = new UAHCurrency();
|
||||||
|
|
||||||
protected Currency(int value, string name) : base(value, name) { }
|
protected Currency(int value, string name) : base(value, name) { }
|
||||||
|
|
||||||
|
// When no currency is specified
|
||||||
|
private sealed class DefaultCurrency : Currency
|
||||||
|
{
|
||||||
|
public DefaultCurrency() : base(Int32.MaxValue, "DEFAULT") { }
|
||||||
|
}
|
||||||
|
|
||||||
private sealed class USDCurrency : Currency
|
private sealed class USDCurrency : Currency
|
||||||
{
|
{
|
||||||
public USDCurrency() : base(840, "USD") { }
|
public USDCurrency() : base(840, "USD") { }
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AspNetCore.Localizer.Json" Version="1.0.1" />
|
<PackageReference Include="AspNetCore.Localizer.Json" Version="1.0.1" />
|
||||||
<PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="6.1.0" />
|
<!-- <PackageReference Include="MicroElements.Swashbuckle.FluentValidation" Version="6.1.0" /> -->
|
||||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
|
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.4" />
|
||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="9.0.4">
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using cuqmbr.TravelGuide.Configuration.Persistence;
|
using cuqmbr.TravelGuide.Configuration.Persistence;
|
||||||
using cuqmbr.TravelGuide.Configuration.Application;
|
using cuqmbr.TravelGuide.Configuration.Application;
|
||||||
|
using cuqmbr.TravelGuide.Configuration.Infrastructure;
|
||||||
using cuqmbr.TravelGuide.Configuration.Identity;
|
using cuqmbr.TravelGuide.Configuration.Identity;
|
||||||
using cuqmbr.TravelGuide.Configuration.Configuration;
|
using cuqmbr.TravelGuide.Configuration.Configuration;
|
||||||
using cuqmbr.TravelGuide.Configuration.Logging;
|
using cuqmbr.TravelGuide.Configuration.Logging;
|
||||||
@ -9,7 +10,7 @@ using cuqmbr.TravelGuide.HttpApi.Middlewares;
|
|||||||
using cuqmbr.TravelGuide.HttpApi.Swashbuckle.OperationFilters;
|
using cuqmbr.TravelGuide.HttpApi.Swashbuckle.OperationFilters;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using Swashbuckle.AspNetCore.SwaggerUI;
|
using Swashbuckle.AspNetCore.SwaggerUI;
|
||||||
using MicroElements.Swashbuckle.FluentValidation.AspNetCore;
|
// using MicroElements.Swashbuckle.FluentValidation.AspNetCore;
|
||||||
using Microsoft.OpenApi.Models;
|
using Microsoft.OpenApi.Models;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
@ -25,12 +26,13 @@ services.ConfigureLogging();
|
|||||||
|
|
||||||
services.ConfigurePersistence();
|
services.ConfigurePersistence();
|
||||||
services.ConfigureIdentity();
|
services.ConfigureIdentity();
|
||||||
// services.AddInfrastructure();
|
services.ConfigureInfrastructure();
|
||||||
services.ConfigureApplication();
|
services.ConfigureApplication();
|
||||||
|
|
||||||
services.AddScoped<SessionUserService, AspNetSessionUserService>();
|
services.AddScoped<SessionUserService, AspNetSessionUserService>();
|
||||||
services.AddScoped<TimeZoneService, AspNetTimeZoneService>();
|
|
||||||
services.AddScoped<CultureService, AspNetCultureService>();
|
services.AddScoped<CultureService, AspNetCultureService>();
|
||||||
|
services.AddScoped<TimeZoneService, AspNetTimeZoneService>();
|
||||||
|
services.AddScoped<SessionCurrencyService, AspNetSessionCurrencyService>();
|
||||||
|
|
||||||
services.AddControllers();
|
services.AddControllers();
|
||||||
|
|
||||||
@ -82,8 +84,18 @@ services.AddSwaggerGen(options =>
|
|||||||
"from IANA tz database (https://www.iana.org/time-zones).",
|
"from IANA tz database (https://www.iana.org/time-zones).",
|
||||||
Type = SecuritySchemeType.ApiKey
|
Type = SecuritySchemeType.ApiKey
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Set Accept-Currency header in Authorize window
|
||||||
|
options.OperationFilter<AcceptCurrencyHeaderOperationFilter>();
|
||||||
|
options.AddSecurityDefinition("Accept-Currency", new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Name = "Accept-Currency",
|
||||||
|
Description = "ISO-4217 Currency Code.",
|
||||||
|
Type = SecuritySchemeType.ApiKey
|
||||||
|
});
|
||||||
});
|
});
|
||||||
services.AddFluentValidationRulesToSwagger();
|
// services.AddFluentValidationRulesToSwagger();
|
||||||
|
|
||||||
|
|
||||||
services.AddScoped<ThreadCultureSetterMiddleware>();
|
services.AddScoped<ThreadCultureSetterMiddleware>();
|
||||||
|
38
src/HttpApi/Services/AspNetSessionCurrencyService.cs
Normal file
38
src/HttpApi/Services/AspNetSessionCurrencyService.cs
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.HttpApi.Services;
|
||||||
|
|
||||||
|
public sealed class AspNetSessionCurrencyService : SessionCurrencyService
|
||||||
|
{
|
||||||
|
private readonly HttpContext _httpContext;
|
||||||
|
|
||||||
|
public AspNetSessionCurrencyService(IHttpContextAccessor httpContextAccessor)
|
||||||
|
{
|
||||||
|
_httpContext = httpContextAccessor.HttpContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Currency Currency
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string? headerCurrencyCode =
|
||||||
|
_httpContext.Request.Headers["Accept-Currency"];
|
||||||
|
|
||||||
|
string currencyCode =
|
||||||
|
headerCurrencyCode?.ToUpper() ??
|
||||||
|
cuqmbr.TravelGuide.Domain.Enums.Currency.Default.Name;
|
||||||
|
|
||||||
|
var resultCurrency =
|
||||||
|
cuqmbr.TravelGuide.Domain.Enums.Currency.FromName(currencyCode);
|
||||||
|
|
||||||
|
if (resultCurrency == null)
|
||||||
|
{
|
||||||
|
resultCurrency =
|
||||||
|
cuqmbr.TravelGuide.Domain.Enums.Currency.Default;
|
||||||
|
}
|
||||||
|
|
||||||
|
return resultCurrency;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,39 @@
|
|||||||
|
using Microsoft.OpenApi.Models;
|
||||||
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
|
|
||||||
|
namespace cuqmbr.TravelGuide.HttpApi.Swashbuckle.OperationFilters;
|
||||||
|
|
||||||
|
public class AcceptCurrencyHeaderOperationFilter : IOperationFilter
|
||||||
|
{
|
||||||
|
public void Apply(OpenApiOperation operation, OperationFilterContext context)
|
||||||
|
{
|
||||||
|
// TODO: Remove security requirements
|
||||||
|
operation.Security ??= new List<OpenApiSecurityRequirement>();
|
||||||
|
|
||||||
|
var acceptCurrency = new OpenApiSecurityScheme
|
||||||
|
{
|
||||||
|
Reference = new OpenApiReference
|
||||||
|
{
|
||||||
|
Type = ReferenceType.SecurityScheme,
|
||||||
|
Id = "Accept-Currency"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
operation.Security.Add(new OpenApiSecurityRequirement
|
||||||
|
{
|
||||||
|
[acceptCurrency] = new List<string>()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (operation.Parameters == null)
|
||||||
|
operation.Parameters = new List<OpenApiParameter>();
|
||||||
|
|
||||||
|
operation.Parameters.Add(new OpenApiParameter
|
||||||
|
{
|
||||||
|
Name = "Accept-Currency",
|
||||||
|
Description = "ISO-4217 Currency Code.",
|
||||||
|
In = ParameterLocation.Header,
|
||||||
|
Schema = new OpenApiSchema { Type = "String" },
|
||||||
|
Required = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -13,17 +13,6 @@
|
|||||||
"Microsoft.Extensions.Localization": "9.0.0"
|
"Microsoft.Extensions.Localization": "9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"MicroElements.Swashbuckle.FluentValidation": {
|
|
||||||
"type": "Direct",
|
|
||||||
"requested": "[6.1.0, )",
|
|
||||||
"resolved": "6.1.0",
|
|
||||||
"contentHash": "VzqApLPY8xIqXDvWqRuvoDYEoCHII42c4LgvLO3BikKoIVcECD+ZSG727I7yPZ/J07VEoa8aJddoqUtSm4E4gw==",
|
|
||||||
"dependencies": {
|
|
||||||
"FluentValidation": "[10.0.0, 12.0.0)",
|
|
||||||
"MicroElements.OpenApi.FluentValidation": "6.1.0",
|
|
||||||
"Swashbuckle.AspNetCore.SwaggerGen": "[6.3.0, 8.0.0)"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Microsoft.AspNetCore.OpenApi": {
|
"Microsoft.AspNetCore.OpenApi": {
|
||||||
"type": "Direct",
|
"type": "Direct",
|
||||||
"requested": "[9.0.4, )",
|
"requested": "[9.0.4, )",
|
||||||
@ -159,17 +148,6 @@
|
|||||||
"resolved": "2.0.1",
|
"resolved": "2.0.1",
|
||||||
"contentHash": "FYv95bNT4UwcNA+G/J1oX5OpRiSUxteXaUt2BJbRSdRNiIUNbggJF69wy6mnk2wYToaanpdXZdCwVylt96MpwQ=="
|
"contentHash": "FYv95bNT4UwcNA+G/J1oX5OpRiSUxteXaUt2BJbRSdRNiIUNbggJF69wy6mnk2wYToaanpdXZdCwVylt96MpwQ=="
|
||||||
},
|
},
|
||||||
"MicroElements.OpenApi.FluentValidation": {
|
|
||||||
"type": "Transitive",
|
|
||||||
"resolved": "6.1.0",
|
|
||||||
"contentHash": "qJPAI3bL70ND6fIi4bGqQf/lpV9wUod23R7JVhVVYRonoT/ZGmPBjMbO//IPPy3yP2F21iMX05brYjyU4/WqwQ==",
|
|
||||||
"dependencies": {
|
|
||||||
"FluentValidation": "[10.0.0, 12.0.0)",
|
|
||||||
"Microsoft.AspNetCore.Http.Abstractions": "2.2.0",
|
|
||||||
"Microsoft.Extensions.Logging.Abstractions": "6.0.0",
|
|
||||||
"Microsoft.Extensions.Options": "6.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Microsoft.AspNetCore.Authentication": {
|
"Microsoft.AspNetCore.Authentication": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "2.3.0",
|
"resolved": "2.3.0",
|
||||||
@ -634,13 +612,23 @@
|
|||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "ACtnvl3H3M/f8Z42980JxsNu7V9PPbzys4vBs83ZewnsgKd7JeYK18OMPo0g+MxAHrpgMrjmlinXDiaSRPcVnA=="
|
"contentHash": "ACtnvl3H3M/f8Z42980JxsNu7V9PPbzys4vBs83ZewnsgKd7JeYK18OMPo0g+MxAHrpgMrjmlinXDiaSRPcVnA=="
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Diagnostics": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "1bCSQrGv9+bpF5MGKF6THbnRFUZqQDrWPA39NDeVW9djeHBmow8kX4SX6/8KkeKI8gmUDG7jsG/bVuNAcY/ATQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.1",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
|
"contentHash": "IAucBcHYtiCmMyFag+Vrp5m+cjGRlDttJk9Vx7Dqpq+Ama4BzVUOk0JARQakgFFr7ZTBSgLKlHmtY5MiItB7Cg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
"Microsoft.Extensions.Options": "8.0.2"
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": {
|
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||||
@ -678,6 +666,19 @@
|
|||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Http": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "ezelU6HJgmq4862YoWuEbHGSV+JnfnonTSbNSJVh6n6wDehyiJn4hBtcK7rGbf2KO3QeSvK5y8E7uzn1oaRH5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Identity.Core": {
|
"Microsoft.Extensions.Identity.Core": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
@ -873,6 +874,11 @@
|
|||||||
"System.CodeDom": "6.0.0"
|
"System.CodeDom": "6.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Newtonsoft.Json": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "13.0.3",
|
||||||
|
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
|
||||||
|
},
|
||||||
"Npgsql": {
|
"Npgsql": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.3",
|
"resolved": "9.0.3",
|
||||||
@ -1119,7 +1125,9 @@
|
|||||||
"infrastructure": {
|
"infrastructure": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Application": "[1.0.0, )"
|
"Application": "[1.0.0, )",
|
||||||
|
"Microsoft.Extensions.Http": "[9.0.4, )",
|
||||||
|
"Newtonsoft.Json": "[13.0.3, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"persistence": {
|
"persistence": {
|
||||||
|
@ -10,6 +10,11 @@
|
|||||||
<ProjectReference Include="..\Application\Application.csproj" />
|
<ProjectReference Include="..\Application\Application.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Http" Version="9.0.4" />
|
||||||
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
@ -0,0 +1,101 @@
|
|||||||
|
using System.Globalization;
|
||||||
|
using cuqmbr.TravelGuide.Application.Common.Interfaces.Services;
|
||||||
|
using cuqmbr.TravelGuide.Domain.Enums;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
// https://github.com/fawazahmed0/exchange-api
|
||||||
|
|
||||||
|
public sealed class ExchangeApiCurrencyConverterService :
|
||||||
|
CurrencyConverterService
|
||||||
|
{
|
||||||
|
private readonly
|
||||||
|
IDictionary<
|
||||||
|
DateOnly, IDictionary<
|
||||||
|
Currency, IDictionary<
|
||||||
|
Currency, decimal>>> _cache;
|
||||||
|
|
||||||
|
private const string urlFormat = "https://cdn.jsdelivr.net/" +
|
||||||
|
"npm/@fawazahmed0/currency-api@{0}/v1/currencies/{1}.json";
|
||||||
|
|
||||||
|
private readonly IHttpClientFactory _httpClientFactory;
|
||||||
|
|
||||||
|
public ExchangeApiCurrencyConverterService(
|
||||||
|
IHttpClientFactory httpClientFactory)
|
||||||
|
{
|
||||||
|
_httpClientFactory = httpClientFactory;
|
||||||
|
|
||||||
|
_cache =
|
||||||
|
new Dictionary<
|
||||||
|
DateOnly, IDictionary<
|
||||||
|
Currency, IDictionary<
|
||||||
|
Currency, decimal>>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<decimal> ConvertAsync(decimal amount, Currency from,
|
||||||
|
Currency to, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
return await ConvertAsync(amount, from, to,
|
||||||
|
DateTimeOffset.UtcNow, cancellationToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<decimal> ConvertAsync(decimal amount, Currency from,
|
||||||
|
Currency to, DateTimeOffset time, CancellationToken cancellationToken)
|
||||||
|
{
|
||||||
|
if (from.Equals(to))
|
||||||
|
{
|
||||||
|
return amount;
|
||||||
|
}
|
||||||
|
|
||||||
|
var requestDate = DateOnly.FromDateTime(time.ToUniversalTime().Date);
|
||||||
|
|
||||||
|
// Return cached value if available
|
||||||
|
if (_cache.Keys.Contains(requestDate) &&
|
||||||
|
_cache[requestDate].Keys.Contains(from) &&
|
||||||
|
_cache[requestDate][from].Keys.Contains(to))
|
||||||
|
{
|
||||||
|
return amount * _cache[requestDate][from][to];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Retreive new value from api
|
||||||
|
|
||||||
|
var httpClient = _httpClientFactory.CreateClient();
|
||||||
|
|
||||||
|
var requestDateString =
|
||||||
|
requestDate == DateOnly.FromDateTime(DateTime.UtcNow) ?
|
||||||
|
"latest" :
|
||||||
|
requestDate.ToString("yyyy-MM-dd", CultureInfo.InvariantCulture);
|
||||||
|
|
||||||
|
var url = String.Format(urlFormat,
|
||||||
|
requestDateString, from.Name.ToLower());
|
||||||
|
|
||||||
|
var jsonString =
|
||||||
|
await httpClient.GetStringAsync(url, cancellationToken);
|
||||||
|
|
||||||
|
var obj = JsonConvert.DeserializeObject<dynamic>(jsonString);
|
||||||
|
|
||||||
|
decimal rate = obj[from.Name.ToLower()][to.Name.ToLower()];
|
||||||
|
|
||||||
|
|
||||||
|
// Cache new value
|
||||||
|
|
||||||
|
if (!_cache.Keys.Contains(requestDate))
|
||||||
|
{
|
||||||
|
_cache.Add(requestDate,
|
||||||
|
new Dictionary<Currency, IDictionary<Currency, decimal>>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_cache[requestDate].Keys.Contains(from))
|
||||||
|
{
|
||||||
|
_cache[requestDate].Add(from, new Dictionary<Currency, decimal>());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_cache[requestDate][from].Keys.Contains(to))
|
||||||
|
{
|
||||||
|
_cache[requestDate][from].Add(to, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return amount * rate;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,26 @@
|
|||||||
"version": 1,
|
"version": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"net9.0": {
|
"net9.0": {
|
||||||
|
"Microsoft.Extensions.Http": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[9.0.4, )",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "ezelU6HJgmq4862YoWuEbHGSV+JnfnonTSbNSJVh6n6wDehyiJn4hBtcK7rGbf2KO3QeSvK5y8E7uzn1oaRH5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Newtonsoft.Json": {
|
||||||
|
"type": "Direct",
|
||||||
|
"requested": "[13.0.3, )",
|
||||||
|
"resolved": "13.0.3",
|
||||||
|
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
|
||||||
|
},
|
||||||
"AspNetCore.Localizer.Json": {
|
"AspNetCore.Localizer.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "1.0.1",
|
"resolved": "1.0.1",
|
||||||
@ -97,6 +117,31 @@
|
|||||||
"Microsoft.Extensions.Primitives": "9.0.0"
|
"Microsoft.Extensions.Primitives": "9.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Configuration": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "KIVBrMbItnCJDd1RF4KEaE8jZwDJcDUJW5zXpbwQ05HNYTK1GveHxHK0B3SjgDJuR48GRACXAO+BLhL8h34S7g==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Primitives": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "0LN/DiIKvBrkqp7gkF3qhGIeZk6/B63PthAHjQsxymJfIBcz0kbf4/p/t4lMgggVxZ+flRi5xvTwlpPOoZk8fg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Primitives": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Configuration.Binder": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "cdrjcl9RIcwt3ECbnpP0Gt1+pkjdW90mq5yFYy8D9qRj2NqFFcv3yDp141iEamsd9E218sGxK8WHaIOcrqgDJg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.DependencyInjection": {
|
"Microsoft.Extensions.DependencyInjection": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
@ -110,6 +155,25 @@
|
|||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "UI0TQPVkS78bFdjkTodmkH0Fe8lXv9LnhGFKgKrsgUJ5a5FVdFRcgjIkBVLbGgdRhxWirxH/8IXUtEyYJx6GQg=="
|
"contentHash": "UI0TQPVkS78bFdjkTodmkH0Fe8lXv9LnhGFKgKrsgUJ5a5FVdFRcgjIkBVLbGgdRhxWirxH/8IXUtEyYJx6GQg=="
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Diagnostics": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "1bCSQrGv9+bpF5MGKF6THbnRFUZqQDrWPA39NDeVW9djeHBmow8kX4SX6/8KkeKI8gmUDG7jsG/bVuNAcY/ATQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "IAucBcHYtiCmMyFag+Vrp5m+cjGRlDttJk9Vx7Dqpq+Ama4BzVUOk0JARQakgFFr7ZTBSgLKlHmtY5MiItB7Cg==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Localization": {
|
"Microsoft.Extensions.Localization": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.0",
|
"resolved": "9.0.0",
|
||||||
@ -153,6 +217,18 @@
|
|||||||
"Microsoft.Extensions.Primitives": "9.0.4"
|
"Microsoft.Extensions.Primitives": "9.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "aridVhAT3Ep+vsirR1pzjaOw0Jwiob6dc73VFQn2XmDfBA2X98M8YKO1GarvsXRX7gX1Aj+hj2ijMzrMHDOm0A==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Configuration.Binder": "9.0.4",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Primitives": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Primitives": {
|
"Microsoft.Extensions.Primitives": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
|
@ -497,13 +497,23 @@
|
|||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "ACtnvl3H3M/f8Z42980JxsNu7V9PPbzys4vBs83ZewnsgKd7JeYK18OMPo0g+MxAHrpgMrjmlinXDiaSRPcVnA=="
|
"contentHash": "ACtnvl3H3M/f8Z42980JxsNu7V9PPbzys4vBs83ZewnsgKd7JeYK18OMPo0g+MxAHrpgMrjmlinXDiaSRPcVnA=="
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Diagnostics": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "1bCSQrGv9+bpF5MGKF6THbnRFUZqQDrWPA39NDeVW9djeHBmow8kX4SX6/8KkeKI8gmUDG7jsG/bVuNAcY/ATQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options.ConfigurationExtensions": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
"Microsoft.Extensions.Diagnostics.Abstractions": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "8.0.1",
|
"resolved": "9.0.4",
|
||||||
"contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
|
"contentHash": "IAucBcHYtiCmMyFag+Vrp5m+cjGRlDttJk9Vx7Dqpq+Ama4BzVUOk0JARQakgFFr7ZTBSgLKlHmtY5MiItB7Cg==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
"Microsoft.Extensions.Options": "8.0.2"
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Microsoft.Extensions.FileProviders.Abstractions": {
|
"Microsoft.Extensions.FileProviders.Abstractions": {
|
||||||
@ -541,6 +551,19 @@
|
|||||||
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
"Microsoft.Extensions.Logging.Abstractions": "8.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"Microsoft.Extensions.Http": {
|
||||||
|
"type": "Transitive",
|
||||||
|
"resolved": "9.0.4",
|
||||||
|
"contentHash": "ezelU6HJgmq4862YoWuEbHGSV+JnfnonTSbNSJVh6n6wDehyiJn4hBtcK7rGbf2KO3QeSvK5y8E7uzn1oaRH5w==",
|
||||||
|
"dependencies": {
|
||||||
|
"Microsoft.Extensions.Configuration.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.DependencyInjection.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Diagnostics": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Logging.Abstractions": "9.0.4",
|
||||||
|
"Microsoft.Extensions.Options": "9.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"Microsoft.Extensions.Identity.Core": {
|
"Microsoft.Extensions.Identity.Core": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "9.0.4",
|
"resolved": "9.0.4",
|
||||||
@ -772,8 +795,8 @@
|
|||||||
},
|
},
|
||||||
"Newtonsoft.Json": {
|
"Newtonsoft.Json": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
"resolved": "13.0.1",
|
"resolved": "13.0.3",
|
||||||
"contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A=="
|
"contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
|
||||||
},
|
},
|
||||||
"Npgsql": {
|
"Npgsql": {
|
||||||
"type": "Transitive",
|
"type": "Transitive",
|
||||||
@ -1005,7 +1028,9 @@
|
|||||||
"infrastructure": {
|
"infrastructure": {
|
||||||
"type": "Project",
|
"type": "Project",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"Application": "[1.0.0, )"
|
"Application": "[1.0.0, )",
|
||||||
|
"Microsoft.Extensions.Http": "[9.0.4, )",
|
||||||
|
"Newtonsoft.Json": "[13.0.3, )"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"persistence": {
|
"persistence": {
|
||||||
|
Loading…
Reference in New Issue
Block a user