Merge pull request #120 from meysamhadeli/develop

Develop
This commit is contained in:
Meysam Hadeli 2023-01-23 02:11:25 +03:30 committed by GitHub
commit 3c562e1ed9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
35 changed files with 480 additions and 280 deletions

View File

@ -247,7 +247,7 @@ Content-Type: application/json
authorization: bearer {{Authenticate.response.body.access_token}}
{
"passengerId": 7225627535474688,
"passengerId": 8765596234940416,
"flightId": 1,
"description": "I want to fly to iran"
}

View File

@ -2,14 +2,18 @@
namespace BuildingBlocks.Core.Model;
public interface IAggregate : IAudit
public interface IAggregate : IAudit, IVersion
{
IReadOnlyList<IDomainEvent> DomainEvents { get; }
IEvent[] ClearDomainEvents();
long Version { get; set; }
}
public interface IAggregate<out T> : IAggregate
{
T Id { get; }
}
public interface IVersion
{
long Version { get; set; }
}

View File

@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace BuildingBlocks.PersistMessageProcessor.Data.Migrations
{
[DbContext(typeof(PersistMessageDbContext))]
[Migration("20230122153121_initial")]
[Migration("20230122204943_initial")]
partial class initial
{
/// <inheritdoc />

View File

@ -5,6 +5,7 @@ namespace BuildingBlocks.PersistMessageProcessor.Data;
using System.Net;
using Configurations;
using Core.Model;
using global::Polly;
using Microsoft.Extensions.Logging;
@ -57,7 +58,9 @@ public class PersistMessageDbContext : DbContext, IPersistMessageDbContext
var databaseValues = await entry.GetDatabaseValuesAsync(cancellationToken);
if (databaseValues != null)
{
entry.OriginalValues.SetValues(databaseValues);
}
}
return await base.SaveChangesAsync(cancellationToken);
@ -68,7 +71,7 @@ public class PersistMessageDbContext : DbContext, IPersistMessageDbContext
private void OnBeforeSaving()
{
foreach (var entry in ChangeTracker.Entries<PersistMessage>())
foreach (var entry in ChangeTracker.Entries<IVersion>())
{
switch (entry.State)
{

View File

@ -1,6 +1,8 @@
namespace BuildingBlocks.PersistMessageProcessor;
public class PersistMessage
using Core.Model;
public class PersistMessage: IVersion
{
public PersistMessage(long id, string dataType, string data, MessageDeliveryType deliveryType)
{

View File

@ -54,7 +54,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
public async Task<IReadOnlyList<PersistMessage>> GetByFilterAsync(Expression<Func<PersistMessage, bool>> predicate,
CancellationToken cancellationToken = default)
{
return (await _persistMessageDbContext.PersistMessages.AsNoTracking().Where(predicate).ToListAsync(cancellationToken))
return (await _persistMessageDbContext.PersistMessages.Where(predicate).ToListAsync(cancellationToken))
.AsReadOnly();
}
@ -110,7 +110,7 @@ public class PersistMessageProcessor : IPersistMessageProcessor
public async Task ProcessAllAsync(CancellationToken cancellationToken = default)
{
var messages = await _persistMessageDbContext.PersistMessages.AsNoTracking()
var messages = await _persistMessageDbContext.PersistMessages
.Where(x => x.MessageStatus != MessageStatus.Processed)
.ToListAsync(cancellationToken);

View File

@ -14,7 +14,7 @@ public static class GrpcCircuitBreaker
//ref: https://anthonygiretti.com/2020/03/31/grpc-asp-net-core-3-1-resiliency-with-polly/
public static IHttpClientBuilder AddGrpcCircuitBreakerPolicyHandler(this IHttpClientBuilder httpClientBuilder)
{
return httpClientBuilder.AddPolicyHandler((sp, _) =>
return httpClientBuilder.AddPolicyHandler((sp, _) =>
{
var options = sp.GetRequiredService<IConfiguration>().GetOptions<PolicyOptions>(nameof(PolicyOptions));
@ -23,28 +23,7 @@ public static class GrpcCircuitBreaker
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("PollyGrpcCircuitBreakerPoliciesLogger");
// gRPC status
var gRpcErrors = new StatusCode[]
{
StatusCode.DeadlineExceeded, StatusCode.Internal, StatusCode.NotFound, StatusCode.Cancelled,
StatusCode.ResourceExhausted, StatusCode.Unavailable, StatusCode.Unknown
};
// Http errors
var serverErrors = new HttpStatusCode[]
{
HttpStatusCode.BadGateway, HttpStatusCode.GatewayTimeout, HttpStatusCode.ServiceUnavailable,
HttpStatusCode.InternalServerError, HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout
};
return Policy.HandleResult<HttpResponseMessage>(r =>
{
var grpcStatus = StatusManager.GetStatusCode(r);
var httpStatusCode = r.StatusCode;
return (grpcStatus == null && serverErrors.Contains(httpStatusCode)) || // if the server send an error before gRPC pipeline
(httpStatusCode == HttpStatusCode.OK && gRpcErrors.Contains(grpcStatus.Value)); // if gRPC pipeline handled the request (gRPC always answers OK)
})
return Policy.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.CircuitBreakerAsync(
handledEventsAllowedBeforeBreaking: options.CircuitBreaker.RetryCount,
durationOfBreak: TimeSpan.FromSeconds(options.CircuitBreaker.BreakDuration),
@ -64,20 +43,4 @@ public static class GrpcCircuitBreaker
});
});
}
private static class StatusManager
{
public static StatusCode? GetStatusCode(HttpResponseMessage response)
{
var headers = response.Headers;
if (!headers.Contains("grpc-status") && response.StatusCode == HttpStatusCode.OK)
return StatusCode.OK;
if (headers.Contains("grpc-status"))
return (StatusCode)int.Parse(headers.GetValues("grpc-status").First());
return null;
}
}
}

View File

@ -20,37 +20,17 @@ public static class GrpcRetry
Guard.Against.Null(options, nameof(options));
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("PollyGrpcRetryPoliciesLogger");
// gRPC status
var gRpcErrors = new StatusCode[]
{
StatusCode.DeadlineExceeded, StatusCode.Internal, StatusCode.NotFound, StatusCode.Cancelled,
StatusCode.ResourceExhausted, StatusCode.Unavailable, StatusCode.Unknown
};
// Http errors
var serverErrors = new HttpStatusCode[]
{
HttpStatusCode.BadGateway, HttpStatusCode.GatewayTimeout, HttpStatusCode.ServiceUnavailable,
HttpStatusCode.InternalServerError, HttpStatusCode.TooManyRequests, HttpStatusCode.RequestTimeout
};
return Policy.HandleResult<HttpResponseMessage>(r =>
{
var grpcStatus = StatusManager.GetStatusCode(r);
var httpStatusCode = r.StatusCode;
return (grpcStatus == null && serverErrors.Contains(httpStatusCode)) || // if the server send an error before gRPC pipeline
(httpStatusCode == HttpStatusCode.OK && gRpcErrors.Contains(grpcStatus.Value)); // if gRPC pipeline handled the request (gRPC always answers OK)
})
.WaitAndRetryAsync(retryCount: options.Retry.RetryCount,
sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(options.Retry.SleepDuration),
return Policy
.HandleResult<HttpResponseMessage>(r => !r.IsSuccessStatusCode)
.WaitAndRetryAsync(options.Retry.RetryCount,
retryAttempt => TimeSpan.FromSeconds(options.Retry.SleepDuration),
onRetry: (response, timeSpan, retryCount, context) =>
{
if (response?.Exception != null)
{
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
var logger = loggerFactory.CreateLogger("PollyGrpcRetryPoliciesLogger");
logger.LogError(response.Exception,
"Request failed with {StatusCode}. Waiting {TimeSpan} before next retry. Retry attempt {RetryCount}.",
response.Result.StatusCode,
@ -60,20 +40,4 @@ public static class GrpcRetry
});
});
}
private static class StatusManager
{
public static StatusCode? GetStatusCode(HttpResponseMessage response)
{
var headers = response.Headers;
if (!headers.Contains("grpc-status") && response.StatusCode == HttpStatusCode.OK)
return StatusCode.OK;
if (headers.Contains("grpc-status"))
return (StatusCode)int.Parse(headers.GetValues("grpc-status").First());
return null;
}
}
}

View File

@ -36,7 +36,7 @@
"FlightAddress": "https://localhost:5003",
"PassengerAddress": "https://localhost:5012"
},
"RetryOptions": {
"PolicyOptions": {
"Retry": {
"RetryCount": 3,
"SleepDuration": 1

View File

@ -62,7 +62,7 @@ public class CreateBookingCommandHandler : ICommandHandler<CreateBookingCommand,
await _flightGrpcServiceClient.ReserveSeatAsync(new ReserveSeatRequest
{
FlightId = flight.FlightId, SeatNumber = emptySeat?.SeatNumber
FlightId = flight.Id, SeatNumber = emptySeat?.SeatNumber
});
var result = await _eventStoreDbRepository.Add(

View File

@ -100,7 +100,6 @@ public static class InfrastructureExtensions
});
app.UseCorrelationId();
app.UseHttpMetrics();
// app.UseMigration<PersistMessageDbContext>(env);
app.UseCustomHealthCheck();
app.MapMetrics();
app.MapGet("/", x => x.Response.WriteAsync(appOptions.Name));

View File

@ -0,0 +1,16 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class RoleClaimConfiguration : IEntityTypeConfiguration<RoleClaim>
{
public void Configure(EntityTypeBuilder<RoleClaim> builder)
{
builder.ToTable(nameof(RoleClaim));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -0,0 +1,16 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class RoleConfiguration : IEntityTypeConfiguration<Role>
{
public void Configure(EntityTypeBuilder<Role> builder)
{
builder.ToTable(nameof(Role));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -0,0 +1,16 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class UserClaimConfiguration : IEntityTypeConfiguration<UserClaim>
{
public void Configure(EntityTypeBuilder<UserClaim> builder)
{
builder.ToTable(nameof(UserClaim));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -0,0 +1,16 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class UserConfiguration : IEntityTypeConfiguration<User>
{
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable(nameof(User));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -0,0 +1,17 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class UserLoginConfiguration : IEntityTypeConfiguration<UserLogin>
{
public void Configure(EntityTypeBuilder<UserLogin> builder)
{
builder.ToTable(nameof(UserLogin));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -0,0 +1,16 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class UserRoleConfiguration : IEntityTypeConfiguration<UserRole>
{
public void Configure(EntityTypeBuilder<UserRole> builder)
{
builder.ToTable(nameof(UserRole));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -0,0 +1,16 @@
namespace Identity.Data.Configurations;
using Identity.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
public class UserTokenConfiguration : IEntityTypeConfiguration<UserToken>
{
public void Configure(EntityTypeBuilder<UserToken> builder)
{
builder.ToTable(nameof(UserToken));
// // ref: https://learn.microsoft.com/en-us/ef/core/saving/concurrency?tabs=fluent-api
builder.Property(r => r.Version).IsConcurrencyToken();
}
}

View File

@ -8,20 +8,16 @@ using System.Threading.Tasks;
using BuildingBlocks.Core.Event;
using BuildingBlocks.Core.Model;
using BuildingBlocks.EFCore;
using Humanizer;
using Identity.Identity.Models;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Storage;
namespace Identity.Data;
public sealed class IdentityContext : IdentityDbContext<ApplicationUser, IdentityRole<long>, long,
IdentityUserClaim<long>,
IdentityUserRole<long>, IdentityUserLogin<long>, IdentityRoleClaim<long>, IdentityUserToken<long>>, IDbContext
public sealed class IdentityContext : IdentityDbContext<User, Role, long,
UserClaim, UserRole, UserLogin, RoleClaim, UserToken>, IDbContext
{
private IDbContextTransaction _currentTransaction;
@ -38,6 +34,12 @@ public sealed class IdentityContext : IdentityDbContext<ApplicationUser, Identit
builder.ToSnakeCaseTables();
}
public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
{
OnBeforeSaving();
return await base.SaveChangesAsync(cancellationToken);
}
public async Task BeginTransactionAsync(CancellationToken cancellationToken = default)
{
if (_currentTransaction != null)
@ -96,4 +98,21 @@ public sealed class IdentityContext : IdentityDbContext<ApplicationUser, Identit
return domainEvents.ToImmutableList();
}
private void OnBeforeSaving()
{
foreach (var entry in ChangeTracker.Entries<IVersion>())
{
switch (entry.State)
{
case EntityState.Modified:
entry.Entity.Version++;
break;
case EntityState.Deleted:
entry.Entity.Version++;
break;
}
}
}
}

View File

@ -12,7 +12,7 @@ using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Identity.Data.Migrations
{
[DbContext(typeof(IdentityContext))]
[Migration("20230113183552_initial")]
[Migration("20230122204905_initial")]
partial class initial
{
/// <inheritdoc />
@ -25,7 +25,81 @@ namespace Identity.Data.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Identity.Identity.Models.ApplicationUser", b =>
modelBuilder.Entity("Identity.Identity.Models.Role", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text")
.HasColumnName("concurrency_stamp");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("name");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("normalized_name");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_roles");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("asp_net_roles", (string)null);
});
modelBuilder.Entity("Identity.Identity.Models.RoleClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text")
.HasColumnName("claim_type");
b.Property<string>("ClaimValue")
.HasColumnType("text")
.HasColumnName("claim_value");
b.Property<long>("RoleId")
.HasColumnType("bigint")
.HasColumnName("role_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_role_claims");
b.HasIndex("RoleId")
.HasDatabaseName("ix_asp_net_role_claims_role_id");
b.ToTable("asp_net_role_claims", (string)null);
});
modelBuilder.Entity("Identity.Identity.Models.User", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
@ -107,6 +181,11 @@ namespace Identity.Data.Migrations
.HasColumnType("character varying(256)")
.HasColumnName("user_name");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_users");
@ -120,71 +199,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_users", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<long>", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text")
.HasColumnName("concurrency_stamp");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("name");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("normalized_name");
b.HasKey("Id")
.HasName("pk_asp_net_roles");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("asp_net_roles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text")
.HasColumnName("claim_type");
b.Property<string>("ClaimValue")
.HasColumnType("text")
.HasColumnName("claim_value");
b.Property<long>("RoleId")
.HasColumnType("bigint")
.HasColumnName("role_id");
b.HasKey("Id")
.HasName("pk_asp_net_role_claims");
b.HasIndex("RoleId")
.HasDatabaseName("ix_asp_net_role_claims_role_id");
b.ToTable("asp_net_role_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
@ -205,6 +220,11 @@ namespace Identity.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("user_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_user_claims");
@ -214,7 +234,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_user_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserLogin", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text")
@ -232,6 +252,11 @@ namespace Identity.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("user_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("LoginProvider", "ProviderKey")
.HasName("pk_asp_net_user_logins");
@ -241,7 +266,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_user_logins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserRole", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint")
@ -251,6 +276,11 @@ namespace Identity.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("role_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("UserId", "RoleId")
.HasName("pk_asp_net_user_roles");
@ -260,7 +290,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_user_roles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserToken", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint")
@ -278,15 +308,20 @@ namespace Identity.Data.Migrations
.HasColumnType("text")
.HasColumnName("value");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("UserId", "LoginProvider", "Name")
.HasName("pk_asp_net_user_tokens");
b.ToTable("asp_net_user_tokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.RoleClaim", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<long>", null)
b.HasOne("Identity.Identity.Models.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
@ -294,9 +329,9 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_role_claims_asp_net_roles_role_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserClaim", b =>
{
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@ -304,9 +339,9 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_user_claims_asp_net_users_user_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserLogin", b =>
{
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@ -314,16 +349,16 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_user_logins_asp_net_users_user_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserRole", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<long>", null)
b.HasOne("Identity.Identity.Models.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_asp_net_user_roles_asp_net_roles_role_id");
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@ -331,9 +366,9 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_user_roles_asp_net_users_user_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserToken", b =>
{
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)

View File

@ -18,6 +18,7 @@ namespace Identity.Data.Migrations
{
id = table.Column<long>(type: "bigint", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
version = table.Column<long>(type: "bigint", nullable: false),
name = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
normalizedname = table.Column<string>(name: "normalized_name", type: "character varying(256)", maxLength: 256, nullable: true),
concurrencystamp = table.Column<string>(name: "concurrency_stamp", type: "text", nullable: true)
@ -36,6 +37,7 @@ namespace Identity.Data.Migrations
firstname = table.Column<string>(name: "first_name", type: "text", nullable: true),
lastname = table.Column<string>(name: "last_name", type: "text", nullable: true),
passportnumber = table.Column<string>(name: "pass_port_number", type: "text", nullable: true),
version = table.Column<long>(type: "bigint", nullable: false),
username = table.Column<string>(name: "user_name", type: "character varying(256)", maxLength: 256, nullable: true),
normalizedusername = table.Column<string>(name: "normalized_user_name", type: "character varying(256)", maxLength: 256, nullable: true),
email = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
@ -62,6 +64,7 @@ namespace Identity.Data.Migrations
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
version = table.Column<long>(type: "bigint", nullable: false),
roleid = table.Column<long>(name: "role_id", type: "bigint", nullable: false),
claimtype = table.Column<string>(name: "claim_type", type: "text", nullable: true),
claimvalue = table.Column<string>(name: "claim_value", type: "text", nullable: true)
@ -83,6 +86,7 @@ namespace Identity.Data.Migrations
{
id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
version = table.Column<long>(type: "bigint", nullable: false),
userid = table.Column<long>(name: "user_id", type: "bigint", nullable: false),
claimtype = table.Column<string>(name: "claim_type", type: "text", nullable: true),
claimvalue = table.Column<string>(name: "claim_value", type: "text", nullable: true)
@ -104,6 +108,7 @@ namespace Identity.Data.Migrations
{
loginprovider = table.Column<string>(name: "login_provider", type: "text", nullable: false),
providerkey = table.Column<string>(name: "provider_key", type: "text", nullable: false),
version = table.Column<long>(type: "bigint", nullable: false),
providerdisplayname = table.Column<string>(name: "provider_display_name", type: "text", nullable: true),
userid = table.Column<long>(name: "user_id", type: "bigint", nullable: false)
},
@ -123,7 +128,8 @@ namespace Identity.Data.Migrations
columns: table => new
{
userid = table.Column<long>(name: "user_id", type: "bigint", nullable: false),
roleid = table.Column<long>(name: "role_id", type: "bigint", nullable: false)
roleid = table.Column<long>(name: "role_id", type: "bigint", nullable: false),
version = table.Column<long>(type: "bigint", nullable: false)
},
constraints: table =>
{
@ -149,6 +155,7 @@ namespace Identity.Data.Migrations
userid = table.Column<long>(name: "user_id", type: "bigint", nullable: false),
loginprovider = table.Column<string>(name: "login_provider", type: "text", nullable: false),
name = table.Column<string>(type: "text", nullable: false),
version = table.Column<long>(type: "bigint", nullable: false),
value = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>

View File

@ -22,7 +22,81 @@ namespace Identity.Data.Migrations
NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder);
modelBuilder.Entity("Identity.Identity.Models.ApplicationUser", b =>
modelBuilder.Entity("Identity.Identity.Models.Role", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text")
.HasColumnName("concurrency_stamp");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("name");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("normalized_name");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_roles");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("asp_net_roles", (string)null);
});
modelBuilder.Entity("Identity.Identity.Models.RoleClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text")
.HasColumnName("claim_type");
b.Property<string>("ClaimValue")
.HasColumnType("text")
.HasColumnName("claim_value");
b.Property<long>("RoleId")
.HasColumnType("bigint")
.HasColumnName("role_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_role_claims");
b.HasIndex("RoleId")
.HasDatabaseName("ix_asp_net_role_claims_role_id");
b.ToTable("asp_net_role_claims", (string)null);
});
modelBuilder.Entity("Identity.Identity.Models.User", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
@ -104,6 +178,11 @@ namespace Identity.Data.Migrations
.HasColumnType("character varying(256)")
.HasColumnName("user_name");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_users");
@ -117,71 +196,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_users", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRole<long>", b =>
{
b.Property<long>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("bigint")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<long>("Id"));
b.Property<string>("ConcurrencyStamp")
.IsConcurrencyToken()
.HasColumnType("text")
.HasColumnName("concurrency_stamp");
b.Property<string>("Name")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("name");
b.Property<string>("NormalizedName")
.HasMaxLength(256)
.HasColumnType("character varying(256)")
.HasColumnName("normalized_name");
b.HasKey("Id")
.HasName("pk_asp_net_roles");
b.HasIndex("NormalizedName")
.IsUnique()
.HasDatabaseName("RoleNameIndex");
b.ToTable("asp_net_roles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
.HasColumnType("integer")
.HasColumnName("id");
NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property<int>("Id"));
b.Property<string>("ClaimType")
.HasColumnType("text")
.HasColumnName("claim_type");
b.Property<string>("ClaimValue")
.HasColumnType("text")
.HasColumnName("claim_value");
b.Property<long>("RoleId")
.HasColumnType("bigint")
.HasColumnName("role_id");
b.HasKey("Id")
.HasName("pk_asp_net_role_claims");
b.HasIndex("RoleId")
.HasDatabaseName("ix_asp_net_role_claims_role_id");
b.ToTable("asp_net_role_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserClaim", b =>
{
b.Property<int>("Id")
.ValueGeneratedOnAdd()
@ -202,6 +217,11 @@ namespace Identity.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("user_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("Id")
.HasName("pk_asp_net_user_claims");
@ -211,7 +231,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_user_claims", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserLogin", b =>
{
b.Property<string>("LoginProvider")
.HasColumnType("text")
@ -229,6 +249,11 @@ namespace Identity.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("user_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("LoginProvider", "ProviderKey")
.HasName("pk_asp_net_user_logins");
@ -238,7 +263,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_user_logins", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserRole", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint")
@ -248,6 +273,11 @@ namespace Identity.Data.Migrations
.HasColumnType("bigint")
.HasColumnName("role_id");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("UserId", "RoleId")
.HasName("pk_asp_net_user_roles");
@ -257,7 +287,7 @@ namespace Identity.Data.Migrations
b.ToTable("asp_net_user_roles", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserToken", b =>
{
b.Property<long>("UserId")
.HasColumnType("bigint")
@ -275,15 +305,20 @@ namespace Identity.Data.Migrations
.HasColumnType("text")
.HasColumnName("value");
b.Property<long>("Version")
.IsConcurrencyToken()
.HasColumnType("bigint")
.HasColumnName("version");
b.HasKey("UserId", "LoginProvider", "Name")
.HasName("pk_asp_net_user_tokens");
b.ToTable("asp_net_user_tokens", (string)null);
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityRoleClaim<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.RoleClaim", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<long>", null)
b.HasOne("Identity.Identity.Models.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
@ -291,9 +326,9 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_role_claims_asp_net_roles_role_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserClaim<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserClaim", b =>
{
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@ -301,9 +336,9 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_user_claims_asp_net_users_user_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserLogin<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserLogin", b =>
{
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@ -311,16 +346,16 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_user_logins_asp_net_users_user_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserRole<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserRole", b =>
{
b.HasOne("Microsoft.AspNetCore.Identity.IdentityRole<long>", null)
b.HasOne("Identity.Identity.Models.Role", null)
.WithMany()
.HasForeignKey("RoleId")
.OnDelete(DeleteBehavior.Cascade)
.IsRequired()
.HasConstraintName("fk_asp_net_user_roles_asp_net_roles_role_id");
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)
@ -328,9 +363,9 @@ namespace Identity.Data.Migrations
.HasConstraintName("fk_asp_net_user_roles_asp_net_users_user_id");
});
modelBuilder.Entity("Microsoft.AspNetCore.Identity.IdentityUserToken<long>", b =>
modelBuilder.Entity("Identity.Identity.Models.UserToken", b =>
{
b.HasOne("Identity.Identity.Models.ApplicationUser", null)
b.HasOne("Identity.Identity.Models.User", null)
.WithMany()
.HasForeignKey("UserId")
.OnDelete(DeleteBehavior.Cascade)

View File

@ -11,12 +11,12 @@ namespace Identity.Data.Seed;
public class IdentityDataSeeder : IDataSeeder
{
private readonly RoleManager<IdentityRole<long>> _roleManager;
private readonly UserManager<User> _userManager;
private readonly RoleManager<Role> _roleManager;
private readonly IEventDispatcher _eventDispatcher;
private readonly UserManager<ApplicationUser> _userManager;
public IdentityDataSeeder(UserManager<ApplicationUser> userManager,
RoleManager<IdentityRole<long>> roleManager,
public IdentityDataSeeder(UserManager<User> userManager,
RoleManager<Role> roleManager,
IEventDispatcher eventDispatcher)
{
_userManager = userManager;
@ -33,17 +33,17 @@ public class IdentityDataSeeder : IDataSeeder
private async Task SeedRoles()
{
if (await _roleManager.RoleExistsAsync(Constants.Role.Admin) == false)
await _roleManager.CreateAsync(new(Constants.Role.Admin));
await _roleManager.CreateAsync(new Role {Name = Constants.Role.Admin});
if (await _roleManager.RoleExistsAsync(Constants.Role.User) == false)
await _roleManager.CreateAsync(new(Constants.Role.User));
await _roleManager.CreateAsync(new Role {Name = Constants.Role.User});
}
private async Task SeedUsers()
{
if (await _userManager.FindByNameAsync("samh") == null)
{
var user = new ApplicationUser
var user = new User
{
FirstName = "Sam",
LastName = "H",
@ -65,7 +65,7 @@ public class IdentityDataSeeder : IDataSeeder
if (await _userManager.FindByNameAsync("meysamh2") == null)
{
var user = new ApplicationUser
var user = new User
{
FirstName = "Sam2",
LastName = "H2",

View File

@ -11,7 +11,7 @@ public static class IdentityServerExtensions
{
public static IServiceCollection AddIdentityServer(this IServiceCollection services, IWebHostEnvironment env)
{
services.AddIdentity<ApplicationUser, IdentityRole<long>>(config =>
services.AddIdentity<User, Role>(config =>
{
config.Password.RequiredLength = 6;
config.Password.RequireDigit = false;
@ -32,7 +32,7 @@ public static class IdentityServerExtensions
.AddInMemoryApiResources(Config.ApiResources)
.AddInMemoryApiScopes(Config.ApiScopes)
.AddInMemoryClients(Config.Clients)
.AddAspNetIdentity<ApplicationUser>()
.AddAspNetIdentity<User>()
.AddResourceOwnerValidator<UserValidator>();
if (env.IsDevelopment())

View File

@ -16,7 +16,6 @@
</ItemGroup>
<ItemGroup>
<Folder Include="Data\Configurations" />
<Folder Include="Data\Migrations" />
</ItemGroup>

View File

@ -15,9 +15,9 @@ namespace Identity.Identity.Features.RegisterNewUser.Commands.V1;
public class RegisterNewUserCommandHandler : ICommandHandler<RegisterNewUserCommand, RegisterNewUserResponseDto>
{
private readonly IEventDispatcher _eventDispatcher;
private readonly UserManager<ApplicationUser> _userManager;
private readonly UserManager<User> _userManager;
public RegisterNewUserCommandHandler(UserManager<ApplicationUser> userManager,
public RegisterNewUserCommandHandler(UserManager<User> userManager,
IEventDispatcher eventDispatcher)
{
_userManager = userManager;
@ -29,7 +29,7 @@ public class RegisterNewUserCommandHandler : ICommandHandler<RegisterNewUserComm
{
Guard.Against.Null(command, nameof(command));
var applicationUser = new ApplicationUser()
var applicationUser = new User()
{
FirstName = command.FirstName,
LastName = command.LastName,

View File

@ -0,0 +1,9 @@
namespace Identity.Identity.Models;
using BuildingBlocks.Core.Model;
using Microsoft.AspNetCore.Identity;
public class Role: IdentityRole<long>, IVersion
{
public long Version { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Identity.Identity.Models;
using BuildingBlocks.Core.Model;
using Microsoft.AspNetCore.Identity;
public class RoleClaim: IdentityRoleClaim<long>, IVersion
{
public long Version { get; set; }
}

View File

@ -2,9 +2,12 @@ using Microsoft.AspNetCore.Identity;
namespace Identity.Identity.Models;
public class ApplicationUser : IdentityUser<long>
using BuildingBlocks.Core.Model;
public class User : IdentityUser<long>, IVersion
{
public string FirstName { get; init; }
public string LastName { get; init; }
public string PassPortNumber { get; init; }
public long Version { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Identity.Identity.Models;
using BuildingBlocks.Core.Model;
using Microsoft.AspNetCore.Identity;
public class UserClaim: IdentityUserClaim<long>, IVersion
{
public long Version { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Identity.Identity.Models;
using BuildingBlocks.Core.Model;
using Microsoft.AspNetCore.Identity;
public class UserLogin: IdentityUserLogin<long>, IVersion
{
public long Version { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Identity.Identity.Models;
using BuildingBlocks.Core.Model;
using Microsoft.AspNetCore.Identity;
public class UserRole: IdentityUserRole<long>, IVersion
{
public long Version { get; set; }
}

View File

@ -0,0 +1,9 @@
namespace Identity.Identity.Models;
using BuildingBlocks.Core.Model;
using Microsoft.AspNetCore.Identity;
public class UserToken: IdentityUserToken<long>, IVersion
{
public long Version { get; set; }
}

View File

@ -9,11 +9,11 @@ namespace Identity;
public class UserValidator : IResourceOwnerPasswordValidator
{
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<User> _signInManager;
private readonly UserManager<User> _userManager;
public UserValidator(SignInManager<ApplicationUser> signInManager,
UserManager<ApplicationUser> userManager)
public UserValidator(SignInManager<User> signInManager,
UserManager<User> userManager)
{
_signInManager = signInManager;
_userManager = userManager;