refactor: corrections and refinements

This commit is contained in:
Jean Gatto
2023-09-17 10:49:30 -03:00
parent bbc37743ca
commit d9e901e3c0
108 changed files with 277 additions and 240 deletions
+2 -2
View File
@@ -11,10 +11,10 @@
**/*.*proj.user
**/*.dbmdl
**/*.jfm
**/azds.yaml
**/bin
**/charts
**/docker-compose*
**/compose*
**/Dockerfile*
**/node_modules
**/npm-debug.log
@@ -22,4 +22,4 @@
**/secrets.dev.yaml
**/values.dev.yaml
LICENSE
README.md
README.md
-18
View File
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Authors>Jean Gatto (@jeangatto)</Authors>
<MaintainerEmail>jean_gatto@hotmail.com</MaintainerEmail>
@@ -18,21 +17,4 @@
<ContinuousIntegrationBuild Condition="'$(GITHUB_ACTIONS)' == 'true'">true</ContinuousIntegrationBuild>
<NoWarn>$(NoWarn);1591</NoWarn>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" />
<PackageReference Include="Roslynator.Analyzers">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
<PackageReference Include="SonarAnalyzer.CSharp">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>
+1 -3
View File
@@ -1,11 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
<CentralPackageTransitivePinningEnabled>false</CentralPackageTransitivePinningEnabled>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Ardalis.Result.FluentValidation" Version="7.1.0" />
<PackageVersion Include="Ardalis.Result" Version="7.1.0" />
@@ -54,6 +52,7 @@
<PackageVersion Include="Microsoft.Extensions.Options" Version="7.0.1" />
<PackageVersion Include="Microsoft.Extensions.Primitives" Version="7.0.0" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.19.4" />
<PackageVersion Include="MiniProfiler.AspNetCore.Mvc" Version="4.3.8" />
<PackageVersion Include="MiniProfiler.EntityFrameworkCore" Version="4.3.8" />
<PackageVersion Include="MongoDB.Bson" Version="2.21.0" />
@@ -71,5 +70,4 @@
<PackageVersion Include="xunit.runner.visualstudio" Version="2.5.0" />
<PackageVersion Include="xunit" Version="2.5.0" />
</ItemGroup>
</Project>
+6
View File
@@ -59,6 +59,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Infrastructure", "Infrastru
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Core", "Core", "{9371D508-9FCA-4AED-ABCF-AF9457E743AC}"
EndProject
Project("{E53339B2-1760-4266-BCC7-CA923CBCF16C}") = "docker-compose", "docker-compose.dcproj", "{24EF58F6-CBF8-4910-A17C-E8DE7ED96A87}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -97,6 +99,10 @@ Global
{7BA06288-8446-4099-9341-D213A835763C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7BA06288-8446-4099-9341-D213A835763C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7BA06288-8446-4099-9341-D213A835763C}.Release|Any CPU.Build.0 = Release|Any CPU
{24EF58F6-CBF8-4910-A17C-E8DE7ED96A87}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{24EF58F6-CBF8-4910-A17C-E8DE7ED96A87}.Debug|Any CPU.Build.0 = Debug|Any CPU
{24EF58F6-CBF8-4910-A17C-E8DE7ED96A87}.Release|Any CPU.ActiveCfg = Release|Any CPU
{24EF58F6-CBF8-4910-A17C-E8DE7ED96A87}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" Sdk="Microsoft.Docker.Sdk">
<PropertyGroup Label="Globals">
<ProjectVersion>2.1</ProjectVersion>
<DockerTargetOS>Linux</DockerTargetOS>
<ProjectGuid>24ef58f6-cbf8-4910-a17c-e8de7ed96a87</ProjectGuid>
<DockerLaunchAction>LaunchBrowser</DockerLaunchAction>
<DockerServiceUrl>{Scheme}://localhost:{ServicePort}/swagger</DockerServiceUrl>
<DockerServiceName>shop-webapi</DockerServiceName>
</PropertyGroup>
<ItemGroup>
<None Include="docker-compose.override.yml">
<DependentUpon>docker-compose.yml</DependentUpon>
</None>
<None Include="docker-compose.yml" />
<None Include=".dockerignore" />
</ItemGroup>
</Project>
+4 -1
View File
@@ -5,6 +5,9 @@ services:
shop-webapi:
environment:
- ASPNETCORE_ENVIRONMENT=Docker
- ASPNETCORE_URLS=http://+:80
ports:
- "80"
volumes:
- ~/.aspnet/https:/root/.aspnet/https:ro
- ~/.microsoft/usersecrets:/root/.microsoft/usersecrets:ro
- ~/.microsoft/usersecrets:/root/.microsoft/usersecrets:ro
+1 -3
View File
@@ -15,9 +15,7 @@ services:
context: .
dockerfile: src/Shop.PublicApi/Dockerfile
expose:
- 5072
ports:
- "5072:5072"
- 80
links:
- sqlserver
- mongoserver
+12
View File
@@ -0,0 +1,12 @@
{
"profiles": {
"Docker Compose": {
"nativeDebugging": true,
"commandName": "DockerCompose",
"commandVersion": "1.0",
"serviceActions": {
"shop-webapi": "StartDebugging"
}
}
}
}
@@ -35,4 +35,4 @@ public class LoggingBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest,
return response;
}
}
}
@@ -30,4 +30,4 @@ public class CreateCustomerCommand : IRequest<Result<CreatedCustomerResponse>>
[Required]
[DataType(DataType.Date)]
public DateTime DateOfBirth { get; set; }
}
}
@@ -19,4 +19,4 @@ public class CreateCustomerCommandValidator : AbstractValidator<CreateCustomerCo
.MaximumLength(254)
.EmailAddress();
}
}
}
@@ -9,4 +9,4 @@ public class DeleteCustomerCommand : IRequest<Result>
public DeleteCustomerCommand(Guid id) => Id = id;
public Guid Id { get; }
}
}
@@ -9,4 +9,4 @@ public class DeleteCustomerCommandValidator : AbstractValidator<DeleteCustomerCo
RuleFor(command => command.Id)
.NotEmpty();
}
}
}
@@ -14,4 +14,4 @@ public class UpdateCustomerCommand : IRequest<Result>
[MaxLength(200)]
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
}
}
@@ -14,4 +14,4 @@ public class UpdateCustomerCommandValidator : AbstractValidator<UpdateCustomerCo
.MaximumLength(254)
.EmailAddress();
}
}
}
@@ -67,4 +67,4 @@ public class CreateCustomerCommandHandler : IRequestHandler<CreateCustomerComman
return Result<CreatedCustomerResponse>.Success(
new CreatedCustomerResponse(customer.Id), "Successfully registered!");
}
}
}
@@ -53,4 +53,4 @@ public class DeleteCustomerCommandHandler : IRequestHandler<DeleteCustomerComman
// Returning the success message.
return Result.SuccessWithMessage("Successfully removed!");
}
}
}
@@ -64,4 +64,4 @@ public class UpdateCustomerCommandHandler : IRequestHandler<UpdateCustomerComman
// Returning the success message.
return Result.SuccessWithMessage("Updated successfully!");
}
}
}
@@ -8,4 +8,4 @@ public class CreatedCustomerResponse : IResponse
public CreatedCustomerResponse(Guid id) => Id = id;
public Guid Id { get; }
}
}
+5 -5
View File
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.Result.FluentValidation" />
<PackageReference Include="Ardalis.Result" />
@@ -12,10 +12,10 @@
<PackageReference Include="MediatR" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shop.Domain\Shop.Domain.csproj" />
<ProjectReference Include="..\Shop.Core\Shop.Core.csproj" />
</ItemGroup>
</Project>
+1 -1
View File
@@ -8,4 +8,4 @@ public sealed class CacheOptions : IAppOptions
public int AbsoluteExpirationInHours { get; private init; }
public int SlidingExpirationInSeconds { get; private init; }
}
}
@@ -19,4 +19,4 @@ public sealed class ConnectionOptions : IAppOptions
public bool CacheConnectionInMemory() =>
CacheConnection.Equals("InMemory", StringComparison.InvariantCultureIgnoreCase);
}
}
@@ -21,4 +21,4 @@ public static class AssemblyExtensions
.Where(type => type.IsClass && !type.IsAbstract && !type.IsInterface && isAssignableToTInterface(type))
.ToList();
}
}
}
@@ -18,4 +18,4 @@ public static class ConfigurationExtensions
.GetRequiredSection(TOptions.ConfigSectionPath)
.Get<TOptions>(options => options.BindNonPublicProperties = true);
}
}
}
@@ -23,4 +23,4 @@ public static class GenericTypeExtensions
// Remove the backtick and append the generic arguments to the type name
return $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>";
}
}
}
+1 -1
View File
@@ -68,4 +68,4 @@ internal sealed class PrivateConstructorContractResolver : DefaultJsonTypeInfoRe
return jsonTypeInfo;
}
}
}
@@ -18,4 +18,4 @@ public static class ServiceProviderExtensions
{
return serviceProvider.GetRequiredService<IOptions<TOptions>>().Value;
}
}
}
+1 -1
View File
@@ -13,4 +13,4 @@ public static partial class RegexPatterns
@"^([0-9a-zA-Z]([+\-_.][0-9a-zA-Z]+)*)+@(([0-9a-zA-Z][-\w]*[0-9a-zA-Z]*\.)+[a-zA-Z0-9]{2,17})$",
RegexOptions.IgnoreCase | RegexOptions.Compiled | RegexOptions.CultureInvariant)]
private static partial Regex EmailRegexPatternAttr();
}
}
+1 -1
View File
@@ -22,4 +22,4 @@ public abstract class BaseEvent : INotification
/// Gets the date and time when the event occurred.
/// </summary>
public DateTime OccurredOn { get; private init; } = DateTime.Now;
}
}
@@ -9,4 +9,4 @@ public class CorrelationIdGenerator : ICorrelationIdGenerator
public string Get() => _correlationId;
public void Set(string correlationId) => _correlationId = correlationId;
}
}
@@ -16,4 +16,4 @@ public interface ICorrelationIdGenerator
/// </summary>
/// <param name="correlationId">The correlation ID to set.</param>
void Set(string correlationId);
}
}
+1 -1
View File
@@ -36,4 +36,4 @@ public class EventStore : BaseEvent
/// Gets or sets the data.
/// </summary>
public string Data { get; private init; }
}
}
+1 -1
View File
@@ -5,4 +5,4 @@ namespace Shop.Core.SharedKernel;
/// </summary>
public interface IAggregateRoot
{
}
}
+1 -1
View File
@@ -9,4 +9,4 @@ public interface IAppOptions
/// The configuration section path.
/// </summary>
static abstract string ConfigSectionPath { get; }
}
}
+1 -1
View File
@@ -30,4 +30,4 @@ public interface ICacheService
/// <param name="cacheKeys">The keys of the items to remove from the cache.</param>
/// <returns>A task representing the asynchronous removal operation.</returns>
Task RemoveAsync(params string[] cacheKeys);
}
}
+1 -1
View File
@@ -19,4 +19,4 @@ public interface IEntity<out TKey> : IEntity where TKey : IEquatable<TKey>
/// Gets the ID of the entity.
/// </summary>
TKey Id { get; }
}
}
@@ -15,4 +15,4 @@ public interface IEventStoreRepository : IDisposable
/// <param name="eventStores">The event stores to store.</param>
/// <returns>A task representing the asynchronous operation.</returns>
Task StoreAsync(IEnumerable<EventStore> eventStores);
}
}
+1 -1
View File
@@ -2,4 +2,4 @@ namespace Shop.Core.SharedKernel;
public interface IResponse
{
}
}
+1 -1
View File
@@ -13,4 +13,4 @@ public interface IUnitOfWork : IDisposable
/// </summary>
/// <returns>A task representing the asynchronous operation.</returns>
Task SaveChangesAsync();
}
}
@@ -36,4 +36,4 @@ public interface IWriteOnlyRepository<TEntity, in TKey> : IDisposable
/// <param name="id">The ID of the entity to retrieve.</param>
/// <returns>The retrieved entity.</returns>
Task<TEntity> GetByIdAsync(TKey id);
}
}
+4 -4
View File
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="MediatR" />
<PackageReference Include="Microsoft.EntityFrameworkCore" />
@@ -22,5 +22,5 @@
<PackageReference Include="System.Configuration.ConfigurationManager" />
<PackageReference Include="System.Text.Json" />
</ItemGroup>
</Project>
@@ -85,4 +85,4 @@ public class Customer : BaseEntity, IAggregateRoot
_isDeleted = true;
AddDomainEvent(new CustomerDeletedEvent(Id, FirstName, LastName, Gender, Email.Address, DateOfBirth));
}
}
}
@@ -12,4 +12,4 @@ public enum EGender
[Description("Feminino")]
Female = 2
}
}
@@ -28,4 +28,4 @@ public abstract class CustomerBaseEvent : BaseEvent
public EGender Gender { get; private init; }
public string Email { get; private init; }
public DateTime DateOfBirth { get; private init; }
}
}
@@ -13,4 +13,4 @@ public class CustomerCreatedEvent : CustomerBaseEvent
DateTime dateOfBirth) : base(id, firstName, lastName, gender, email, dateOfBirth)
{
}
}
}
@@ -13,4 +13,4 @@ public class CustomerDeletedEvent : CustomerBaseEvent
DateTime dateOfBirth) : base(id, firstName, lastName, gender, email, dateOfBirth)
{
}
}
}
@@ -13,4 +13,4 @@ public class CustomerUpdatedEvent : CustomerBaseEvent
DateTime dateOfBirth) : base(id, firstName, lastName, gender, email, dateOfBirth)
{
}
}
}
@@ -21,4 +21,4 @@ public interface ICustomerWriteOnlyRepository : IWriteOnlyRepository<Customer, G
/// <param name="currentId">The current ID of the customer to exclude from the check.</param>
/// <returns>True if a customer with the email and current ID exists, false otherwise.</returns>
Task<bool> ExistsByEmailAsync(Email email, Guid currentId);
}
}
+1 -1
View File
@@ -23,4 +23,4 @@ public static class CustomerFactory
public static Customer Create(string firstName, string lastName, EGender gender, Email email, DateTime dateOfBirth)
=> new(firstName, lastName, gender, email, dateOfBirth);
}
}
+5 -5
View File
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.Result" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shop.Core\Shop.Core.csproj" />
</ItemGroup>
</Project>
@@ -27,4 +27,4 @@ internal static class EntityTypeBuilderExtensions
builder
.Ignore(entity => entity.DomainEvents);
}
}
}
@@ -22,4 +22,4 @@ internal static class ModelBuilderExtensions
foreach (var fk in foreignKeys)
fk.DeleteBehavior = DeleteBehavior.Restrict;
}
}
}
@@ -64,4 +64,4 @@ internal abstract class BaseWriteOnlyRepository<TEntity, Tkey> : IWriteOnlyRepos
}
#endregion
}
}
@@ -23,4 +23,4 @@ internal class CustomerWriteOnlyRepository : BaseWriteOnlyRepository<Customer, G
await Context.Customers
.AsNoTracking()
.AnyAsync(customer => customer.Email.Address == email.Address && customer.Id != currentId);
}
}
@@ -48,4 +48,4 @@ internal sealed class EventStoreRepository : IEventStoreRepository
}
#endregion
}
}
@@ -89,4 +89,4 @@ internal class DistributedCacheService : ICacheService
await _distributedCache.RemoveAsync(cacheKey);
}
}
}
}
@@ -91,4 +91,4 @@ internal class MemoryCacheService : ICacheService
return Task.CompletedTask;
}
}
}
+1 -1
View File
@@ -167,4 +167,4 @@ internal sealed class UnitOfWork : IUnitOfWork
}
#endregion
}
}
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="EntityFrameworkCore.DataEncryption" />
<PackageReference Include="MediatR" />
@@ -19,15 +19,15 @@
<PackageReference Include="MongoDB.Driver" />
<PackageReference Include="Polly" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shop.Core\Shop.Core.csproj" />
<ProjectReference Include="..\Shop.Domain\Shop.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="Shop.UnitTests" />
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
<InternalsVisibleTo Include="Shop.UnitTests" />
</ItemGroup>
</Project>
@@ -127,4 +127,4 @@ public class CustomersController : ControllerBase
[ProducesResponseType(typeof(ApiResponse), StatusCodes.Status500InternalServerError)]
public async Task<IActionResult> GetAll() =>
(await _mediator.Send(new GetAllCustomerQuery())).ToActionResult();
}
}
+12 -17
View File
@@ -1,37 +1,32 @@
# https://hub.docker.com/_/microsoft-dotnet-sdk/
ARG sdk_version=7.0-bookworm-slim
FROM mcr.microsoft.com/dotnet/aspnet:$sdk_version AS base
FROM mcr.microsoft.com/dotnet/aspnet:7.0-bookworm-slim AS base
WORKDIR /app
EXPOSE 5072
EXPOSE 80
EXPOSE 443
ENV ASPNETCORE_URLS=http://+:5072
ENV DOTNET_NOLOGO=1
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
ENV DOTNET_EnableDiagnostics=0
FROM mcr.microsoft.com/dotnet/sdk:$sdk_version AS build
ARG configuration=Release
FROM mcr.microsoft.com/dotnet/sdk:7.0-bookworm-slim AS build
WORKDIR /src
COPY ["Directory.Build.props", "src/"]
COPY ["Directory.Packages.props", "src/"]
COPY ["Directory.Packages.props", "."]
COPY ["Directory.Build.props", "."]
COPY ["nuget.config", "."]
COPY ["src/Shop.PublicApi/Shop.PublicApi.csproj", "src/Shop.PublicApi/"]
COPY ["src/Shop.Infrastructure/Shop.Infrastructure.csproj", "src/Shop.Infrastructure/"]
COPY ["src/Shop.Application/Shop.Application.csproj", "src/Shop.Application/"]
COPY ["src/Shop.Domain/Shop.Domain.csproj", "src/Shop.Domain/"]
COPY ["src/Shop.Core/Shop.Core.csproj", "src/Shop.Core/"]
COPY ["src/Shop.Application/Shop.Application.csproj", "src/Shop.Application/"]
COPY ["src/Shop.Infrastructure/Shop.Infrastructure.csproj", "src/Shop.Infrastructure/"]
COPY ["src/Shop.Query/Shop.Query.csproj", "src/Shop.Query/"]
RUN dotnet restore "src/Shop.PublicApi/Shop.PublicApi.csproj"
COPY . .
WORKDIR "/src/src/Shop.PublicApi"
RUN dotnet build "Shop.PublicApi.csproj" --configuration $configuration --no-restore --nologo --output /app/build
RUN dotnet build "Shop.PublicApi.csproj" --configuration Release --no-restore --nologo --output /app/build
FROM build AS publish
ARG configuration=Release
RUN dotnet publish "Shop.PublicApi.csproj" --configuration $configuration --no-restore --nologo --self-contained true --output /app/publish
RUN dotnet publish "Shop.PublicApi.csproj" --configuration Release --no-restore --nologo --self-contained true --output /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Shop.PublicApi.dll"]
ENTRYPOINT ["dotnet", "Shop.PublicApi.dll"]
+37
View File
@@ -0,0 +1,37 @@
# https://hub.docker.com/_/microsoft-dotnet-sdk/
ARG sdk_version=7.0-bookworm-slim
FROM mcr.microsoft.com/dotnet/aspnet:$sdk_version AS base
WORKDIR /app
EXPOSE 5072
ENV ASPNETCORE_URLS=http://+:5072
ENV DOTNET_NOLOGO=1
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
ENV DOTNET_SKIP_FIRST_TIME_EXPERIENCE=1
ENV DOTNET_EnableDiagnostics=0
FROM mcr.microsoft.com/dotnet/sdk:$sdk_version AS build
ARG configuration=Release
WORKDIR /src
COPY ["Directory.Build.props", "src/"]
COPY ["Directory.Packages.props", "src/"]
COPY ["src/Shop.PublicApi/Shop.PublicApi.csproj", "src/Shop.PublicApi/"]
COPY ["src/Shop.Infrastructure/Shop.Infrastructure.csproj", "src/Shop.Infrastructure/"]
COPY ["src/Shop.Domain/Shop.Domain.csproj", "src/Shop.Domain/"]
COPY ["src/Shop.Core/Shop.Core.csproj", "src/Shop.Core/"]
COPY ["src/Shop.Application/Shop.Application.csproj", "src/Shop.Application/"]
COPY ["src/Shop.Query/Shop.Query.csproj", "src/Shop.Query/"]
RUN dotnet restore "src/Shop.PublicApi/Shop.PublicApi.csproj"
COPY . .
WORKDIR "/src/src/Shop.PublicApi"
RUN dotnet build "Shop.PublicApi.csproj" --configuration $configuration --no-restore --nologo --output /app/build
FROM build AS publish
ARG configuration=Release
RUN dotnet publish "Shop.PublicApi.csproj" --configuration $configuration --no-restore --nologo --self-contained true --output /app/publish
FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "Shop.PublicApi.dll"]
@@ -10,4 +10,4 @@ internal static class MiddlewareExtensions
public static void UseErrorHandling(this IApplicationBuilder builder) =>
builder.UseMiddleware<ErrorHandlingMiddleware>();
}
}
@@ -55,4 +55,4 @@ internal static class ResultExtensions
return new BadRequestObjectResult(ApiResponse.BadRequest(errors));
}
}
}
}
@@ -29,18 +29,7 @@ internal static class ServicesCollectionExtensions
{
Version = "v1",
Title = "Shop (e-commerce)",
Description = "ASP.NET Core C# CQRS Event Sourcing, REST API, DDD, SOLID Principles and Clean Architecture",
Contact = new OpenApiContact
{
Name = "Jean Gatto",
Email = "jean_gatto@hotmail.com",
Url = new Uri(configuration.GetValue<string>("Urls:LinkedIn"))
},
License = new OpenApiLicense
{
Name = "MIT License",
Url = new Uri(configuration.GetValue<string>("Urls:Github"))
}
Description = "ASP.NET Core C# CQRS Event Sourcing, REST API, DDD, SOLID Principles and Clean Architecture"
});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
@@ -138,4 +127,4 @@ internal static class ServicesCollectionExtensions
optionsBuilder.EnableSensitiveDataLogging();
}
}
}
}
@@ -92,4 +92,4 @@ internal static class WebApplicationExtensions
app.Logger.LogInformation("----- MongoDB: collections were created successfully!");
}
}
}
@@ -38,4 +38,4 @@ public class CorrelationIdMiddleware
return Task.CompletedTask;
});
}
}
}
@@ -52,4 +52,4 @@ public class ErrorHandlingMiddleware
}
}
}
}
}
@@ -36,4 +36,4 @@ public partial class Initial : Migration
migrationBuilder.DropTable(
name: "Customers");
}
}
}
@@ -28,4 +28,4 @@ public partial class EventStore : Migration
migrationBuilder.DropTable(
name: "EventStores");
}
}
}
+1 -1
View File
@@ -110,4 +110,4 @@ public sealed class ApiResponse<T> : ApiResponse
public static ApiResponse<T> Ok(T result, string successMessage) =>
new() { Success = true, StatusCode = StatusCodes.Status200OK, Result = result, SuccessMessage = successMessage };
}
}
@@ -1,4 +1,47 @@
{
{
"profiles": {
"http": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"hotReloadEnabled": true,
"applicationUrl": "http://localhost:5072"
},
"https": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"dotnetRunMessages": true,
"hotReloadEnabled": true,
"applicationUrl": "https://localhost:7225;"
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"hotReloadEnabled": true
},
"Docker": {
"commandName": "Docker",
"launchBrowser": true,
"launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger",
"environmentVariables": {
"ASPNETCORE_URLS": "https://+:443;http://+:80"
},
"publishAllPorts": true,
"useSSL": true
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
@@ -7,38 +50,5 @@
"applicationUrl": "http://localhost:6452",
"sslPort": 44331
}
},
"profiles": {
"http": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"hotReloadEnabled": true,
"launchUrl": "swagger",
"applicationUrl": "http://localhost:5072",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"https": {
"commandName": "Project",
"dotnetRunMessages": true,
"launchBrowser": true,
"hotReloadEnabled": true,
"launchUrl": "swagger",
"applicationUrl": "https://localhost:7225;",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"hotReloadEnabled": true,
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
}
+10 -10
View File
@@ -1,16 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<IncludeOpenAPIAnalyzers>true</IncludeOpenAPIAnalyzers>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<DockerTargetOS>Linux</DockerTargetOS>
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<RuntimeIdentifiers>linux-arm64;linux-x64</RuntimeIdentifiers>
<PublishReadyToRun>true</PublishReadyToRun>
<PublishReadyToRunShowWarnings>true</PublishReadyToRunShowWarnings>
<UserSecretsId>7d8d0af0-7540-48a6-b160-d34c988a1ad6</UserSecretsId>
<DockerfileContext>..\..</DockerfileContext>
<DockerComposeProjectPath>..\..\docker-compose.dcproj</DockerComposeProjectPath>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.Result" />
<PackageReference Include="AspNetCore.HealthChecks.MongoDb" />
@@ -35,21 +34,22 @@
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks.EntityFrameworkCore" />
<PackageReference Include="Microsoft.Extensions.Diagnostics.HealthChecks" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" />
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" />
<PackageReference Include="MiniProfiler.EntityFrameworkCore" />
<PackageReference Include="Swashbuckle.AspNetCore" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shop.Application\Shop.Application.csproj" />
<ProjectReference Include="..\Shop.Infrastructure\Shop.Infrastructure.csproj" />
<ProjectReference Include="..\Shop.Query\Shop.Query.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
<InternalsVisibleTo Include="Shop.IntegrationTests" />
<InternalsVisibleTo Include="Shop.UnitTests" />
</ItemGroup>
</Project>
@@ -6,17 +6,13 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Urls": {
"LinkedIn": "https://www.linkedin.com/in/jeangatto/",
"Github": "https://github.com/jeangatto/ASP.NET-Core-Clean-Architecture-CQRS-Event-Sourcing/blob/main/LICENSE"
},
"ConnectionStrings": {
"SqlConnection": "",
"NoSqlConnection": "",
"CacheConnection": ""
},
"CacheOptions": {
"AbsoluteExpirationInHours": 0,
"SlidingExpirationInSeconds": 0
"AbsoluteExpirationInHours": 2,
"SlidingExpirationInSeconds": 60
}
}
@@ -6,10 +6,6 @@
"Microsoft.Hosting.Lifetime": "Information"
}
},
"Urls": {
"LinkedIn": "https://www.linkedin.com/in/jeangatto/",
"Github": "https://github.com/jeangatto/ASP.NET-Core-Clean-Architecture-CQRS-Event-Sourcing/blob/main/LICENSE"
},
"ConnectionStrings": {
"SqlConnection": "Server=sqlserver;Integrated Security=true;Initial Catalog=ShopContext;User Id=sa;Password=pMA63033n6tF;Trusted_Connection=false;MultipleActiveResultSets=true;Encrypt=True;TrustServerCertificate=True;",
"NoSqlConnection": "mongodb://mongoserver",
+1 -1
View File
@@ -19,4 +19,4 @@ public interface IQueryModel<out TKey> : IQueryModel where TKey : IEquatable<TKe
/// Gets the ID of the query model.
/// </summary>
TKey Id { get; }
}
}
@@ -25,4 +25,4 @@ public interface IReadDbContext
/// </summary>
/// <returns>A task representing the asynchronous creation of collections.</returns>
Task CreateCollectionsAsync();
}
}
@@ -9,4 +9,4 @@ public interface IReadDbMapping
/// Configures the mappings for reading from the database.
/// </summary>
void Configure();
}
}
@@ -18,4 +18,4 @@ public interface IReadOnlyRepository<TQueryModel, in TKey>
/// <param name="id">The ID of the query model.</param>
/// <returns>The task representing the asynchronous operation, returning the query model.</returns>
Task<TQueryModel> GetByIdAsync(TKey id);
}
}
@@ -27,4 +27,4 @@ public interface ISynchronizeDb
/// <returns>A task representing the asynchronous delete operation.</returns>
Task DeleteAsync<TQueryModel>(Expression<Func<TQueryModel, bool>> deleteFilter)
where TQueryModel : IQueryModel;
}
}
@@ -31,4 +31,4 @@ public class GetAllCustomerQueryHandler : IRequestHandler<GetAllCustomerQuery, R
return Result<IEnumerable<CustomerQueryModel>>.Success(
await _cacheService.GetOrCreateAsync(CacheKey, _readOnlyRepository.GetAllAsync));
}
}
}
@@ -52,4 +52,4 @@ public class GetCustomerByIdQueryHandler : IRequestHandler<GetCustomerByIdQuery,
? Result<CustomerQueryModel>.NotFound($"No customer found by Id: {request.Id}")
: Result<CustomerQueryModel>.Success(customer);
}
}
}
@@ -7,4 +7,4 @@ namespace Shop.Query.Application.Customer.Queries;
public class GetAllCustomerQuery : IRequest<Result<IEnumerable<CustomerQueryModel>>>
{
}
}
@@ -10,4 +10,4 @@ public class GetCustomerByIdQuery : IRequest<Result<CustomerQueryModel>>
public GetCustomerByIdQuery(Guid id) => Id = id;
public Guid Id { get; }
}
}
@@ -9,4 +9,4 @@ public class GetCustomerByIdQueryValidator : AbstractValidator<GetCustomerByIdQu
RuleFor(command => command.Id)
.NotEmpty();
}
}
}
@@ -144,4 +144,4 @@ public sealed class NoSqlDbContext : IReadDbContext, ISynchronizeDb
}
#endregion
}
}
+1 -1
View File
@@ -38,4 +38,4 @@ public class CustomerMap : IReadDbMapping
classMap.UnmapMember(customer => customer.FullName);
});
}
}
}
@@ -9,4 +9,4 @@ namespace Shop.Query.Data.Repositories.Abstractions;
public interface ICustomerReadOnlyRepository : IReadOnlyRepository<CustomerQueryModel, Guid>
{
Task<IEnumerable<CustomerQueryModel>> GetAllAsync();
}
}
@@ -30,4 +30,4 @@ internal abstract class BaseReadOnlyRepository<TQueryModel, Tkey> : IReadOnlyRep
/// <returns>The query model.</returns>
public async Task<TQueryModel> GetByIdAsync(Tkey id) =>
await Collection.Find(queryModel => queryModel.Id.Equals(id)).FirstOrDefaultAsync();
}
}
@@ -18,4 +18,4 @@ internal class CustomerReadOnlyRepository : BaseReadOnlyRepository<CustomerQuery
.SortBy(customer => customer.FirstName)
.ThenBy(customer => customer.DateOfBirth)
.ToListAsync();
}
}
@@ -68,4 +68,4 @@ public class CustomerEventHandler :
private void LogEvent<TEvent>(TEvent @event) where TEvent : CustomerBaseEvent =>
_logger.LogInformation("----- Triggering the event {EventName}, model: {EventModel}", typeof(TEvent).Name, @event.ToJson());
}
}
@@ -22,4 +22,4 @@ public class EventToQueryModelProfile : Profile
private static CustomerQueryModel CreateCustomerQueryModel<TEvent>(TEvent @event) where TEvent : CustomerBaseEvent =>
new(@event.Id, @event.FirstName, @event.LastName, @event.Gender.ToString(), @event.Email, @event.DateOfBirth);
}
}
@@ -33,4 +33,4 @@ public class CustomerQueryModel : IQueryModel<Guid>
public DateTime DateOfBirth { get; private init; }
public string FullName => (FirstName + " " + LastName).Trim();
}
}
+6 -6
View File
@@ -1,9 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.Result.FluentValidation" />
<PackageReference Include="Ardalis.Result" />
@@ -17,15 +17,15 @@
<PackageReference Include="MongoDB.Driver" />
<PackageReference Include="Polly" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Shop.Core\Shop.Core.csproj" />
<ProjectReference Include="..\Shop.Domain\Shop.Domain.csproj" />
</ItemGroup>
<ItemGroup>
<InternalsVisibleTo Include="DynamicProxyGenAssembly2" />
<InternalsVisibleTo Include="Shop.UnitTests" />
</ItemGroup>
</Project>
@@ -474,9 +474,6 @@ public class CustomersControllerTests : IAsyncLifetime
return new WebApplicationFactory<Program>()
.WithWebHostBuilder(hostBuilder =>
{
hostBuilder.UseSetting("Urls:LinkedIn", "https://www.linkedin.com/in/jeangatto/");
hostBuilder.UseSetting("Urls:Github", "https://github.com/jeangatto/ASP.NET-Core-Clean-Architecture-CQRS-Event-Sourcing/blob/main/LICENSE");
hostBuilder.UseSetting("ConnectionStrings:SqlConnection", "InMemory");
hostBuilder.UseSetting("ConnectionStrings:NoSqlConnection", "InMemory");
hostBuilder.UseSetting("ConnectionStrings:CacheConnection", "InMemory");
@@ -528,4 +525,4 @@ public class CustomersControllerTests : IAsyncLifetime
private static WebApplicationFactoryClientOptions CreateClientOptions() => new() { AllowAutoRedirect = false };
#endregion
}
}
@@ -7,4 +7,4 @@ internal static class FakerExtensions
{
public static Faker<T> UsePrivateConstructor<T>(this Faker<T> faker) where T : class =>
faker.CustomInstantiator(_ => Activator.CreateInstance(typeof(T), nonPublic: true) as T);
}
}
@@ -1,11 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Ardalis.Result" />
<PackageReference Include="AutoMapper" />
@@ -37,15 +37,15 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Shop.PublicApi\Shop.PublicApi.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="xunit.runner.json">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>
@@ -118,4 +118,4 @@ public class CreateCustomerCommandHandlerTests : IClassFixture<EfSqliteFixture>
act.IsSuccess.Should().BeFalse();
act.ValidationErrors.Should().NotBeNullOrEmpty().And.OnlyHaveUniqueItems();
}
}
}
@@ -108,4 +108,4 @@ public class DeleteCustomerCommandHandlerTests : IClassFixture<EfSqliteFixture>
act.IsSuccess.Should().BeFalse();
act.ValidationErrors.Should().NotBeNullOrEmpty().And.OnlyHaveUniqueItems();
}
}
}
@@ -155,4 +155,4 @@ public class UpdateCustomerCommandHandlerTest : IClassFixture<EfSqliteFixture>
act.IsSuccess.Should().BeFalse();
act.ValidationErrors.Should().NotBeNullOrEmpty().And.OnlyHaveUniqueItems();
}
}
}

Some files were not shown because too many files have changed in this diff Show More