Compare commits
10 Commits
f1afd41888
...
6d28773c06
| Author | SHA1 | Date | |
|---|---|---|---|
| 6d28773c06 | |||
| d9511f29c7 | |||
| 3c012adcfd | |||
| 35f0e303a5 | |||
| 6c8dfb3170 | |||
| 1193852c1b | |||
| db0a2c4227 | |||
| 57d89c7b62 | |||
| 0ab356ddc6 | |||
| 5938f9d6a4 |
@@ -0,0 +1,6 @@
|
||||
MSSQL_SA_PASSWORD=Programmer.369
|
||||
MSSQL_PORT=1433
|
||||
REDIS_PASSWORD=Programmer.369
|
||||
REDIS_PORT=6379
|
||||
MONGO_PORT=27017
|
||||
ASPNETCORE_ENVIRONMENT=Development
|
||||
@@ -53,8 +53,9 @@
|
||||
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.21.*" />
|
||||
<PackageVersion Include="MiniProfiler.AspNetCore.Mvc" Version="4.5.*" />
|
||||
<PackageVersion Include="MiniProfiler.EntityFrameworkCore" Version="4.5.*" />
|
||||
<PackageVersion Include="MongoDB.Bson" Version="3.4.*" />
|
||||
<PackageVersion Include="MongoDB.Driver" Version="3.4.*" />
|
||||
<PackageVersion Include="MongoDB.Bson" Version="3.5.*" />
|
||||
<PackageVersion Include="MongoDB.Driver" Version="3.5.*" />
|
||||
<PackageVersion Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="9.0.4" />
|
||||
<PackageVersion Include="NSubstitute.Analyzers.CSharp" Version="1.0.*" />
|
||||
<PackageVersion Include="NSubstitute" Version="5.3.*" />
|
||||
<PackageVersion Include="Polly" Version="8.6.*" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# ASP.NET Core C# CQRS Event Sourcing, REST API, DDD, SOLID Principles and Clean Architecture
|
||||
# ASP.NET Core C# — Clean Architecture, CQRS, Event Sourcing
|
||||
|
||||
[](https://github.com/jeangatto/ASP.NET-Core-Clean-Architecture-CQRS-Event-Sourcing/actions/workflows/dotnet.yml)
|
||||
[](https://github.com/JeanGatto/ASP.NET-Core-Clean-Architecture-CQRS-Event-Sourcing/actions/workflows/sonar-cloud.yml)
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
[](https://stars.medv.io/jeangatto/ASP.NET-Core-Clean-Architecture-CQRS-Event-Sourcing)
|
||||
|
||||
About the repoitory:
|
||||
About the repository:
|
||||
Open source project written in the latest version of ASP.NET Core, implementing the concepts of S.O.L.I.D, Clean Code,
|
||||
CQRS (Command Query Responsibility Segregation)
|
||||
|
||||
@@ -32,15 +32,18 @@ If you liked this project, learned something, give it a star. Thank you!
|
||||
- Entity Framework Core 9
|
||||
- **EF Compiled Queries** (https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/ef/language-reference/compiled-queries-linq-to-entities)
|
||||
- Unit & Integration Tests + xUnit + FluentAssertions (7.1.0)
|
||||
- Polly
|
||||
- AutoMapper (15)
|
||||
- FluentValidator
|
||||
- MediatR (13)
|
||||
- xUnit (https://github.com/xunit/xunit)
|
||||
- FluentAssertions (https://github.com/fluentassertions/fluentassertions)
|
||||
- Polly (https://github.com/App-vNext/Polly)
|
||||
- AutoMapper (https://github.com/LuckyPennySoftware/AutoMapper)
|
||||
- FluentValidator (https://github.com/FluentValidation/FluentValidation)
|
||||
- MediatR (https://github.com/LuckyPennySoftware/MediatR)
|
||||
- Result (https://github.com/ardalis/Result)
|
||||
- ~~Swagger UI~~
|
||||
- OpenApi
|
||||
- **Scalar** - Interactive API Reference from OpenAPI/Swagger (https://github.com/scalar/scalar)
|
||||
- HealthChecks
|
||||
- SQL Server
|
||||
- Microsoft SQL Server
|
||||
- MongoDB
|
||||
- Redis (Cache)
|
||||
- Docker & Docker Compose
|
||||
@@ -58,7 +61,7 @@ If you liked this project, learned something, give it a star. Thank you!
|
||||
- Event Sourcing
|
||||
- Unit of Work
|
||||
- Repository Pattern
|
||||
- Resut Pattern
|
||||
- Result Pattern
|
||||
|
||||
## Running the application
|
||||
|
||||
@@ -68,10 +71,21 @@ After cloning the repository to the desired folder, run the command in the termi
|
||||
dotnet clean Shop.sln --nologo /tl && dotnet build Shop.sln --nologo /tl
|
||||
```
|
||||
|
||||
Set passwords in the `.env` file:
|
||||
|
||||
```yaml
|
||||
MSSQL_SA_PASSWORD=YOUR_STRONG_!Passw0rd
|
||||
REDIS_PASSWORD=YOUR_STRONG_!Passw0rd
|
||||
MSSQL_PORT=1433
|
||||
MONGO_PORT=27017
|
||||
REDIS_PORT=6379
|
||||
ASPNETCORE_ENVIRONMENT=Development
|
||||
```
|
||||
|
||||
Next step, run the command in the terminal:
|
||||
|
||||
```csharp
|
||||
docker-compose up --build --abort-on-container-exit --remove-orphans
|
||||
docker-compose up --build
|
||||
```
|
||||
|
||||
Now just open the url in the browser:
|
||||
|
||||
@@ -35,6 +35,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
|
||||
nuget.config = nuget.config
|
||||
README.md = README.md
|
||||
requests.http = requests.http
|
||||
.env = .env
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shop.Query", "src\Shop.Query\Shop.Query.csproj", "{C2A82AAD-0348-4B29-B7E7-E36509EE068C}"
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
services:
|
||||
shop-webapi:
|
||||
environment:
|
||||
- ASPNETCORE_ENVIRONMENT=Docker
|
||||
- ASPNETCORE_URLS=http://+:80
|
||||
ports:
|
||||
- "80"
|
||||
shop-api:
|
||||
volumes:
|
||||
- ~/.aspnet/https:/root/.aspnet/https:ro
|
||||
- ~/.microsoft/usersecrets:/root/.microsoft/usersecrets:ro
|
||||
|
||||
+83
-69
@@ -1,80 +1,94 @@
|
||||
networks:
|
||||
app-network:
|
||||
driver: bridge
|
||||
|
||||
services:
|
||||
# ASP.NET Core Web API Application
|
||||
shop-webapi:
|
||||
image: ${DOCKER_REGISTRY-}shop-webapi
|
||||
container_name: shop-webapi
|
||||
restart: always
|
||||
# Microsoft SQL Server
|
||||
# https://hub.docker.com/r/microsoft/mssql-server/
|
||||
shop-sql-server:
|
||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||
restart: unless-stopped
|
||||
environment:
|
||||
ACCEPT_EULA: "Y"
|
||||
MSSQL_SA_PASSWORD: ${MSSQL_SA_PASSWORD}
|
||||
MSSQL_PID: Express
|
||||
MSSQL_COLLATION: SQL_Latin1_General_CP1_CI_AS
|
||||
ports:
|
||||
- "${MSSQL_PORT}:${MSSQL_PORT}"
|
||||
volumes:
|
||||
- sql_data:/var/opt/mssql
|
||||
networks:
|
||||
- shop-network
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# MongoDB
|
||||
# https://hub.docker.com/_/mongo/
|
||||
shop-mongo-server:
|
||||
image: mongo:latest
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${MONGO_PORT}:${MONGO_PORT}"
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
networks:
|
||||
- shop-network
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# Redis Cache
|
||||
# https://hub.docker.com/_/redis/
|
||||
shop-redis-server:
|
||||
image: redis:latest
|
||||
restart: unless-stopped
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD}
|
||||
ports:
|
||||
- "${REDIS_PORT}:${REDIS_PORT}"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
networks:
|
||||
- shop-network
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
# Shop API Container (NET Core)
|
||||
shop-api:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: src/Shop.PublicApi/Dockerfile
|
||||
expose:
|
||||
- 80
|
||||
links:
|
||||
- shop-sql-server
|
||||
- shop-mongo-server
|
||||
- shop-redis
|
||||
networks:
|
||||
- app-network
|
||||
image: shop-api:latest
|
||||
restart: on-failure
|
||||
env_file:
|
||||
- ./.env
|
||||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: ${ASPNETCORE_ENVIRONMENT}
|
||||
ConnectionStrings__SqlConnection: "Server=shop-sql-server,1433;Database=ShopContext;User Id=sa;Password=${MSSQL_SA_PASSWORD};TrustServerCertificate=True;"
|
||||
ConnectionStrings__NoSqlConnection: "mongodb://shop-mongo-server:27017"
|
||||
ConnectionStrings__CacheConnection: "shop-redis-server:6379,password=${REDIS_PASSWORD},abortConnect=false"
|
||||
ports:
|
||||
- "5000:80"
|
||||
depends_on:
|
||||
- shop-sql-server
|
||||
- shop-mongo-server
|
||||
- shop-redis
|
||||
|
||||
# SQL Server
|
||||
shop-sql-server:
|
||||
image: mcr.microsoft.com/azure-sql-edge:latest
|
||||
cap_add: ["SYS_PTRACE"]
|
||||
hostname: mssql
|
||||
container_name: shop-sql-server
|
||||
restart: always
|
||||
expose:
|
||||
- 1433
|
||||
ports:
|
||||
- "1433:1433"
|
||||
environment:
|
||||
- ACCEPT_EULA=Y
|
||||
- MSSQL_SA_PASSWORD=${MSSQL_SA_PASSWORD}
|
||||
- MSSQL_PID=Developer
|
||||
- MSSQL_COLLATION=Latin1_General_CI_AI
|
||||
- shop-redis-server
|
||||
networks:
|
||||
- app-network
|
||||
volumes:
|
||||
- "./data-mssql:/var/opt/mssql/data"
|
||||
|
||||
# MongoDB Server
|
||||
shop-mongo-server:
|
||||
image: mongo:latest
|
||||
container_name: shop-mongo-server
|
||||
restart: always
|
||||
expose:
|
||||
- 27017
|
||||
ports:
|
||||
- "27017:27017"
|
||||
networks:
|
||||
- app-network
|
||||
|
||||
# Redis Cache Server
|
||||
shop-redis:
|
||||
image: redis:latest
|
||||
container_name: shop-redis
|
||||
command: redis-server --requirepass ${REDIS_PASSWORD}
|
||||
restart: always
|
||||
expose:
|
||||
- 6379
|
||||
ports:
|
||||
- "6379:6379"
|
||||
networks:
|
||||
- app-network
|
||||
volumes:
|
||||
- "./data-mongo:/data/db"
|
||||
- shop-network
|
||||
logging:
|
||||
driver: "json-file"
|
||||
options:
|
||||
max-size: "10m"
|
||||
max-file: "3"
|
||||
|
||||
volumes:
|
||||
data-mssql:
|
||||
external: true
|
||||
sql_data:
|
||||
redis_data:
|
||||
mongo_data:
|
||||
|
||||
data-mongo:
|
||||
external: true
|
||||
networks:
|
||||
shop-network:
|
||||
driver: bridge
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"sdk": {
|
||||
"version": "9.0.304",
|
||||
"version": "9.0.305",
|
||||
"rollForward": "latestMajor",
|
||||
"allowPrerelease": false
|
||||
}
|
||||
|
||||
@@ -8,8 +8,11 @@ public sealed class ConnectionOptions : IAppOptions
|
||||
{
|
||||
static string IAppOptions.ConfigSectionPath => "ConnectionStrings";
|
||||
|
||||
// [Required]
|
||||
// public string SqlConnection { get; private init; }
|
||||
|
||||
[Required]
|
||||
public string SqlConnection { get; private init; }
|
||||
public string PostgresConnection { get; private init; }
|
||||
|
||||
[Required]
|
||||
public string NoSqlConnection { get; private init; }
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using Shop.Core.JsonResolvers;
|
||||
|
||||
namespace Shop.Core.Extensions;
|
||||
|
||||
@@ -45,28 +44,3 @@ public static class JsonExtensions
|
||||
return jsonSettings;
|
||||
}
|
||||
}
|
||||
|
||||
internal sealed class PrivateConstructorContractResolver : DefaultJsonTypeInfoResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON type information for the specified type, with support for creating objects with private constructors.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to get the JSON type information for.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use for serialization.</param>
|
||||
/// <returns>The JSON type information for the specified type.</returns>
|
||||
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
|
||||
{
|
||||
var jsonTypeInfo = base.GetTypeInfo(type, options);
|
||||
|
||||
// Check if the type is an object, has no public constructor, and CreateObject is not already set
|
||||
if (jsonTypeInfo.Kind == JsonTypeInfoKind.Object
|
||||
&& jsonTypeInfo.CreateObject is null
|
||||
&& jsonTypeInfo.Type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Length == 0)
|
||||
{
|
||||
// Set CreateObject to a lambda expression that creates an instance using a private constructor
|
||||
jsonTypeInfo.CreateObject = () => Activator.CreateInstance(jsonTypeInfo.Type, true);
|
||||
}
|
||||
|
||||
return jsonTypeInfo;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
|
||||
namespace Shop.Core.JsonResolvers;
|
||||
|
||||
public sealed class PrivateConstructorContractResolver : DefaultJsonTypeInfoResolver
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the JSON type information for the specified type, with support for creating objects with private constructors.
|
||||
/// </summary>
|
||||
/// <param name="type">The type to get the JSON type information for.</param>
|
||||
/// <param name="options">The <see cref="JsonSerializerOptions"/> to use for serialization.</param>
|
||||
/// <returns>The JSON type information for the specified type.</returns>
|
||||
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
|
||||
{
|
||||
var jsonTypeInfo = base.GetTypeInfo(type, options);
|
||||
|
||||
// Check if the type is an object, has no public constructor, and CreateObject is not already set
|
||||
if (jsonTypeInfo.Kind == JsonTypeInfoKind.Object
|
||||
&& jsonTypeInfo.CreateObject is null
|
||||
&& jsonTypeInfo.Type.GetConstructors(BindingFlags.Public | BindingFlags.Instance).Length == 0)
|
||||
{
|
||||
// Set CreateObject to a lambda expression that creates an instance using a private constructor
|
||||
jsonTypeInfo.CreateObject = () => Activator.CreateInstance(jsonTypeInfo.Type, true);
|
||||
}
|
||||
|
||||
return jsonTypeInfo;
|
||||
}
|
||||
}
|
||||
@@ -7,7 +7,7 @@ namespace Shop.Infrastructure.Data.Context;
|
||||
public abstract class BaseDbContext<TContext>(DbContextOptions<TContext> dbOptions) : DbContext(dbOptions)
|
||||
where TContext : DbContext
|
||||
{
|
||||
private const string Collation = "Latin1_General_CI_AI";
|
||||
//private const string Collation = "en_US.UTF-8";
|
||||
|
||||
public override ChangeTracker ChangeTracker
|
||||
{
|
||||
@@ -33,7 +33,7 @@ public abstract class BaseDbContext<TContext>(DbContextOptions<TContext> dbOptio
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder
|
||||
.UseCollation(Collation)
|
||||
// .UseCollation(Collation)
|
||||
.RemoveCascadeDeleteConvention();
|
||||
|
||||
base.OnModelCreating(modelBuilder);
|
||||
|
||||
@@ -26,5 +26,8 @@ internal static class EntityTypeBuilderExtensions
|
||||
// Ignores the DomainEvents property for the entity.
|
||||
builder
|
||||
.Ignore(entity => entity.DomainEvents);
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
namespace Shop.Infrastructure.Data.Extensions;
|
||||
|
||||
@@ -21,5 +23,27 @@ internal static class ModelBuilderExtensions
|
||||
// Change the delete behavior of each foreign key to restrict
|
||||
foreach (var fk in foreignKeys)
|
||||
fk.DeleteBehavior = DeleteBehavior.Restrict;
|
||||
|
||||
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
|
||||
{
|
||||
foreach (var property in entityType.GetProperties())
|
||||
{
|
||||
if (property.ClrType == typeof(DateTime))
|
||||
{
|
||||
property.SetValueConverter(new ValueConverter<DateTime, DateTime>(
|
||||
v => v.Kind == DateTimeKind.Utc ? v : v.ToUniversalTime(),
|
||||
v => DateTime.SpecifyKind(v, DateTimeKind.Utc)
|
||||
));
|
||||
}
|
||||
|
||||
else if (property.ClrType == typeof(DateTime?))
|
||||
{
|
||||
property.SetValueConverter(new ValueConverter<DateTime?, DateTime?>(
|
||||
v => v.HasValue ? (v.Value.Kind == DateTimeKind.Utc ? v : v.Value.ToUniversalTime()) : v,
|
||||
v => v.HasValue ? DateTime.SpecifyKind(v.Value, DateTimeKind.Utc) : v
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,10 +33,13 @@ internal sealed class UnitOfWork(
|
||||
|
||||
logger.LogInformation("----- Begin transaction: '{TransactionId}'", transaction.TransactionId);
|
||||
|
||||
IReadOnlyList<BaseEvent> domainEvents = Array.Empty<BaseEvent>();
|
||||
IReadOnlyList<EventStore> eventStores = Array.Empty<EventStore>();
|
||||
|
||||
try
|
||||
{
|
||||
// Getting the domain events and event stores from the tracked entities in the EF Core context.
|
||||
var (domainEvents, eventStores) = BeforeSaveChanges();
|
||||
(domainEvents, eventStores) = BeforeSaveChanges();
|
||||
|
||||
var rowsAffected = await writeDbContext.SaveChangesAsync();
|
||||
|
||||
@@ -44,8 +47,7 @@ internal sealed class UnitOfWork(
|
||||
|
||||
await transaction.CommitAsync();
|
||||
|
||||
// Triggering the events and saving the stores.
|
||||
await AfterSaveChangesAsync(domainEvents, eventStores);
|
||||
|
||||
|
||||
logger.LogInformation(
|
||||
"----- Transaction successfully confirmed: '{TransactionId}', Rows Affected: {RowsAffected}",
|
||||
@@ -64,6 +66,9 @@ internal sealed class UnitOfWork(
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
// Triggering the events and saving the stores.
|
||||
await AfterSaveChangesAsync(domainEvents, eventStores);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:9.0-bookworm-slim AS base
|
||||
WORKDIR /app
|
||||
EXPOSE 80
|
||||
|
||||
EXPOSE 80
|
||||
ENV ASPNETCORE_URLS=http://+:80
|
||||
|
||||
# Specifies whether .NET welcome and telemetry messages are displayed on the first run.
|
||||
@@ -10,6 +10,9 @@ ENV DOTNET_NOLOGO=1
|
||||
# Specifies whether data about the .NET tools usage is collected and sent to Microsoft.
|
||||
ENV DOTNET_CLI_TELEMETRY_OPTOUT=1
|
||||
|
||||
# Defines the build configuration to use at build time. The default is 'Release'
|
||||
ARG BUILD_CONFIGURATION=Release
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/sdk:9.0-bookworm-slim AS build
|
||||
WORKDIR /src
|
||||
COPY ["Directory.Packages.props", "."]
|
||||
@@ -24,10 +27,10 @@ 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 Release --no-restore --nologo --output /app/build
|
||||
RUN dotnet build "Shop.PublicApi.csproj" --configuration $BUILD_CONFIGURATION --no-restore --nologo --output /app/build
|
||||
|
||||
FROM build AS publish
|
||||
RUN dotnet publish "Shop.PublicApi.csproj" --configuration Release --no-restore --nologo --output /app/publish
|
||||
RUN dotnet publish "Shop.PublicApi.csproj" --configuration $BUILD_CONFIGURATION --no-restore --nologo --output /app/publish
|
||||
|
||||
FROM base AS final
|
||||
WORKDIR /app
|
||||
|
||||
@@ -29,16 +29,16 @@ internal static class ServicesCollectionExtensions
|
||||
|
||||
public static IServiceCollection AddHealthChecks(this IServiceCollection services, IConfiguration configuration)
|
||||
{
|
||||
var options = configuration.GetOptions<ConnectionOptions>();
|
||||
var connectionOptions = configuration.GetOptions<ConnectionOptions>();
|
||||
|
||||
var healthCheckBuilder = services
|
||||
.AddHealthChecks()
|
||||
.AddDbContextCheck<WriteDbContext>(tags: DbRelationalTags)
|
||||
.AddDbContextCheck<EventStoreDbContext>(tags: DbRelationalTags)
|
||||
.AddMongoDb(clientFactory: _ => new MongoClient(options.NoSqlConnection), tags: DbNoSqlTags);
|
||||
.AddMongoDb(clientFactory: _ => new MongoClient(connectionOptions.NoSqlConnection), tags: DbNoSqlTags);
|
||||
|
||||
if (!options.CacheConnectionInMemory())
|
||||
healthCheckBuilder.AddRedis(options.CacheConnection);
|
||||
if (!connectionOptions.CacheConnectionInMemory())
|
||||
healthCheckBuilder.AddRedis(connectionOptions.CacheConnection);
|
||||
|
||||
return services;
|
||||
}
|
||||
@@ -48,12 +48,10 @@ internal static class ServicesCollectionExtensions
|
||||
if (!environment.IsEnvironment(TestingEnvironmentName))
|
||||
{
|
||||
services.AddDbContextPool<WriteDbContext>((serviceProvider, optionsBuilder) =>
|
||||
ConfigureDbContext<WriteDbContext>(
|
||||
serviceProvider, optionsBuilder, QueryTrackingBehavior.TrackAll));
|
||||
ConfigureDbContext<WriteDbContext>(serviceProvider, optionsBuilder, QueryTrackingBehavior.TrackAll));
|
||||
|
||||
services.AddDbContextPool<EventStoreDbContext>((serviceProvider, optionsBuilder) =>
|
||||
ConfigureDbContext<EventStoreDbContext>(
|
||||
serviceProvider, optionsBuilder, QueryTrackingBehavior.NoTrackingWithIdentityResolution));
|
||||
ConfigureDbContext<EventStoreDbContext>(serviceProvider, optionsBuilder, QueryTrackingBehavior.NoTrackingWithIdentityResolution));
|
||||
}
|
||||
|
||||
return services;
|
||||
@@ -85,13 +83,13 @@ internal static class ServicesCollectionExtensions
|
||||
DbContextOptionsBuilder optionsBuilder,
|
||||
QueryTrackingBehavior queryTrackingBehavior) where TDbContext : DbContext
|
||||
{
|
||||
var connectionOptions = serviceProvider.GetOptions<ConnectionOptions>();
|
||||
var logger = serviceProvider.GetRequiredService<ILogger<TDbContext>>();
|
||||
var options = serviceProvider.GetOptions<ConnectionOptions>();
|
||||
var environment = serviceProvider.GetRequiredService<IHostEnvironment>();
|
||||
var envIsDevelopment = environment.IsDevelopment();
|
||||
|
||||
optionsBuilder
|
||||
.UseSqlServer(options.SqlConnection, sqlServerOptions =>
|
||||
.UseNpgsql(connectionOptions.PostgresConnection, sqlServerOptions =>
|
||||
{
|
||||
sqlServerOptions
|
||||
.MigrationsAssembly(DbMigrationAssemblyName)
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
@@ -12,7 +13,7 @@ namespace Shop.PublicApi.Extensions;
|
||||
|
||||
internal static class WebApplicationExtensions
|
||||
{
|
||||
public static async Task RunAppAsync(this WebApplication app)
|
||||
public static async Task ConfigureAndRunAppAsync(this WebApplication app)
|
||||
{
|
||||
await using var serviceScope = app.Services.CreateAsyncScope();
|
||||
|
||||
@@ -62,8 +63,20 @@ internal static class WebApplicationExtensions
|
||||
|
||||
app.Logger.LogInformation("----- {DbName}: checking if there are any pending migrations...", dbName);
|
||||
|
||||
var allMigrations = dbContext.Database.GetMigrations();
|
||||
|
||||
app.Logger.LogInformation("----- {DbName}: {MigrationsCount} migrations were found", dbName, allMigrations.Count());
|
||||
|
||||
var appliedMigrations = await dbContext.Database.GetAppliedMigrationsAsync();
|
||||
|
||||
app.Logger.LogInformation("----- {DbName}: {AppliedMigrationsCount} applied migrations were found", dbName, appliedMigrations.Count());
|
||||
|
||||
var pendingMigrations = allMigrations.Except(appliedMigrations).ToList();
|
||||
|
||||
app.Logger.LogInformation("----- {DbName}: {PendingMigrationsCount} pending migrations were found", dbName, pendingMigrations.Count);
|
||||
|
||||
// Check if there are any pending migrations for the context.
|
||||
if (dbContext.Database.HasPendingModelChanges())
|
||||
if (pendingMigrations.Count > 0)
|
||||
{
|
||||
app.Logger.LogInformation("----- {DbName}: creating and migrating the database...", dbName);
|
||||
|
||||
|
||||
@@ -1,89 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Shop.Infrastructure.Data.Context;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations
|
||||
{
|
||||
[DbContext(typeof(WriteDbContext))]
|
||||
[Migration("20230207164309_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Latin1_General_CI_AI")
|
||||
.HasAnnotation("ProductVersion", "7.0.2")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Shop.Domain.Entities.Customer.Customer", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<DateTime>("DateOfBirth")
|
||||
.HasColumnType("DATE");
|
||||
|
||||
b.Property<string>("FirstName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasMaxLength(6)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(6)");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("Customers");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("Shop.Domain.Entities.Customer.Customer", b =>
|
||||
{
|
||||
b.OwnsOne("Shop.Domain.ValueObjects.Email", "Email", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CustomerId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b1.Property<string>("Address")
|
||||
.IsRequired()
|
||||
.HasMaxLength(254)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(254)")
|
||||
.HasColumnName("Email");
|
||||
|
||||
b1.HasKey("CustomerId");
|
||||
|
||||
b1.HasIndex("Address")
|
||||
.IsUnique()
|
||||
.HasFilter("[Email] IS NOT NULL");
|
||||
|
||||
b1.ToTable("Customers");
|
||||
|
||||
b1.WithOwner()
|
||||
.HasForeignKey("CustomerId");
|
||||
});
|
||||
|
||||
b.Navigation("Email");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Shop.PublicApi.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Customers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
FirstName = table.Column<string>(type: "varchar(100)", unicode: false, maxLength: 100, nullable: false),
|
||||
LastName = table.Column<string>(type: "varchar(100)", unicode: false, maxLength: 100, nullable: false),
|
||||
Gender = table.Column<string>(type: "varchar(6)", unicode: false, maxLength: 6, nullable: false),
|
||||
Email = table.Column<string>(type: "varchar(254)", unicode: false, maxLength: 254, nullable: true),
|
||||
DateOfBirth = table.Column<DateTime>(type: "DATE", nullable: false)
|
||||
},
|
||||
constraints: table => table.PrimaryKey("PK_Customers", x => x.Id));
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Customers_Email",
|
||||
table: "Customers",
|
||||
column: "Email",
|
||||
unique: true,
|
||||
filter: "[Email] IS NOT NULL");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Customers");
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class EF_Update : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Gender",
|
||||
table: "Customers",
|
||||
type: "nvarchar(6)",
|
||||
maxLength: 6,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(6)",
|
||||
oldUnicode: false,
|
||||
oldMaxLength: 6);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Gender",
|
||||
table: "Customers",
|
||||
type: "varchar(6)",
|
||||
unicode: false,
|
||||
maxLength: 6,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "nvarchar(6)",
|
||||
oldMaxLength: 6);
|
||||
}
|
||||
}
|
||||
+13
-15
@@ -2,9 +2,9 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Shop.Infrastructure.Data.Context;
|
||||
|
||||
#nullable disable
|
||||
@@ -12,24 +12,23 @@ using Shop.Infrastructure.Data.Context;
|
||||
namespace Shop.PublicApi.Migrations
|
||||
{
|
||||
[DbContext(typeof(WriteDbContext))]
|
||||
[Migration("20241128202054_EF_Update")]
|
||||
partial class EF_Update
|
||||
[Migration("20250924110748_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Latin1_General_CI_AI")
|
||||
.HasAnnotation("ProductVersion", "9.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Shop.Domain.Entities.CustomerAggregate.Customer", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("DateOfBirth")
|
||||
.HasColumnType("DATE");
|
||||
@@ -38,18 +37,18 @@ namespace Shop.PublicApi.Migrations
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasMaxLength(6)
|
||||
.HasColumnType("nvarchar(6)");
|
||||
.HasColumnType("character varying(6)");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
@@ -61,20 +60,19 @@ namespace Shop.PublicApi.Migrations
|
||||
b.OwnsOne("Shop.Domain.ValueObjects.Email", "Email", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CustomerId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("Address")
|
||||
.IsRequired()
|
||||
.HasMaxLength(254)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(254)")
|
||||
.HasColumnType("character varying(254)")
|
||||
.HasColumnName("Email");
|
||||
|
||||
b1.HasKey("CustomerId");
|
||||
|
||||
b1.HasIndex("Address")
|
||||
.IsUnique()
|
||||
.HasFilter("[Email] IS NOT NULL");
|
||||
.IsUnique();
|
||||
|
||||
b1.ToTable("Customers");
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "Customers",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
FirstName = table.Column<string>(type: "character varying(100)", unicode: false, maxLength: 100, nullable: false),
|
||||
LastName = table.Column<string>(type: "character varying(100)", unicode: false, maxLength: 100, nullable: false),
|
||||
Gender = table.Column<string>(type: "character varying(6)", maxLength: 6, nullable: false),
|
||||
Email = table.Column<string>(type: "character varying(254)", unicode: false, maxLength: 254, nullable: true),
|
||||
DateOfBirth = table.Column<DateTime>(type: "DATE", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_Customers", x => x.Id);
|
||||
});
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_Customers_Email",
|
||||
table: "Customers",
|
||||
column: "Email",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "Customers");
|
||||
}
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Shop.Infrastructure.Data.Context;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations.EventStoreDb
|
||||
{
|
||||
[DbContext(typeof(EventStoreDbContext))]
|
||||
[Migration("20230226145437_EventStore")]
|
||||
partial class EventStore
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Latin1_General_CI_AI")
|
||||
.HasAnnotation("ProductVersion", "7.0.3")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Shop.Core.Events.EventStore", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<Guid>("AggregateId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("VARCHAR(MAX)")
|
||||
.HasComment("JSON serialized event");
|
||||
|
||||
b.Property<string>("MessageType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnName("CreatedAt");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.ToTable("EventStores");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
namespace Shop.PublicApi.Migrations.EventStoreDb;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class EventStore : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "EventStores",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
Data = table.Column<string>(type: "VARCHAR(MAX)", unicode: false, nullable: false, comment: "JSON serialized event"),
|
||||
MessageType = table.Column<string>(type: "varchar(100)", unicode: false, maxLength: 100, nullable: false),
|
||||
AggregateId = table.Column<Guid>(type: "uniqueidentifier", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "datetime2", nullable: false)
|
||||
},
|
||||
constraints: table => table.PrimaryKey("PK_EventStores", x => x.Id));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "EventStores");
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations.EventStoreDb;
|
||||
|
||||
/// <inheritdoc />
|
||||
public partial class EF_Update : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Data",
|
||||
table: "EventStores",
|
||||
type: "varchar(255)",
|
||||
unicode: false,
|
||||
maxLength: 255,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "VARCHAR(MAX)",
|
||||
oldUnicode: false,
|
||||
comment: "JSON serialized event",
|
||||
oldComment: "JSON serialized event");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AlterColumn<string>(
|
||||
name: "Data",
|
||||
table: "EventStores",
|
||||
type: "VARCHAR(MAX)",
|
||||
unicode: false,
|
||||
nullable: false,
|
||||
oldClrType: typeof(string),
|
||||
oldType: "varchar(255)",
|
||||
oldUnicode: false,
|
||||
oldMaxLength: 255,
|
||||
comment: "JSON serialized event",
|
||||
oldComment: "JSON serialized event");
|
||||
}
|
||||
}
|
||||
+12
-13
@@ -2,53 +2,52 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Shop.Infrastructure.Data.Context;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations.EventStoreDb
|
||||
namespace Shop.PublicApi.Migrations.EventStoreMigrations
|
||||
{
|
||||
[DbContext(typeof(EventStoreDbContext))]
|
||||
[Migration("20241128202230_EF_Update")]
|
||||
partial class EF_Update
|
||||
[Migration("20250924110826_Initial")]
|
||||
partial class Initial
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Latin1_General_CI_AI")
|
||||
.HasAnnotation("ProductVersion", "9.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Shop.Core.SharedKernel.EventStore", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("AggregateId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnType("character varying(255)")
|
||||
.HasComment("JSON serialized event");
|
||||
|
||||
b.Property<string>("MessageType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("CreatedAt");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations.EventStoreMigrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class Initial : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.CreateTable(
|
||||
name: "EventStores",
|
||||
columns: table => new
|
||||
{
|
||||
Id = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
Data = table.Column<string>(type: "character varying(255)", unicode: false, maxLength: 255, nullable: false, comment: "JSON serialized event"),
|
||||
MessageType = table.Column<string>(type: "character varying(100)", unicode: false, maxLength: 100, nullable: false),
|
||||
AggregateId = table.Column<Guid>(type: "uuid", nullable: false),
|
||||
CreatedAt = table.Column<DateTime>(type: "timestamp with time zone", nullable: false)
|
||||
},
|
||||
constraints: table =>
|
||||
{
|
||||
table.PrimaryKey("PK_EventStores", x => x.Id);
|
||||
});
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropTable(
|
||||
name: "EventStores");
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-11
@@ -2,13 +2,13 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Shop.Infrastructure.Data.Context;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace Shop.PublicApi.Migrations.EventStoreDb
|
||||
namespace Shop.PublicApi.Migrations.EventStoreMigrations
|
||||
{
|
||||
[DbContext(typeof(EventStoreDbContext))]
|
||||
partial class EventStoreDbContextModelSnapshot : ModelSnapshot
|
||||
@@ -17,35 +17,34 @@ namespace Shop.PublicApi.Migrations.EventStoreDb
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Latin1_General_CI_AI")
|
||||
.HasAnnotation("ProductVersion", "9.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Shop.Core.SharedKernel.EventStore", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<Guid>("AggregateId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<string>("Data")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(255)")
|
||||
.HasColumnType("character varying(255)")
|
||||
.HasComment("JSON serialized event");
|
||||
|
||||
b.Property<string>("MessageType")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<DateTime>("OccurredOn")
|
||||
.HasColumnType("datetime2")
|
||||
.HasColumnType("timestamp with time zone")
|
||||
.HasColumnName("CreatedAt");
|
||||
|
||||
b.HasKey("Id");
|
||||
@@ -2,8 +2,8 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Metadata;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
|
||||
using Shop.Infrastructure.Data.Context;
|
||||
|
||||
#nullable disable
|
||||
@@ -17,16 +17,15 @@ namespace Shop.PublicApi.Migrations
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder
|
||||
.UseCollation("Latin1_General_CI_AI")
|
||||
.HasAnnotation("ProductVersion", "9.0.0")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 128);
|
||||
.HasAnnotation("ProductVersion", "9.0.9")
|
||||
.HasAnnotation("Relational:MaxIdentifierLength", 63);
|
||||
|
||||
SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder);
|
||||
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
|
||||
|
||||
modelBuilder.Entity("Shop.Domain.Entities.CustomerAggregate.Customer", b =>
|
||||
{
|
||||
b.Property<Guid>("Id")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b.Property<DateTime>("DateOfBirth")
|
||||
.HasColumnType("DATE");
|
||||
@@ -35,18 +34,18 @@ namespace Shop.PublicApi.Migrations
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.Property<string>("Gender")
|
||||
.IsRequired()
|
||||
.HasMaxLength(6)
|
||||
.HasColumnType("nvarchar(6)");
|
||||
.HasColumnType("character varying(6)");
|
||||
|
||||
b.Property<string>("LastName")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(100)");
|
||||
.HasColumnType("character varying(100)");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
@@ -58,20 +57,19 @@ namespace Shop.PublicApi.Migrations
|
||||
b.OwnsOne("Shop.Domain.ValueObjects.Email", "Email", b1 =>
|
||||
{
|
||||
b1.Property<Guid>("CustomerId")
|
||||
.HasColumnType("uniqueidentifier");
|
||||
.HasColumnType("uuid");
|
||||
|
||||
b1.Property<string>("Address")
|
||||
.IsRequired()
|
||||
.HasMaxLength(254)
|
||||
.IsUnicode(false)
|
||||
.HasColumnType("varchar(254)")
|
||||
.HasColumnType("character varying(254)")
|
||||
.HasColumnName("Email");
|
||||
|
||||
b1.HasKey("CustomerId");
|
||||
|
||||
b1.HasIndex("Address")
|
||||
.IsUnique()
|
||||
.HasFilter("[Email] IS NOT NULL");
|
||||
.IsUnique();
|
||||
|
||||
b1.ToTable("Customers");
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO.Compression;
|
||||
using Asp.Versioning;
|
||||
@@ -139,4 +140,4 @@ app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.MapControllers();
|
||||
|
||||
await app.RunAppAsync();
|
||||
await app.ConfigureAndRunAppAsync();
|
||||
@@ -40,6 +40,7 @@
|
||||
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" />
|
||||
<PackageReference Include="MiniProfiler.AspNetCore.Mvc" />
|
||||
<PackageReference Include="MiniProfiler.EntityFrameworkCore" />
|
||||
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" />
|
||||
<PackageReference Include="Roslynator.Analyzers">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
|
||||
@@ -9,11 +9,6 @@
|
||||
"Microsoft.AspNetCore.DataProtection": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"SqlConnection": "",
|
||||
"NoSqlConnection": "",
|
||||
"CacheConnection": ""
|
||||
},
|
||||
"CacheOptions": {
|
||||
"AbsoluteExpirationInHours": 2,
|
||||
"SlidingExpirationInSeconds": 60
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft": "Warning",
|
||||
"Microsoft.AspNetCore": "Information",
|
||||
"Microsoft.Hosting.Lifetime": "Information",
|
||||
"Microsoft.EntityFrameworkCore": "Information",
|
||||
"Microsoft.AspNetCore.DataProtection": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"SqlConnection": "",
|
||||
"NoSqlConnection": "",
|
||||
"CacheConnection": ""
|
||||
},
|
||||
"CacheOptions": {
|
||||
"AbsoluteExpirationInHours": 2,
|
||||
"SlidingExpirationInSeconds": 60
|
||||
}
|
||||
}
|
||||
@@ -6,5 +6,11 @@
|
||||
"Microsoft.Hosting.Lifetime": "Information"
|
||||
}
|
||||
},
|
||||
"ConnectionStrings": {
|
||||
"PostgresConnection" : "Host=localhost;Port=5432;Database=ShopDDD;Username=mmdi;Password=mmdi",
|
||||
"SqlConnection": "Server=localhost,1433;Database=ShopContext;User Id=sa;Password=Programmer.369;TrustServerCertificate=True;",
|
||||
"NoSqlConnection" : "mongodb://localhost:27017",
|
||||
"CacheConnection" : "localhost:6379,password=Programmer.369,abortConnect=false"
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user