├── .dockerignore ├── .gitattributes ├── .gitignore ├── ErSoftDev.sln ├── README.md ├── data ├── database.sqlite └── keys.json ├── docker-compose.yml ├── launchSettings.json └── src ├── ApiGateway └── ErSoftDev.ApiGateway │ ├── .config │ └── dotnet-tools.json │ ├── Application │ └── HealthChecks │ │ └── IdentityGrpcServiceHealthCheck.cs │ ├── Configuration.cs │ ├── Dockerfile │ ├── ErSoftDev.ApiGateway.csproj │ ├── Extensions │ └── ServiceCollectionExtension.cs │ ├── GatewayXmlComment.xml │ ├── Infrastructure │ └── ServiceProviderConfiguration │ │ ├── Google │ │ └── ProtoBuf │ │ │ └── wrappers.proto │ │ └── Identity │ │ ├── AccountService.cs │ │ ├── IAccountService.cs │ │ └── Protos │ │ └── AccountProto.proto │ ├── Ocelot │ ├── Development │ │ ├── Ocelot.Global.Json │ │ ├── Ocelot.Identity.Api.json │ │ └── Ocelot.SwaggerEndPoints.json │ └── Docker │ │ ├── Ocelot.Global.Json │ │ ├── Ocelot.Identity.Api.json │ │ └── Ocelot.SwaggerEndPoints.json │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── SeedWorks │ └── ApiGatewayResultStatusCode.cs │ ├── appsettings.Development.json │ ├── appsettings.Docker.json │ ├── appsettings.json │ └── ocelot.json ├── ErSoftDev.Common ├── ErSoftDev.Common.csproj └── Utilities │ ├── ApiHelper.cs │ ├── AttributeExtensions.cs │ ├── DateExtension.cs │ ├── EnumExtensions.cs │ ├── FullNameAttribute.cs │ ├── GenericTypeExtensions.cs │ ├── GeometryExtension.cs │ ├── GrpCustomType.cs │ ├── HttpContextAccessorExtension.cs │ ├── HttpContextConvert.cs │ ├── IdentityExtensions.cs │ ├── MapsterExtension.cs │ ├── Paging.cs │ ├── PagingExtensions.cs │ ├── SecurityHelper.cs │ ├── SqlExtensions.cs │ ├── StringExtensions.cs │ └── Tools.cs ├── ErSoftDev.DomainSeedWork ├── ApiResult.cs ├── ApiResultStatusCode.cs ├── AppException.cs ├── BaseEntity.cs ├── BusinessException.cs ├── Enumeration.cs ├── ErSoftDev.DomainSeedWork.csproj ├── IAggregateRoot.cs ├── IRepository.cs ├── IUnitOfWork.cs ├── Resources │ ├── SharedTranslate.Designer.cs │ ├── SharedTranslate.en-US.resx │ ├── SharedTranslate.fa-IR.resx │ └── SharedTranslate.resx ├── SharedTranslate.cs └── ValueObject.cs ├── ErSoftDev.Framework ├── Api │ └── BaseController.cs ├── BaseApp │ ├── AppSetting.cs │ ├── BaseConfig.cs │ └── HighSecurity.cs ├── BaseModel │ ├── BaseDbContext.cs │ └── ModelBuilderExtensions.cs ├── Behaviors │ └── LoggingBehavior.cs ├── Configuration │ ├── ApplicationBuilderExtensions.cs │ ├── AutofacConfigurationExtension.cs │ ├── CustomLongToStringConverter.cs │ ├── EndpointRouteBuilderExtensions.cs │ ├── Google │ │ └── ProtoBuf │ │ │ └── wrappers.proto │ ├── HangfireConfigurationExtensions.cs │ ├── HealthCheckBuilderExtension.cs │ ├── IRegisterType.cs │ ├── MediatrExtension.cs │ └── ServiceCollectionExtentions.cs ├── ErSoftDev.Framework.csproj ├── Filters │ └── ApiResultFilterAttribute.cs ├── Grpc │ └── IGrpcService.cs ├── Jwt │ ├── IJwtService.cs │ ├── JsonWebToken.cs │ └── JwtService.cs ├── Log │ ├── ILogger.cs │ └── Logger.cs ├── Middlewares │ ├── CustomExceptionHandlerMiddleware.cs │ ├── CustomJwtTokenValidationMiddleware.cs │ ├── CustomStringLocalizedMiddleware.cs │ ├── CustomSwaggerUiMiddleware.cs │ ├── EventBusConsumerMiddleware.cs │ └── RateLimitationMiddleware.cs ├── Mongo │ ├── BaseMongoDbContext.cs │ ├── IMongoRepository.cs │ └── MongoRepository.cs ├── RabbitMq │ ├── Connection.cs │ ├── EventBusRabbitMqService.cs │ ├── IIntegrationEventBus.cs │ ├── IntegrationEventBus.cs │ └── Registration.cs ├── Redis │ ├── IRedisService.cs │ └── RedisService.cs └── Swagger │ ├── AddHeaderParameter.cs │ ├── EnumSchemaFilter.cs │ ├── RemoveVersionParameter.cs │ ├── SetVersionInPath.cs │ └── UnauthorizedResponsesOperationFilter.cs ├── HealthCheck └── ErSoftDev.HealthCheck │ ├── Configuration.cs │ ├── Dockerfile │ ├── Dockerfile.original │ ├── ErSoftDev.HealthCheck.csproj │ ├── ErSoftDev.HealthCheck.http │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── appsettings.Development.json │ ├── appsettings.Docker.json │ └── appsettings.json └── Identity ├── ErSoftDev.Identity.Application ├── Command │ ├── AddRoleCommand.cs │ ├── AddRoleCommandHandler.cs │ ├── DeleteRoleCommand.cs │ ├── DeleteRoleCommandHandler.cs │ ├── DeleteUserCommand.cs │ ├── DeleteUserCommandHandler.cs │ ├── GetRefreshTokenCommand.cs │ ├── GetRefreshTokenCommandHandler.cs │ ├── LoginCommand.cs │ ├── LoginCommandHandler.cs │ ├── RegisterUserCommand.cs │ ├── RegisterUserCommandHandler.cs │ ├── RevokeRefreshTokenCommand.cs │ ├── RevokeRefreshTokenCommandHandler.cs │ ├── UpdateRoleCommand.cs │ ├── UpdateRoleCommandHandler.cs │ ├── UpdateUserCommand.cs │ └── UpdateUserCommandHandler.cs ├── Dtos │ ├── OperateDto.cs │ └── RoleDto.cs ├── ErSoftDev.Identity.Application.csproj ├── HealthChecks │ ├── CapEventBusPublishHealthCheck.cs │ ├── CapEventBusSubscribeHealthCheck.cs │ ├── DataBaseHealthCheck.cs │ └── RedisHealthCheck.cs ├── IntegrationEvents │ └── IntegrationEventExtension.cs └── Queries │ ├── CheckAuthenticateAndAuthorizationQuery.cs │ ├── CheckAuthenticateAndAuthorizationQueryHandler.cs │ ├── CheckAuthorizeQuery.cs │ ├── CheckAuthorizeQueryHandler.cs │ ├── GetOperatesQuery.cs │ ├── GetOperatesQueryHandler.cs │ ├── GetRolesQuery.cs │ ├── GetRolesQueryHandlers.cs │ ├── IsSecurityStampTokenQuery.cs │ └── IsSecurityStampTokenQueryHandler.cs ├── ErSoftDev.Identity.Domain ├── AggregatesModel │ ├── OperateAggregate │ │ └── Operate.cs │ ├── RoleAggregate │ │ ├── IRoleRepository.cs │ │ ├── Role.cs │ │ └── RoleOperate.cs │ └── UserAggregate │ │ ├── Address.cs │ │ ├── IUserRepository.cs │ │ ├── User.cs │ │ ├── UserLogin.cs │ │ ├── UserRefreshToken.cs │ │ └── UserRole.cs ├── ErSoftDev.Identity.Domain.csproj ├── IdentityTranslate.cs ├── Resources │ ├── IdentityTranslate.Designer.cs │ ├── IdentityTranslate.en-US.resx │ ├── IdentityTranslate.fa-IR.resx │ └── IdentityTranslate.resx └── SeedWorks │ ├── CacheKey.cs │ └── IdentityResultErrorCode.cs ├── ErSoftDev.Identity.EndPoint ├── Configuration.cs ├── Controllers │ ├── IdentityBaseController.cs │ └── v1 │ │ ├── AccountController.cs │ │ └── RoleController.cs ├── Dockerfile ├── ErSoftDev.Identity.EndPoint.csproj ├── Grpc │ ├── Google │ │ └── ProtoBuf │ │ │ └── wrappers.proto │ ├── Protos │ │ └── AccountProto.proto │ └── Services │ │ └── AccountService.cs ├── IdentityXmlComment.xml ├── Program.cs ├── Properties │ └── launchSettings.json ├── appsettings.Development.json ├── appsettings.Docker.json ├── appsettings.json ├── elastic-agent.yml └── failures.txt └── ErSoftDev.Identity.Infrastructure ├── EntityConfigurations ├── OperateEntityTypeConfiguration.cs ├── RoleEntityTypeConfiguration.cs ├── RoleOperateEntityTypeConfiguration.cs ├── UserEntityTypeConfiguration.cs ├── UserLoginEntityTypeConfiguration.cs ├── UserRefreshTokenEntityTypeConfiguration.cs └── UserRoleEntityTypeConfiguration.cs ├── ErSoftDev.Identity.Infrastructure.csproj ├── IdentityDbContext.cs ├── IdentityQueryDbContext.cs ├── Migrations ├── 20240605123913_InitialMigration.Designer.cs ├── 20240605123913_InitialMigration.cs └── IdentityDbContextModelSnapshot.cs ├── NoSql ├── Models │ └── Instrument.cs └── Repositories │ ├── IInstrumentMongoRepository.cs │ └── InstrumentMongoRepository.cs └── Repositories ├── RoleRepository.cs └── UserRepository.cs /.dockerignore: -------------------------------------------------------------------------------- 1 | **/.classpath 2 | **/.dockerignore 3 | **/.env 4 | **/.git 5 | **/.gitignore 6 | **/.project 7 | **/.settings 8 | **/.toolstarget 9 | **/.vs 10 | **/.vscode 11 | **/*.*proj.user 12 | **/*.dbmdl 13 | **/*.jfm 14 | **/azds.yaml 15 | **/bin 16 | **/charts 17 | **/docker-compose* 18 | **/Dockerfile* 19 | **/node_modules 20 | **/npm-debug.log 21 | **/obj 22 | **/secrets.dev.yaml 23 | **/values.dev.yaml 24 | LICENSE 25 | README.md 26 | !**/.gitignore 27 | !.git/HEAD 28 | !.git/config 29 | !.git/packed-refs 30 | !.git/refs/heads/** -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ErSoftDev backend comprehensive solution. 2 | 3 | By this solution you can add any microService to handle part of any commerces. 4 | 5 | Brief descriptions : 6 | - .Net 8 7 | - c# 8 | - Architucture style : micorservice 9 | - Architucture pattern(code design) : DDD 10 | - Dockerize applications 11 | - Use ocelot apigateway(bff) 12 | - Use consul as service discovery 13 | - JWT Authentication 14 | - Secure JWT using Encryption (JWE) 15 | - Authentication in apigateway by identity 16 | - Use rabbitMq as message broker with CAP eventBus 17 | - Use redis bus 18 | - Use ELK to manage logs 19 | - Use jaeger as log stream 20 | - Use hangfire for background tasks and cron jobs 21 | - Use health check classes and health check UI to monitoring miroservices 22 | - Mongo support for noSql data 23 | - Support multilanguage response 24 | - Use multi environment applications and apigateway 25 | - Standard API Resulting 26 | - Use autofac as di 27 | - Automated interface register 28 | - Cqrs pattern 29 | - Use mediatr behavior for loggingBehavior 30 | - Use grpc call for microservice internal connection 31 | - Versioning management 32 | - Integrate Swagger and JWT/OAuth Authentication 33 | - Use dynamic versioning in swagger 34 | - Exception Handling by using Custom Middleware 35 | - Use soft delete for desired entities 36 | - Use automapper like mapster 37 | 38 | 39 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/367cf8ae-09ee-449d-93b0-4ae07e4c4695) 40 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/39ca53d8-698d-4c24-95c4-db80727a2d8e) 41 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/319af26f-db3a-47c3-b021-fd3040cfbc35) 42 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/26124f15-b1ab-4305-b6f4-17b50d14eb5c) 43 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/4dd5a8db-aee5-4742-b5e2-8bbfd6f609fa) 44 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/60962345-51e7-4ec8-b33d-df78984910e0) 45 | ![image](https://github.com/ehsanrezaee/DotNetBackend/assets/11017659/8a1fd421-a4e7-4775-ab16-76b0d9716f90) 46 | 47 | 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /data/database.sqlite: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehsanrezaee/DotNetBackend/6140150d231006937412603d0217926961a3f13a/data/database.sqlite -------------------------------------------------------------------------------- /data/keys.json: -------------------------------------------------------------------------------- 1 | { 2 | "key": "-----BEGIN RSA PRIVATE KEY-----\nMIIEogIBAAKCAQEAjsQVptOriM5wc/D9w8KFKXOJlW78Ocd7ixfbRLJJyzLgs6Jx\nVu0WJc4ludJyNnSCECtkH7tThOLYhks5cN08GuxPQpkNIfLlydlDbBpd88KU7l4y\nh9RUKXMt9I9iJkXCottP4pZeqxFqxqruI2ZgCF/fHBiHn+Wi1rtLIkIFTI+sdwaU\nX3CpcP9PXwMn39y0LQbY3saMEt1j8KDFvrsbfWS407gUti6IqI+I+/2bLqLKv8Tc\n+5X2VEYwuFva9HQ5SNCGjLr2OePR96i7m1GirpnSz71aCH4GpClKgxKvHhFjj5vy\nTZqicZPtlmqettZYf97NB0mgkxFXZPmTmVUIlwIDAQABAoIBAFSGwBL/6+WZ5Hag\nzn5i4xiBsYnqJifHddwKieYIcSx/uQ5iNRy0TpKflTKJ6NlY7dDJAATRkkdxT6Vj\nUGUEd5uxIdRaba4V8/soSYTtr4atRCRFXUGScyn/acwMQJ5MW0q08n1DblV2gHOT\nrF8FNAKBUMV/uHzxJxJf3cIwuJZ07WmBA+oS0oUUj8T2QHbcIwf1Nlvxy37uNnYo\njeJWVA8fqTQDRQhC6O6X2GCAzOduohmDz7PigcOl0UF2GjlXrtMFkAzn5kdAmof5\nyPh6RXIuoG0jhx6OzDt9eB2rFPZhBUxQroypaFhs4gmry3f6OqtPErJZgvLC0b0I\n4qYx4bECgYEA3TxG5twHRqdaTJ0A9tRSV2KVVIYNkhBwVlOVc/C+wwIt7prIPUPw\nsx2nlY7tgL3jgjB3IWQAO4WOxwEsFDpXvlUuauubRbyJbDLXmJn9rU6wmvtedK2A\nnc4YGhQs2bgnPJnhmmxFU9n+/3Su+i9+I5r148cIPsuNfrpntCQswlMCgYEApTMv\nYQN6uHA2rh0iawR2wU+pF9JXd8FBwCRasDk8IOuByg2TCGquWttg4OJtKOM7VaX/\n/enGwI9AFTSBcYQd+8IwMy4CXKPI72QRUztdjUm3WXPVvkwNr+q01q9mtPfGQ20h\noSuwPdyZBIU2cV9WthdldecD0Vsrubzar6GRoC0CgYBUaQQwXzETfxTP+HN+ucH0\n/3M0fbU9zrHd7iQuyWMvamx2Bm5yGbMD1EO1p4PsxAbDDJTXk50XGL1CJqtXyG7j\n+wIr31st/2J7euaRneeRMV3mtBP09qIFE7ZUdPAr3bxyvc+7KKZG+Pz3IOEGKgq5\nsQ0ybCU0OFvzR1H8BHVjawKBgGlHs3waIY2FRfO0cYjOMXiE8fhSfpe9O8/d20XP\nU/iO3goMmJWWl0Mj6BupcXPLTLcKsZf58kYphOd+rLfRQOJ/IQSc37h2UMnvdfMb\nNEWkowqI/cDm6xofc9wVsFjIRzwVQodaNllWStZMpyOdZL9rLafz78TuW3FlX+Dq\nEMqJAoGATYEYPnvOriTKSMnshvOUE6bwOtMoVVud0f59rjgrPPvhQsvkdn9/pn8f\nXK9Bse8kVbTyMp5nzgRAd18E6F2b1UKe+io/H8iWK4Sh4Yjx034pslZ1rZBfYpUY\nVWnCRKwxMxULy6EAtrlihPA8sWnZm+Z1CbmoBmI4t8IwmTxWb1U=\n-----END RSA PRIVATE KEY-----", 3 | "pub": "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAjsQVptOriM5wc/D9w8KF\nKXOJlW78Ocd7ixfbRLJJyzLgs6JxVu0WJc4ludJyNnSCECtkH7tThOLYhks5cN08\nGuxPQpkNIfLlydlDbBpd88KU7l4yh9RUKXMt9I9iJkXCottP4pZeqxFqxqruI2Zg\nCF/fHBiHn+Wi1rtLIkIFTI+sdwaUX3CpcP9PXwMn39y0LQbY3saMEt1j8KDFvrsb\nfWS407gUti6IqI+I+/2bLqLKv8Tc+5X2VEYwuFva9HQ5SNCGjLr2OePR96i7m1Gi\nrpnSz71aCH4GpClKgxKvHhFjj5vyTZqicZPtlmqettZYf97NB0mgkxFXZPmTmVUI\nlwIDAQAB\n-----END PUBLIC KEY-----" 4 | } -------------------------------------------------------------------------------- /launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Docker Compose": { 4 | "commandName": "DockerCompose", 5 | "commandVersion": "1.0", 6 | "serviceActions": { 7 | "ersoftdev.identity.endpoint": "StartDebugging" 8 | } 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "dotnet-ef": { 6 | "version": "8.0.5", 7 | "commands": [ 8 | "dotnet-ef" 9 | ] 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Application/HealthChecks/IdentityGrpcServiceHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.ApiGateway.Infrastructure.ServiceProviderConfiguration.Identity; 2 | using ErSoftDev.DomainSeedWork; 3 | using Microsoft.Extensions.Diagnostics.HealthChecks; 4 | 5 | namespace ErSoftDev.ApiGateway.Application.HealthChecks 6 | { 7 | public class IdentityGrpcServiceHealthCheck : IHealthCheck 8 | { 9 | private readonly IAccountService _accountService; 10 | 11 | public IdentityGrpcServiceHealthCheck(IAccountService accountService) 12 | { 13 | _accountService = accountService; 14 | } 15 | public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) 16 | { 17 | try 18 | { 19 | await _accountService.IsSecurityStampTokenValid("any security token"); 20 | return HealthCheckResult.Healthy(); 21 | } 22 | catch (Exception ex) 23 | { 24 | return HealthCheckResult.Unhealthy(); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 4 | USER app 5 | WORKDIR /app 6 | EXPOSE 8080 7 | EXPOSE 8081 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 10 | ARG BUILD_CONFIGURATION=Release 11 | WORKDIR /src 12 | COPY ["src/ApiGateway/ErSoftDev.ApiGateway/ErSoftDev.ApiGateway.csproj", "src/ApiGateway/ErSoftDev.ApiGateway/"] 13 | COPY ["src/ErSoftDev.Framework/ErSoftDev.Framework.csproj", "src/ErSoftDev.Framework/"] 14 | COPY ["src/ErSoftDev.Common/ErSoftDev.Common.csproj", "src/ErSoftDev.Common/"] 15 | COPY ["src/ErSoftDev.DomainSeedWork/ErSoftDev.DomainSeedWork.csproj", "src/ErSoftDev.DomainSeedWork/"] 16 | RUN dotnet restore "./src/ApiGateway/ErSoftDev.ApiGateway/ErSoftDev.ApiGateway.csproj" 17 | COPY . . 18 | WORKDIR "/src/src/ApiGateway/ErSoftDev.ApiGateway" 19 | RUN dotnet build "./ErSoftDev.ApiGateway.csproj" -c $BUILD_CONFIGURATION -o /app/build 20 | 21 | FROM build AS publish 22 | ARG BUILD_CONFIGURATION=Release 23 | RUN dotnet publish "./ErSoftDev.ApiGateway.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 24 | 25 | FROM base AS final 26 | WORKDIR /app 27 | COPY --from=publish /app/publish . 28 | ENTRYPOINT ["dotnet", "ErSoftDev.ApiGateway.dll"] -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/ErSoftDev.ApiGateway.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | bfd227b7-eb90-46b4-84c0-9c3a76c7cbe9 8 | Linux 9 | ..\..\.. 10 | True 11 | GatewayXmlComment.xml 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | all 28 | runtime; build; native; contentfiles; analyzers; buildtransitive 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Infrastructure/ServiceProviderConfiguration/Google/ProtoBuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package google.protobuf; 4 | 5 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 6 | option cc_enable_arenas = true; 7 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 8 | option java_package = "com.google.protobuf"; 9 | option java_outer_classname = "WrappersProto"; 10 | option java_multiple_files = true; 11 | option objc_class_prefix = "GPB"; 12 | 13 | // Wrapper message for `double`. 14 | // 15 | // The JSON representation for `DoubleValue` is JSON number. 16 | message DoubleValue { 17 | // The double value. 18 | double value = 1; 19 | } 20 | 21 | // Wrapper message for `float`. 22 | // 23 | // The JSON representation for `FloatValue` is JSON number. 24 | message FloatValue { 25 | // The float value. 26 | float value = 1; 27 | } 28 | 29 | // Wrapper message for `int64`. 30 | // 31 | // The JSON representation for `Int64Value` is JSON string. 32 | message Int64Value { 33 | // The int64 value. 34 | int64 value = 1; 35 | } 36 | 37 | // Wrapper message for `uint64`. 38 | // 39 | // The JSON representation for `UInt64Value` is JSON string. 40 | message UInt64Value { 41 | // The uint64 value. 42 | uint64 value = 1; 43 | } 44 | 45 | // Wrapper message for `int32`. 46 | // 47 | // The JSON representation for `Int32Value` is JSON number. 48 | message Int32Value { 49 | // The int32 value. 50 | int32 value = 1; 51 | } 52 | 53 | // Wrapper message for `uint32`. 54 | // 55 | // The JSON representation for `UInt32Value` is JSON number. 56 | message UInt32Value { 57 | // The uint32 value. 58 | uint32 value = 1; 59 | } 60 | 61 | // Wrapper message for `bool`. 62 | // 63 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 64 | message BoolValue { 65 | // The bool value. 66 | bool value = 1; 67 | } 68 | 69 | // Wrapper message for `string`. 70 | // 71 | // The JSON representation for `StringValue` is JSON string. 72 | message StringValue { 73 | // The string value. 74 | string value = 1; 75 | } 76 | 77 | // Wrapper message for `bytes`. 78 | // 79 | // The JSON representation for `BytesValue` is JSON string. 80 | message BytesValue { 81 | // The bytes value. 82 | bytes value = 1; 83 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Infrastructure/ServiceProviderConfiguration/Identity/AccountService.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.Configuration; 2 | using ErSoftDev.Identity.EndPoint.Grpc.Protos; 3 | 4 | namespace ErSoftDev.ApiGateway.Infrastructure.ServiceProviderConfiguration.Identity 5 | { 6 | public class AccountService : IAccountService, ITransientDependency 7 | { 8 | private readonly AccountGrpcService.AccountGrpcServiceClient _accountGrpcServiceClient; 9 | 10 | public AccountService(AccountGrpcService.AccountGrpcServiceClient accountGrpcServiceClient) 11 | { 12 | _accountGrpcServiceClient = accountGrpcServiceClient; 13 | } 14 | public async Task IsSecurityStampTokenValid(string securityStampToken) 15 | { 16 | return await _accountGrpcServiceClient.IsSecurityStampTokenValidAsync( 17 | new IsSecurityStampTokenRequestGrpc() 18 | { SecurityStampToken = securityStampToken }); 19 | } 20 | 21 | public async Task IsAuthorize(string securityStampToken, string operate) 22 | { 23 | return await _accountGrpcServiceClient.CheckAuthorizeAsync(new CheckAuthorizeRequestGrpc() 24 | { SecurityStampToken = securityStampToken, Operate = operate }); 25 | } 26 | 27 | public async Task CheckAuthenticateAndAuthorization(string securityStampToken, string operate) 28 | { 29 | return await _accountGrpcServiceClient.CheckAuthenticationAndAuthorizationAsync( 30 | new CheckAuthenticationAndAuthorizationGrpcRequest() 31 | { SecurityStampToken = securityStampToken, Operate = operate }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Infrastructure/ServiceProviderConfiguration/Identity/IAccountService.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.EndPoint.Grpc.Protos; 2 | 3 | namespace ErSoftDev.ApiGateway.Infrastructure.ServiceProviderConfiguration.Identity; 4 | 5 | public interface IAccountService 6 | { 7 | Task IsSecurityStampTokenValid(string securityStampToken); 8 | Task IsAuthorize(string securityStampToken, string operate); 9 | 10 | Task CheckAuthenticateAndAuthorization(string securityStampToken, 11 | string operate); 12 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Infrastructure/ServiceProviderConfiguration/Identity/Protos/AccountProto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "ErSoftDev.Identity.EndPoint.Grpc.Protos"; 3 | package AccountGrpcService; 4 | import "google/protobuf/wrappers.proto"; 5 | 6 | service AccountGrpcService{ 7 | rpc IsSecurityStampTokenValid(IsSecurityStampTokenRequestGrpc) returns (IsSecurityStampTokenResponseGrpc); 8 | rpc CheckAuthorize(CheckAuthorizeRequestGrpc) returns (CheckAuthorizeResponseGrpc); 9 | rpc CheckAuthenticationAndAuthorization(CheckAuthenticationAndAuthorizationGrpcRequest) returns (CheckAuthenticationAndAuthorizationGrpcResponse); 10 | } 11 | 12 | message IsSecurityStampTokenRequestGrpc{ 13 | string SecurityStampToken=1; 14 | } 15 | message IsSecurityStampTokenResponseGrpc{ 16 | int32 Status=1; 17 | string Description=2; 18 | .google.protobuf.Int32Value ErrorCode=3; 19 | .google.protobuf.StringValue ErrorDescription=4; 20 | } 21 | 22 | message CheckAuthorizeRequestGrpc{ 23 | string SecurityStampToken=1; 24 | string Operate=2; 25 | } 26 | message CheckAuthorizeResponseGrpc{ 27 | int32 Status=1; 28 | string Description=2; 29 | .google.protobuf.Int32Value ErrorCode=3; 30 | .google.protobuf.StringValue ErrorDescription=4; 31 | } 32 | 33 | message CheckAuthenticationAndAuthorizationGrpcRequest{ 34 | string SecurityStampToken=1; 35 | string Operate=2; 36 | } 37 | message CheckAuthenticationAndAuthorizationGrpcResponse{ 38 | int32 Status=1; 39 | string Description=2; 40 | .google.protobuf.Int32Value ErrorCode=3; 41 | .google.protobuf.StringValue ErrorDescription=4; 42 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Ocelot/Development/Ocelot.Global.Json: -------------------------------------------------------------------------------- 1 | { 2 | "GlobalConfiguration": { 3 | "BaseUrl": "https://localhost:5003", 4 | "ServiceDiscoveryProvider": { 5 | "Host": "localhost", 6 | "Port": 8500, 7 | "Type": "PollConsul", 8 | "PollingInterval": 100 9 | //"Type": "Consul" - Each Request it will update information 10 | /* 11 | Type 12 | Consul, means that Ocelot will get service information from consul per request 13 | PollConsul, means that Ocelot will poll Consul for latest service information 14 | */ 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Ocelot/Development/Ocelot.SwaggerEndPoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "SwaggerEndPoints": [ 3 | { 4 | "Key": "Identity", 5 | "TransformByOcelotConfig": false, 6 | "Config": [ 7 | { 8 | "Name": "Identity API", 9 | "Version": "1.0", 10 | "Url": "https://localhost:5002/swagger/v1.0/swagger.json" 11 | } 12 | ] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Ocelot/Docker/Ocelot.Global.Json: -------------------------------------------------------------------------------- 1 | { 2 | "GlobalConfiguration": { 3 | "BaseUrl": "https://localhost:5203", 4 | "ServiceDiscoveryProvider": { 5 | "Host": "host.docker.internal", 6 | "Port": 8500, 7 | "Type": "PollConsul", 8 | "PollingInterval": 100 9 | //"Type": "Consul" - Each Request it will update information 10 | /* 11 | Type 12 | Consul, means that Ocelot will get service information from consul per request 13 | PollConsul, means that Ocelot will poll Consul for latest service information 14 | */ 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Ocelot/Docker/Ocelot.Identity.Api.json: -------------------------------------------------------------------------------- 1 | { 2 | "Routes": [ 3 | { 4 | "UseServiceDiscovery": true, 5 | "ServiceName": "Identity", 6 | "UpstreamPathTemplate": "/Identity/{everything}}", 7 | "UpstreamHttpMethod": [ "POST", "PUT", "GET" ], 8 | "DownstreamPathTemplate": "/Identity/{everything}}", 9 | "DownstreamScheme": "http", 10 | "SwaggerKey": "Identity", 11 | "Priority": 1, 12 | "ReRoutesCaseSensitive": false, 13 | "LoadBalancerOptions": { 14 | "Type": "LeastConnection" 15 | } 16 | //}, 17 | //{ 18 | // "UseServiceDiscovery": true, 19 | // "ServiceName": "Identity", 20 | // "UpstreamPathTemplate": "/api/{version}/Account/Register", 21 | // "UpstreamHttpMethod": [ "POST" ], 22 | // "DownstreamPathTemplate": "/api/{version}/Account/Register", 23 | // "DownstreamScheme": "http", 24 | // "SwaggerKey": "Identity", 25 | // "Priority": 1, 26 | // "ReRoutesCaseSensitive": false, 27 | // "LoadBalancerOptions": { 28 | // "Type": "LeastConnection" 29 | // } 30 | //}, 31 | //{ 32 | // "UseServiceDiscovery": true, 33 | // "ServiceName": "Identity", 34 | // "UpstreamPathTemplate": "/api/{version}/Account/Update", 35 | // "UpstreamHttpMethod": [ "PUT" ], 36 | // "DownstreamPathTemplate": "/api/{version}/Account/Update", 37 | // "DownstreamScheme": "http", 38 | // "SwaggerKey": "Identity", 39 | // "Priority": 1, 40 | // "ReRoutesCaseSensitive": false, 41 | // "LoadBalancerOptions": { 42 | // "Type": "LeastConnection" 43 | // } 44 | //}, 45 | //{ 46 | // "UseServiceDiscovery": true, 47 | // "ServiceName": "Identity", 48 | // "UpstreamPathTemplate": "/api/{version}/Account/GetRefreshToken", 49 | // "UpstreamHttpMethod": [ "POST" ], 50 | // "DownstreamPathTemplate": "/api/{version}/Account/GetRefreshToken", 51 | // "DownstreamScheme": "http", 52 | // "SwaggerKey": "Identity", 53 | // "Priority": 1, 54 | // "ReRoutesCaseSensitive": false, 55 | // "LoadBalancerOptions": { 56 | // "Type": "LeastConnection" 57 | // } 58 | //}, 59 | //{ 60 | // "UseServiceDiscovery": true, 61 | // "ServiceName": "Identity", 62 | // "UpstreamPathTemplate": "/api/{version}/Account/RevokeRefreshToken", 63 | // "UpstreamHttpMethod": [ "POST" ], 64 | // "DownstreamPathTemplate": "/api/{version}/Account/RevokeRefreshToken", 65 | // "DownstreamScheme": "http", 66 | // "SwaggerKey": "Identity", 67 | // "Priority": 1, 68 | // "ReRoutesCaseSensitive": false, 69 | // "LoadBalancerOptions": { 70 | // "Type": "LeastConnection" 71 | // } 72 | //} 73 | ] 74 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Ocelot/Docker/Ocelot.SwaggerEndPoints.json: -------------------------------------------------------------------------------- 1 | { 2 | "SwaggerEndPoints": [ 3 | { 4 | "Key": "Identity", 5 | "TransformByOcelotConfig": false, 6 | "Config": [ 7 | { 8 | "Name": "Identity API", 9 | "Version": "1.0", 10 | "Url": "http://host.docker.internal:5202/swagger/v1.0/swagger.json" 11 | } 12 | ] 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Program.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Extensions.DependencyInjection; 3 | using ErSoftDev.Framework.BaseApp; 4 | using ErSoftDev.Framework.Configuration; 5 | using MMLib.SwaggerForOcelot.DependencyInjection; 6 | using Ocelot.Cache.CacheManager; 7 | using Ocelot.DependencyInjection; 8 | using Ocelot.Provider.Consul; 9 | using Ocelot.Provider.Polly; 10 | using Configuration = ErSoftDev.ApiGateway.Configuration; 11 | 12 | var builder = WebApplication.CreateBuilder(args); 13 | 14 | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer( 15 | (context, containerBuilder) => containerBuilder.RegisterModule(new AutofacConfigurationExtension())); 16 | 17 | var appConfig = new Configuration(builder.Configuration, builder.Environment); 18 | appConfig.ConfigureServices(builder.Services); 19 | 20 | var ocelot = "Ocelot/" + builder.Environment.EnvironmentName + ""; 21 | 22 | builder.Configuration.AddOcelotWithSwaggerSupport(options => 23 | { 24 | options.Folder = ocelot; 25 | }); 26 | builder.Services.AddOcelot(builder.Configuration) 27 | .AddCacheManager(x => { x.WithDictionaryHandle(); }) 28 | .AddPolly() 29 | .AddConsul(); 30 | builder.Services.AddSwaggerForOcelot(builder.Configuration); 31 | 32 | var appSettings = builder.Configuration 33 | .GetSection($"{nameof(AppSetting)}{builder.Environment.EnvironmentName}") 34 | .Get(); 35 | 36 | var app = builder.Build(); 37 | appConfig.Configure(app, builder.Environment, appSettings); 38 | app.Run(); -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "environmentVariables": { 7 | "ASPNETCORE_ENVIRONMENT": "Development" 8 | }, 9 | "dotnetRunMessages": true, 10 | "applicationUrl": "http://localhost:5016" 11 | }, 12 | "https": { 13 | "commandName": "Project", 14 | "launchBrowser": true, 15 | "environmentVariables": { 16 | "ASPNETCORE_ENVIRONMENT": "Development" 17 | }, 18 | "dotnetRunMessages": true, 19 | "applicationUrl": "https://localhost:7057;http://localhost:5016" 20 | }, 21 | "IIS Express": { 22 | "commandName": "IISExpress", 23 | "launchBrowser": true, 24 | "environmentVariables": { 25 | "ASPNETCORE_ENVIRONMENT": "Development" 26 | } 27 | }, 28 | "Development": { 29 | "commandName": "Project", 30 | "launchBrowser": true, 31 | "environmentVariables": { 32 | "ASPNETCORE_ENVIRONMENT": "Development" 33 | }, 34 | "applicationUrl": "https://localhost:5003;http://localhost:5103", 35 | "launchUrl": "swagger" 36 | }, 37 | "Docker": { 38 | "commandName": "Docker", 39 | "launchBrowser": true, 40 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 41 | "publishAllPorts": true, 42 | "useSSL": false, 43 | "environmentVariables": { 44 | "ASPNETCORE_ENVIRONMENT": "Docker" 45 | }, 46 | "httpPort": 5203 47 | } 48 | }, 49 | "iisSettings": { 50 | "windowsAuthentication": false, 51 | "anonymousAuthentication": true, 52 | "iisExpress": { 53 | "applicationUrl": "http://localhost:55742", 54 | "sslPort": 44373 55 | } 56 | } 57 | } -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/SeedWorks/ApiGatewayResultStatusCode.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.ApiGateway.SeedWorks 4 | { 5 | public class ApiGatewayResultStatusCode : ApiResultStatusCode 6 | { 7 | public static ApiGatewayResultStatusCode IdentityServerIsNotAvailable => new(201, nameof(IdentityServerIsNotAvailable)); 8 | public static ApiGatewayResultStatusCode AuthorizationFailed => new(202, nameof(AuthorizationFailed)); 9 | 10 | public ApiGatewayResultStatusCode(int id, string name) : base(id, name) 11 | { 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSettingDevelopment": { 3 | "Logging": { 4 | "LogLevel": "debug" 5 | }, 6 | "Jaeger": { 7 | "Host": "localhost", 8 | "Port": 5775, 9 | "SamplingRate": 0.5 10 | }, 11 | "Jwt": { 12 | "Issuer": "Identity", 13 | "Audience": "ApiUsers", 14 | "IdentityUrl": "https://localhost:5002/" 15 | }, 16 | "Swagger": { 17 | "SpecificationTitle": "Gateway Project", 18 | "XmlCommentFileName": "GatewayXmlComment.xml", 19 | "VersionCount": 1 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/appsettings.Docker.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSettingDocker": { 3 | "Logging": { 4 | "LogLevel": "debug" 5 | }, 6 | "Jaeger": { 7 | "Host": "localhost", 8 | "Port": 5775, 9 | "SamplingRate": 0.5 10 | }, 11 | "Jwt": { 12 | "Issuer": "Identity", 13 | "Audience": "ApiUsers", 14 | "IdentityUrl": "http://host.docker.internal:5202/" 15 | }, 16 | "Swagger": { 17 | "SpecificationTitle": "Gateway Project", 18 | "XmlCommentFileName": "GatewayXmlComment.xml", 19 | "VersionCount": 1 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/ApiGateway/ErSoftDev.ApiGateway/ocelot.json: -------------------------------------------------------------------------------- 1 | {"Routes":[{"SwaggerKey":"Identity","AddClaimsToRequest":{},"AddHeadersToRequest":{},"AddQueriesToRequest":{},"AuthenticationOptions":{"AuthenticationProviderKey":null,"AllowedScopes":[]},"ChangeDownstreamPathTemplate":{},"DangerousAcceptAnyServerCertificateValidator":false,"DelegatingHandlers":[],"DownstreamHeaderTransform":{},"DownstreamHostAndPorts":[],"DownstreamHttpMethod":null,"DownstreamHttpVersion":null,"DownstreamPathTemplate":"/Identity/{everything}","DownstreamScheme":"https","FileCacheOptions":{"Region":"","TtlSeconds":0},"HttpHandlerOptions":{"AllowAutoRedirect":false,"MaxConnectionsPerServer":2147483647,"UseCookieContainer":false,"UseProxy":true,"UseTracing":false},"Key":null,"LoadBalancerOptions":{"Expiry":2147483647,"Key":"","Type":"LeastConnection"},"Priority":1,"QoSOptions":{"DurationOfBreak":1,"ExceptionsAllowedBeforeBreaking":0,"TimeoutValue":0},"RateLimitOptions":{"ClientWhitelist":[],"EnableRateLimiting":false,"Period":null,"PeriodTimespan":0.0,"Limit":0},"RequestIdKey":null,"RouteClaimsRequirement":{},"RouteIsCaseSensitive":false,"SecurityOptions":{"IPAllowedList":[],"IPBlockedList":[],"ExcludeAllowedFromBlocked":false},"ServiceName":"Identity","ServiceNamespace":null,"Timeout":0,"UpstreamHeaderTransform":{},"UpstreamHost":null,"UpstreamHttpMethod":["POST","GET","PUT"],"UpstreamPathTemplate":"/Identity/{everything}"}],"DynamicRoutes":[],"Aggregates":[],"GlobalConfiguration":{"RequestIdKey":null,"ServiceDiscoveryProvider":{"Scheme":null,"Host":"localhost","Port":8500,"Type":"PollConsul","Token":null,"ConfigurationKey":null,"PollingInterval":100,"Namespace":null},"RateLimitOptions":{"ClientIdHeader":"ClientId","QuotaExceededMessage":null,"RateLimitCounterPrefix":"ocelot","DisableRateLimitHeaders":false,"HttpStatusCode":429},"QoSOptions":{"DurationOfBreak":1,"ExceptionsAllowedBeforeBreaking":0,"TimeoutValue":0},"BaseUrl":"https://localhost:5003","LoadBalancerOptions":{"Expiry":2147483647,"Key":"","Type":""},"DownstreamScheme":null,"HttpHandlerOptions":{"AllowAutoRedirect":false,"MaxConnectionsPerServer":2147483647,"UseCookieContainer":false,"UseProxy":true,"UseTracing":false},"DownstreamHttpVersion":null},"SwaggerEndPoints":[{"Key":"Identity","VersionPlaceholder":"{version}","KeyToPath":"Identity","Config":[{"Name":"Identity API","Version":"1.0","Url":"https://localhost:5002/swagger/v1.0/swagger.json","Service":null}],"HostOverride":null,"TransformByOcelotConfig":false,"RemoveUnusedComponentsFromScheme":true,"TakeServersFromDownstreamService":false}]} -------------------------------------------------------------------------------- /src/ErSoftDev.Common/ErSoftDev.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/ApiHelper.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http.Headers; 2 | using Newtonsoft.Json; 3 | 4 | namespace ErSoftDev.Common.Utilities 5 | { 6 | public static class ApiHelper 7 | { 8 | public static async Task SendHttpAsync(IHttpClientFactory client, 9 | string serviceUrl, 10 | TRequest? request, HttpMethod httpMethod, CancellationToken cancellationToken 11 | , Dictionary? headers = null, string contentType = "application/json") 12 | { 13 | 14 | var httpRequestMessage = new HttpRequestMessage(httpMethod, serviceUrl); 15 | if (request is not null) 16 | httpRequestMessage.Content = new HttpContentConvert(request); 17 | if (httpRequestMessage.Content is not null) 18 | httpRequestMessage.Content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); 19 | if (headers != null) 20 | foreach (var header in headers) 21 | httpRequestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value); 22 | 23 | return await client.CreateClient().SendAsync(httpRequestMessage, cancellationToken); 24 | } 25 | 26 | public static async Task> StreamAndDeserialize(HttpResponseMessage response, 27 | CancellationToken cancellationToken) 28 | { 29 | var responseStream = await response.Content.ReadAsStringAsync(cancellationToken); 30 | var deserializeResponse = 31 | JsonConvert.DeserializeObject(responseStream); 32 | 33 | return new StreamAndDeserializeResponse(responseStream, deserializeResponse!); 34 | } 35 | } 36 | public class StreamAndDeserializeResponse 37 | { 38 | public StreamAndDeserializeResponse(string stream, T deserialize) 39 | { 40 | Stream = stream; 41 | Deserialize = deserialize; 42 | } 43 | 44 | public string Stream { get; set; } 45 | public T Deserialize { get; set; } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/AttributeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace ErSoftDev.Common.Utilities 5 | { 6 | public static class AttributeExtensions 7 | { 8 | public static TValue GetAttributeValue( 9 | this Type type, 10 | Func valueSelector) 11 | where TAttribute : Attribute 12 | { 13 | var att = type.GetCustomAttributes( 14 | typeof(TAttribute), true 15 | ).FirstOrDefault() as TAttribute; 16 | if (att != null) 17 | { 18 | return valueSelector(att); 19 | } 20 | return default(TValue); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/DateExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | 3 | namespace ErSoftDev.Common.Utilities 4 | { 5 | public static class DateExtension 6 | { 7 | public static string GrepToPersian(this string grep) 8 | { 9 | DateTime grepConvert; 10 | grepConvert = Convert.ToDateTime(grep); 11 | 12 | PersianCalendar persianDate = new PersianCalendar(); 13 | string outDate = persianDate.GetYear(grepConvert) + "/"; 14 | if (persianDate.GetMonth(grepConvert).ToString().Length == 1) outDate += "0"; 15 | outDate = outDate + persianDate.GetMonth(grepConvert) + "/"; 16 | if (persianDate.GetDayOfMonth(grepConvert).ToString().Length == 1) outDate += "0"; 17 | outDate += persianDate.GetDayOfMonth(grepConvert); 18 | 19 | return outDate; 20 | } 21 | 22 | public static string GrepToPersianWithTime(this string grep) 23 | { 24 | DateTime grepConvert; 25 | grepConvert = Convert.ToDateTime(grep); 26 | 27 | PersianCalendar persianDate = new PersianCalendar(); 28 | string outDate = persianDate.GetYear(grepConvert) + "/"; 29 | if (persianDate.GetMonth(grepConvert).ToString().Length == 1) outDate += "0"; 30 | outDate = outDate + persianDate.GetMonth(grepConvert) + "/"; 31 | if (persianDate.GetDayOfMonth(grepConvert).ToString().Length == 1) outDate += "0"; 32 | outDate += persianDate.GetDayOfMonth(grepConvert); 33 | 34 | outDate += " " + grepConvert.TimeOfDay; 35 | 36 | return outDate; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/EnumExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using System.Reflection; 3 | 4 | namespace ErSoftDev.Common.Utilities 5 | { 6 | public static class EnumExtensions 7 | { 8 | public static IEnumerable GetEnumValues(this T input) where T : struct 9 | { 10 | if (!typeof(T).IsEnum) 11 | throw new NotSupportedException(); 12 | 13 | return Enum.GetValues(input.GetType()).Cast(); 14 | } 15 | 16 | public static int ToInt(this Enum value) 17 | { 18 | return Convert.ToInt32(value); 19 | } 20 | 21 | 22 | public static string ToDisplay(this Enum value, DisplayProperty property = DisplayProperty.Name) 23 | { 24 | var attribute = value.GetType().GetField(value.ToString()).GetCustomAttributes(false).FirstOrDefault(); 25 | 26 | if (attribute == null) 27 | return value.ToString(); 28 | 29 | var propValue = attribute.GetType().GetProperty(property.ToString()).GetValue(attribute, null); 30 | return propValue.ToString(); 31 | } 32 | 33 | public static Dictionary ToDictionary(this Enum value) 34 | { 35 | return Enum.GetValues(value.GetType()).Cast().ToDictionary(p => Convert.ToInt32(p), q => ToDisplay(q)); 36 | } 37 | 38 | public static bool IsValidEnum(this Enum value) 39 | { 40 | return value.GetType().GetField(value.ToString()) != null; 41 | } 42 | public static string GetStringValue(this Enum value) 43 | { 44 | Type type = value.GetType(); 45 | FieldInfo fieldInfo = type.GetField(value.ToString()); 46 | // Get the stringvalue attributes 47 | EnumStringAttribute[] attribs = fieldInfo.GetCustomAttributes( 48 | typeof(EnumStringAttribute), false) as EnumStringAttribute[]; 49 | // Return the first if there was a match. 50 | return attribs.Length > 0 ? attribs[0].StringValue : null; 51 | } 52 | 53 | } 54 | 55 | public enum DisplayProperty 56 | { 57 | Description, 58 | GroupName, 59 | Name, 60 | Prompt, 61 | ShortName, 62 | Order 63 | } 64 | 65 | public class EnumStringAttribute : Attribute 66 | { 67 | public EnumStringAttribute(string stringValue) 68 | { 69 | this.stringValue = stringValue; 70 | } 71 | private string stringValue; 72 | public string StringValue 73 | { 74 | get { return stringValue; } 75 | set { stringValue = value; } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/FullNameAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Common.Utilities 2 | { 3 | public class FullNameAttribute(string name) : Attribute 4 | { 5 | public string Name { get; set; } = name; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/GenericTypeExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Common.Utilities 2 | { 3 | public static class GenericTypeExtensions 4 | { 5 | public static string GetGenericTypeName(this Type type) 6 | { 7 | string typeName; 8 | 9 | if (type.IsGenericType) 10 | { 11 | var genericTypes = string.Join(",", type.GetGenericArguments().Select(t => t.Name).ToArray()); 12 | typeName = $"{type.Name.Remove(type.Name.IndexOf('`'))}<{genericTypes}>"; 13 | } 14 | else 15 | { 16 | typeName = type.Name; 17 | } 18 | 19 | return typeName; 20 | } 21 | 22 | public static string GetGenericTypeName(this object @object) 23 | { 24 | return @object.GetType().GetGenericTypeName(); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/GeometryExtension.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Common.Utilities 2 | { 3 | public class Coordinates 4 | { 5 | public double Latitude { get; private set; } 6 | public double Longitude { get; private set; } 7 | 8 | public Coordinates(double latitude, double longitude) 9 | { 10 | Latitude = latitude; 11 | Longitude = longitude; 12 | } 13 | } 14 | 15 | public static class CoordinatesDistanceExtensions 16 | { 17 | public static double DistanceTo(this Coordinates baseCoordinates, Coordinates targetCoordinates) 18 | { 19 | return DistanceTo(baseCoordinates, targetCoordinates, UnitOfLength.Kilometers); 20 | } 21 | 22 | public static double DistanceTo(this Coordinates baseCoordinates, Coordinates targetCoordinates, 23 | UnitOfLength unitOfLength) 24 | { 25 | var baseRad = Math.PI * baseCoordinates.Latitude / 180; 26 | var targetRad = Math.PI * targetCoordinates.Latitude / 180; 27 | var theta = baseCoordinates.Longitude - targetCoordinates.Longitude; 28 | var thetaRad = Math.PI * theta / 180; 29 | 30 | double dist = 31 | Math.Sin(baseRad) * Math.Sin(targetRad) + Math.Cos(baseRad) * 32 | Math.Cos(targetRad) * Math.Cos(thetaRad); 33 | dist = Math.Acos(dist); 34 | 35 | dist = dist * 180 / Math.PI; 36 | dist = dist * 60 * 1.1515; 37 | 38 | return unitOfLength.ConvertFromMiles(dist); 39 | } 40 | } 41 | 42 | public class UnitOfLength 43 | { 44 | public static UnitOfLength Kilometers = new UnitOfLength(1.609344); 45 | public static UnitOfLength NauticalMiles = new UnitOfLength(0.8684); 46 | public static UnitOfLength Miles = new UnitOfLength(1); 47 | 48 | private readonly double _fromMilesFactor; 49 | 50 | private UnitOfLength(double fromMilesFactor) 51 | { 52 | _fromMilesFactor = fromMilesFactor; 53 | } 54 | 55 | public double ConvertFromMiles(double input) 56 | { 57 | return input * _fromMilesFactor; 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/GrpCustomType.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Common.Utilities 2 | { 3 | public partial class DecimalValue 4 | { 5 | private const decimal NanoFactor = 1_000_000_000; 6 | public long Units { get; set; } 7 | public int Nanos { get; set; } 8 | public DecimalValue(long units, int nanos) 9 | { 10 | Units = units; 11 | Nanos = nanos; 12 | } 13 | 14 | public static implicit operator decimal(DecimalValue grpcDecimal) 15 | { 16 | return grpcDecimal.Units + grpcDecimal.Nanos / NanoFactor; 17 | } 18 | 19 | public static implicit operator DecimalValue(decimal value) 20 | { 21 | var units = decimal.ToInt64(value); 22 | var nanos = decimal.ToInt32((value - units) * NanoFactor); 23 | return new DecimalValue(units, nanos); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/HttpContextAccessorExtension.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | using Microsoft.AspNetCore.Http; 3 | 4 | namespace ErSoftDev.Common.Utilities 5 | { 6 | public static class HttpContextAccessorExtension 7 | { 8 | public static string ClientIp(this IHttpContextAccessor actionContextAccessor) 9 | { 10 | return actionContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString(); 11 | } 12 | public static string LocalIp(this IHttpContextAccessor accessor) 13 | { 14 | return accessor.HttpContext.Connection.LocalIpAddress.ToString(); 15 | } 16 | 17 | public static string HostName(this IHttpContextAccessor accessor) 18 | { 19 | return accessor.HttpContext.Request.Host.Value; 20 | } 21 | 22 | public static string Schema(this IHttpContextAccessor accessor) 23 | { 24 | return accessor.HttpContext.Request.Scheme; 25 | } 26 | 27 | public static string? UsernameClaimIdentity(this IHttpContextAccessor accessor) 28 | { 29 | if (accessor.HttpContext.User.Identity is ClaimsIdentity identity) 30 | return identity.GetUserName(); 31 | 32 | return ""; 33 | } 34 | 35 | public static string? UserIdClaimIdentity(this IHttpContextAccessor accessor) 36 | { 37 | if (accessor?.HttpContext?.User?.Identity is ClaimsIdentity identity) 38 | return identity.GetUserId(); 39 | 40 | return "0"; 41 | } 42 | 43 | public static string? CustomClientIp(this IHttpContextAccessor accessor) 44 | { 45 | return accessor?.HttpContext?.Request.Headers["ClientIp"]; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/HttpContextConvert.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json.Serialization; 2 | using Newtonsoft.Json; 3 | using System.Text; 4 | 5 | namespace ErSoftDev.Common.Utilities 6 | { 7 | public class HttpContentConvert : StringContent 8 | { 9 | public HttpContentConvert(object obj) : 10 | base(JsonConvert.SerializeObject(obj, 11 | new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver() }), 12 | Encoding.UTF8, "multipart/form-data") 13 | { 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/IdentityExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Globalization; 2 | using System.Security.Claims; 3 | using System.Security.Principal; 4 | 5 | namespace ErSoftDev.Common.Utilities 6 | { 7 | public static class IdentityExtensions 8 | { 9 | public static string? FindFirstValue(this ClaimsIdentity identity, string claimType) 10 | { 11 | return identity.FindFirst(claimType)?.Value; 12 | } 13 | 14 | public static string? FindFirstValue(this IIdentity identity, string claimType) 15 | { 16 | var claimsIdentity = identity as ClaimsIdentity; 17 | return claimsIdentity?.FindFirstValue(claimType); 18 | } 19 | 20 | public static string? GetUserId(this IIdentity identity) 21 | { 22 | return identity.FindFirstValue(ClaimTypes.NameIdentifier); 23 | } 24 | 25 | public static T? GetUserId(this IIdentity identity) where T : IConvertible 26 | { 27 | var userId = identity.GetUserId(); 28 | return userId.HasValue() 29 | ? (T)Convert.ChangeType(userId, typeof(T), CultureInfo.InvariantCulture) 30 | : default(T); 31 | } 32 | 33 | public static string? GetUserName(this IIdentity identity) 34 | { 35 | return identity.FindFirstValue(ClaimTypes.Name); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/MapsterExtension.cs: -------------------------------------------------------------------------------- 1 | using Mapster; 2 | 3 | namespace ErSoftDev.Common.Utilities 4 | { 5 | public static class MapsterExtension 6 | { 7 | public static TTarget MapTo(this object source) 8 | { 9 | return source.Adapt(); 10 | } 11 | 12 | public static TTarget MapTo(this TSource source, bool ignoreNullValue = false) 13 | { 14 | if (ignoreNullValue) 15 | TypeAdapterConfig 16 | .NewConfig() 17 | .IgnoreNullValues(true); 18 | return source.Adapt(); 19 | } 20 | 21 | public static TTarget MapTo(this TSource source, TTarget destination, bool ignoreNullValue = false, int? maxDepth = null) 22 | { 23 | TypeAdapterConfig 24 | .NewConfig() 25 | .MaxDepth(maxDepth) 26 | .IgnoreNullValues(ignoreNullValue) 27 | .NameMatchingStrategy(NameMatchingStrategy.IgnoreCase) 28 | .Map(target => target, source1 => source1); 29 | return (TTarget)source.Adapt(destination, typeof(TSource), typeof(TTarget)); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/Paging.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace ErSoftDev.Common.Utilities 4 | { 5 | public abstract class PagedResultBase 6 | { 7 | public int PageIndex { get; set; } 8 | public int PageSize { get; set; } 9 | public int RowCount { get; set; } 10 | public int PageCount 11 | { 12 | get => (int)Math.Ceiling((double)RowCount / PageSize); 13 | set { } 14 | } 15 | 16 | public int FirstRowOnPage 17 | { 18 | get => (PageIndex) * PageSize + 1; 19 | set { } 20 | } 21 | 22 | public int LastRowOnPage 23 | { 24 | get => Math.Min((PageIndex + 1) * PageSize, RowCount); 25 | set { } 26 | } 27 | } 28 | 29 | public class PagedResult : PagedResultBase where T : class 30 | { 31 | public IList Rows { get; set; } 32 | 33 | public PagedResult() 34 | { 35 | Rows = new List(); 36 | } 37 | } 38 | 39 | public class PagingRequest 40 | { 41 | public int PageSize { get; set; } = 10; 42 | public int PageNumber { get; set; } = 0; 43 | public string OrderBy { get; set; } 44 | public OrderType OrderType { get; set; } = OrderType.Desc; 45 | } 46 | 47 | public enum OrderType 48 | { 49 | [Description("Desc")] 50 | Desc, 51 | [Description("Asc")] 52 | Asc 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/PagingExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace ErSoftDev.Common.Utilities 5 | { 6 | public static class PagingExtensions 7 | { 8 | public static async Task> GetPaged(this IQueryable query, int pageNumber, int pageSize, CancellationToken cancellationToken) where T : class 9 | { 10 | var pagedResult = new PagedResult 11 | { 12 | PageIndex = pageNumber, 13 | PageSize = pageSize, 14 | RowCount = await query.CountAsync(cancellationToken) 15 | }; 16 | var skip = (pageNumber) * pageSize; 17 | pagedResult.Rows = await query.Skip(skip).Take(pageSize).ToListAsync(cancellationToken); 18 | 19 | return pagedResult; 20 | } 21 | public static IQueryable OrderBy(this IQueryable source, string orderBy, string orderType) 22 | { 23 | var expression = source.Expression; 24 | var parameter = Expression.Parameter(typeof(T), "x"); 25 | var selector = Expression.PropertyOrField(parameter, orderBy); 26 | var method = string.Equals(orderType, "desc", StringComparison.OrdinalIgnoreCase) ? 27 | ("OrderByDescending") : 28 | ("OrderBy"); 29 | expression = Expression.Call(typeof(Queryable), method, 30 | new[] { source.ElementType, selector.Type }, 31 | expression, Expression.Quote(Expression.Lambda(selector, parameter))); 32 | 33 | return source.Provider.CreateQuery(expression); 34 | } 35 | } 36 | 37 | 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/ErSoftDev.Common/Utilities/SqlExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Microsoft.Data.SqlClient; 3 | 4 | namespace ErSoftDev.Common.Utilities 5 | { 6 | public static class SqlExtensions 7 | { 8 | public static string GetArguments(this object[] parameters, string spName = "") 9 | { 10 | var sbParamList = new StringBuilder(); 11 | if (spName.HasValue()) sbParamList.Append(spName + " "); 12 | foreach (SqlParameter item in parameters) 13 | { 14 | sbParamList.Append(item.ParameterName); 15 | sbParamList.Append(","); 16 | } 17 | return sbParamList.Remove(sbParamList.Length - 1, 1).ToString(); 18 | } 19 | public static string GetArguments(this SqlParameter[] parameters, string spName = "") 20 | { 21 | var sbParamList = new StringBuilder(); 22 | if (spName.HasValue()) sbParamList.Append(spName + " "); 23 | foreach (var item in parameters) 24 | { 25 | sbParamList.Append(item.ParameterName); 26 | sbParamList.Append(","); 27 | } 28 | return sbParamList.Remove(sbParamList.Length - 1, 1).ToString(); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/ApiResult.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Localization; 2 | using Newtonsoft.Json; 3 | 4 | namespace ErSoftDev.DomainSeedWork 5 | { 6 | public class ApiResult 7 | { 8 | [JsonProperty] 9 | public int Status { get; private set; } 10 | [JsonProperty] 11 | public string Description { get; private set; } 12 | 13 | public string? Message { get; private set; } 14 | 15 | public ApiResult(IStringLocalizer stringLocalizer, 16 | ApiResultStatusCode status, string? message = null 17 | ) 18 | { 19 | var strLocalizer = stringLocalizer; 20 | Status = status.Code; 21 | Description = strLocalizer[status.ToString()].ResourceNotFound 22 | ? ResourceHelper.GetValue(status.ToString()) 23 | : strLocalizer[status.ToString()]; 24 | Message = message; 25 | } 26 | } 27 | 28 | public class ApiResult : ApiResult 29 | where TData : class 30 | { 31 | private readonly IStringLocalizer _stringLocalizer; 32 | 33 | [JsonProperty(NullValueHandling = NullValueHandling.Ignore)] 34 | public TData? Data { get; set; } 35 | 36 | public ApiResult(IStringLocalizer stringLocalizer, 37 | ApiResultStatusCode status, TData? data = null, string? message = null) : base(stringLocalizer, status, message) 38 | { 39 | _stringLocalizer = stringLocalizer; 40 | Data = data; 41 | } 42 | 43 | } 44 | 45 | public static class ResourceHelper 46 | { 47 | public static string GetValue(string key) => 48 | key switch 49 | { 50 | "Success" => Resources.SharedTranslate.Success, 51 | "Failed" => Resources.SharedTranslate.Failed, 52 | "Unknown" => Resources.SharedTranslate.Unknown, 53 | "NotFound" => Resources.SharedTranslate.NotFound, 54 | "AlreadyExists" => Resources.SharedTranslate.AlreadyExists, 55 | "AuthorizationFailed" => Resources.SharedTranslate.AuthorizationFailed, 56 | "BadRequest" => Resources.SharedTranslate.BadRequest, 57 | "DbError" => Resources.SharedTranslate.DbError, 58 | "LogicError" => Resources.SharedTranslate.LogicError, 59 | "ParametersAreNotValid" => Resources.SharedTranslate.ParametersAreNotValid, 60 | "TokenIsNotValid" => Resources.SharedTranslate.TokenIsNotValid, 61 | "TokenIsExpired" => Resources.SharedTranslate.TokenIsExpired, 62 | "TokenHasNotClaim" => Resources.SharedTranslate.TokenHasNotClaim, 63 | "TokenIsNotSafeWithSecurityStamp" => Resources.SharedTranslate.TokenIsNotSafeWithSecurityStamp, 64 | _ => "" 65 | }; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/ApiResultStatusCode.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.DomainSeedWork 2 | { 3 | public class ApiResultStatusCode : Enumeration 4 | { 5 | public static ApiResultStatusCode Success => new(0, nameof(Success)); 6 | public static ApiResultStatusCode Unknown => new(1001, nameof(Unknown)); 7 | public static ApiResultStatusCode NotFound => new(1002, nameof(NotFound)); 8 | public static ApiResultStatusCode LogicError => new(1003, nameof(LogicError)); 9 | public static ApiResultStatusCode AlreadyExists => new(1004, nameof(AlreadyExists)); 10 | public static ApiResultStatusCode ParametersAreNotValid => new(1005, nameof(ParametersAreNotValid)); 11 | public static ApiResultStatusCode BadRequest => new(1006, nameof(BadRequest)); 12 | public static ApiResultStatusCode DbError => new(1007, nameof(DbError)); 13 | public static ApiResultStatusCode TokenIsExpired => new(1008, nameof(TokenIsExpired)); 14 | public static ApiResultStatusCode TokenIsNotValid => new(1009, nameof(TokenIsNotValid)); 15 | public static ApiResultStatusCode TokenHasNotClaim => new(1010, nameof(TokenHasNotClaim)); 16 | public static ApiResultStatusCode TokenIsNotSafeWithSecurityStamp => new(1011, nameof(TokenIsNotSafeWithSecurityStamp)); 17 | public static ApiResultStatusCode AnUnexpectedErrorHasOccurred => new(1012, nameof(AnUnexpectedErrorHasOccurred)); 18 | public ApiResultStatusCode(int id, string name) : base(id, name) 19 | { 20 | } 21 | } 22 | 23 | //public class ApiResultErrorCode : Enumeration 24 | //{ 25 | 26 | 27 | // public ApiResultErrorCode(int id, string name) : base(id, name) 28 | // { 29 | // } 30 | //} 31 | } -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/AppException.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using Microsoft.Extensions.Localization; 3 | 4 | namespace ErSoftDev.DomainSeedWork 5 | { 6 | public class AppException : Exception 7 | { 8 | public ApiResultStatusCode ApiResultStatusCode { get; } 9 | public Exception? Exception { get; } 10 | public HttpStatusCode? HttpStatusCode { get; set; } 11 | public IStringLocalizer StringLocalizer { get; set; } 12 | 13 | public AppException(Exception? exception) 14 | { 15 | Exception = exception; 16 | } 17 | 18 | public AppException(Exception? exception, ApiResultStatusCode apiResultStatusCode, string? message = null, HttpStatusCode? httpStatusCode = null) 19 | : base(message ?? String.Empty) 20 | { 21 | ApiResultStatusCode = apiResultStatusCode; 22 | Exception = exception; 23 | HttpStatusCode = httpStatusCode; 24 | } 25 | 26 | public AppException(ApiResultStatusCode apiResultStatusCode, 27 | string? message = null, HttpStatusCode? httpStatusCode = null) 28 | : base(message ?? string.Empty) 29 | { 30 | ApiResultStatusCode = apiResultStatusCode; 31 | HttpStatusCode = httpStatusCode; 32 | } 33 | 34 | public AppException(IStringLocalizer stringLocalizer, ApiResultStatusCode apiResultStatusCode, 35 | string? message = null, HttpStatusCode? httpStatusCode = null) 36 | : base(message ?? string.Empty) 37 | { 38 | ApiResultStatusCode = apiResultStatusCode; 39 | HttpStatusCode = httpStatusCode; 40 | StringLocalizer = stringLocalizer; 41 | } 42 | } 43 | 44 | 45 | public class AppException : AppException 46 | { 47 | public AppException(IStringLocalizer stringLocalizer, ApiResultStatusCode apiResultStatusCode, 48 | string? message = null, 49 | HttpStatusCode? httpStatusCode = null) : base(stringLocalizer, apiResultStatusCode, 50 | message, httpStatusCode) 51 | { 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/BaseEntity.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.DomainSeedWork 5 | { 6 | public interface IHaveNotPluralized 7 | { 8 | 9 | } 10 | public interface IEntity 11 | { 12 | 13 | } 14 | 15 | public interface ISoftDelete 16 | { 17 | public bool IsDeleted { get; set; } 18 | public long? DeleterUserId { get; set; } 19 | public DateTime? DeletedAt { get; set; } 20 | } 21 | 22 | public abstract class BaseEntity : DomainEvent, IEntity 23 | { 24 | public long CreatorUserId { get; set; } 25 | public DateTime CreatedAt { get; set; } 26 | public long? UpdaterUserId { get; set; } 27 | public DateTime? UpdatedAt { get; set; } 28 | } 29 | public abstract class BaseEntity : BaseEntity 30 | { 31 | [Key] 32 | public TKey? Id { get; set; } 33 | } 34 | 35 | public abstract class DomainEvent 36 | { 37 | private List? _domainEvents; 38 | public IReadOnlyCollection? DomainEvents => _domainEvents?.AsReadOnly(); 39 | 40 | public void AddDomainEvent(INotification eventItem) 41 | { 42 | _domainEvents = _domainEvents ?? new List(); 43 | _domainEvents.Add(eventItem); 44 | } 45 | 46 | public void RemoveDomainEvent(INotification eventItem) 47 | { 48 | _domainEvents?.Remove(eventItem); 49 | } 50 | 51 | public void ClearDomainEvents() 52 | { 53 | _domainEvents?.Clear(); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/BusinessException.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.DomainSeedWork 2 | { 3 | public class BusinessException : Exception 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/Enumeration.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | 3 | namespace ErSoftDev.DomainSeedWork 4 | { 5 | public class Enumeration : IComparable 6 | { 7 | public string Name { get; private set; } 8 | 9 | public int Code { get; private set; } 10 | 11 | protected Enumeration(int code, string name) => (Code, Name) = (code, name); 12 | 13 | public override string ToString() => Name; 14 | 15 | public static IEnumerable GetAll() where T : Enumeration => 16 | typeof(T).GetFields(BindingFlags.Public | 17 | BindingFlags.Static | 18 | BindingFlags.DeclaredOnly) 19 | .Select(f => f.GetValue(null)) 20 | .Cast(); 21 | 22 | public override bool Equals(object obj) 23 | { 24 | if (obj is not Enumeration otherValue) 25 | { 26 | return false; 27 | } 28 | 29 | var typeMatches = GetType().Equals(obj.GetType()); 30 | var valueMatches = Code.Equals(otherValue.Code); 31 | 32 | return typeMatches && valueMatches; 33 | } 34 | 35 | public override int GetHashCode() => Code.GetHashCode(); 36 | 37 | public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue) 38 | { 39 | var absoluteDifference = Math.Abs(firstValue.Code - secondValue.Code); 40 | return absoluteDifference; 41 | } 42 | 43 | public static T FromValue(int value) where T : Enumeration 44 | { 45 | var matchingItem = Parse(value, "value", item => item.Code == value); 46 | return matchingItem; 47 | } 48 | 49 | public static T FromDisplayName(string displayName) where T : Enumeration 50 | { 51 | var matchingItem = Parse(displayName, "display name", item => item.Name == displayName); 52 | return matchingItem; 53 | } 54 | 55 | private static T Parse(K value, string description, Func predicate) where T : Enumeration 56 | { 57 | var matchingItem = GetAll().FirstOrDefault(predicate); 58 | 59 | if (matchingItem == null) 60 | throw new InvalidOperationException($"'{value}' is not a valid {description} in {typeof(T)}"); 61 | 62 | return matchingItem; 63 | } 64 | 65 | public int CompareTo(object other) => Code.CompareTo(((Enumeration)other).Code); 66 | } 67 | } -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/ErSoftDev.DomainSeedWork.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | ErSoftDev.DomainSeedWork 8 | Domain seed work 9 | 1.0.2 10 | Ehsaan rezaee 11 | ErSoftDev 12 | DomainSeedWork 13 | Library that meet all the needs of the rich domain 14 | https://github.com/ehsanrezaee/DotNetBackend 15 | DDD, Domain Driven Design , Rich Domain ,POCO 16 | 17 | MIT 18 | True 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | SharedTranslate.resx 31 | True 32 | True 33 | 34 | 35 | 36 | 37 | 38 | PublicResXFileCodeGenerator 39 | 40 | 41 | SharedTranslate.Designer.cs 42 | ResXFileCodeGenerator 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/IAggregateRoot.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.DomainSeedWork 2 | { 3 | // Markup interface 4 | public interface IAggregateRoot 5 | { 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/IRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using static System.Formats.Asn1.AsnWriter; 3 | 4 | namespace ErSoftDev.DomainSeedWork 5 | { 6 | public interface IRepository where T : IAggregateRoot 7 | { 8 | public IUnitOfWork UnitOfWork { get; } 9 | 10 | Task Add(T tObject, CancellationToken cancellationToken); 11 | 12 | Task Get(Expression> predicate, CancellationToken cancellationToken); 13 | 14 | Task?> GetList(Expression> predicate, CancellationToken cancellationToken); 15 | 16 | void Delete(T tObject); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/IUnitOfWork.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.DomainSeedWork 2 | { 3 | public interface IUnitOfWork : IDisposable 4 | { 5 | Task SaveChangesAsync(CancellationToken cancellationToken = default(CancellationToken)); 6 | public Task SaveEntitiesAsync(CancellationToken cancellationToken = default(CancellationToken)); 7 | } 8 | 9 | } -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/SharedTranslate.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.DomainSeedWork 2 | { 3 | public class SharedTranslate 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/ErSoftDev.DomainSeedWork/ValueObject.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.DomainSeedWork 2 | { 3 | public abstract class ValueObject 4 | { 5 | protected static bool EqualOperator(ValueObject left, ValueObject right) 6 | { 7 | if (ReferenceEquals(left, null) ^ ReferenceEquals(right, null)) 8 | { 9 | return false; 10 | } 11 | 12 | return ReferenceEquals(left, null) || left.Equals(right); 13 | } 14 | 15 | protected static bool NotEqualOperator(ValueObject left, ValueObject right) 16 | { 17 | return !(EqualOperator(left, right)); 18 | } 19 | 20 | protected abstract IEnumerable GetEqualityComponents(); 21 | 22 | public override bool Equals(object obj) 23 | { 24 | if (obj == null || obj.GetType() != GetType()) 25 | { 26 | return false; 27 | } 28 | 29 | var other = (ValueObject)obj; 30 | 31 | return this.GetEqualityComponents().SequenceEqual(other.GetEqualityComponents()); 32 | } 33 | 34 | public override int GetHashCode() 35 | { 36 | return GetEqualityComponents() 37 | .Select(x => x != null ? x.GetHashCode() : 0) 38 | .Aggregate((x, y) => x ^ y); 39 | } 40 | 41 | public ValueObject GetCopy() 42 | { 43 | return this.MemberwiseClone() as ValueObject; 44 | } 45 | } 46 | 47 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Api/BaseController.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.Filters; 2 | using MediatR; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace ErSoftDev.Framework.Api 6 | { 7 | [Route("api/v{version:apiVersion}/[controller]")] 8 | [ApiController] 9 | [ApiResultFilter] 10 | [Consumes("application/json")] 11 | [Produces("application/json")] 12 | public class BaseController : ControllerBase 13 | { 14 | private readonly IMediator _mediator; 15 | public BaseController(IMediator mediator) 16 | { 17 | _mediator = mediator; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/BaseApp/HighSecurity.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Framework.BaseApp 2 | { 3 | public static class HighSecurity 4 | { 5 | /// 6 | /// Secret key for jwt token , more than 16 character 7 | /// 8 | public static string JwtSecretKey = "8'Sg3Mnv[zJa8}R[p*'_r?P7qkldsfjk((87dfwewencdkjekll"; 9 | /// 10 | /// Encrypt key for encrypt generated token by jwt , exactly 16 character 11 | /// 12 | public static string JwtEncryptKey = "o+:EUi2ZF,oqjs,*"; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Behaviors/LoggingBehavior.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | using ErSoftDev.Common.Utilities; 3 | using ErSoftDev.Framework.Log; 4 | 5 | namespace ErSoftDev.Framework.Behaviors 6 | { 7 | public class 8 | LoggingBehavior : IPipelineBehavior //where TRequest : IRequest 10 | { 11 | private readonly ILogger> _logger; 12 | public LoggingBehavior(ILogger> logger) 13 | { 14 | _logger = logger; 15 | } 16 | 17 | public async Task Handle(TRequest request, RequestHandlerDelegate next, 18 | CancellationToken cancellationToken) 19 | { 20 | _logger.LogInformation("Handling command requests CommandName : {0} , Request : {1}", 21 | request.GetGenericTypeName(), request); 22 | 23 | var response = await next(); 24 | 25 | _logger.LogInformation("Command handled - commandName : {0} , Request : {1} , Response : {2}", 26 | request.GetGenericTypeName(), 27 | request, response); 28 | 29 | return response; 30 | } 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/AutofacConfigurationExtension.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using ErSoftDev.Common.Utilities; 3 | using ErSoftDev.Framework.Behaviors; 4 | using ErSoftDev.Framework.Log; 5 | using MediatR; 6 | 7 | namespace ErSoftDev.Framework.Configuration 8 | { 9 | public class AutofacConfigurationExtension : Module 10 | { 11 | protected override void Load(ContainerBuilder containerBuilder) 12 | { 13 | containerBuilder.RegisterGeneric(typeof(LoggingBehavior<,>)).As(typeof(IPipelineBehavior<,>)); 14 | containerBuilder.RegisterGeneric(typeof(Logger<>)).As(typeof(ILogger<>)).InstancePerLifetimeScope(); 15 | 16 | var endPointApplicationAssemblies = Tools.GetAllAssemblies().ToArray(); 17 | 18 | containerBuilder.RegisterAssemblyTypes(endPointApplicationAssemblies) 19 | .AssignableTo() 20 | .AsImplementedInterfaces() 21 | .InstancePerLifetimeScope(); 22 | 23 | containerBuilder.RegisterAssemblyTypes(endPointApplicationAssemblies) 24 | .AssignableTo() 25 | .AsImplementedInterfaces() 26 | .InstancePerDependency(); 27 | 28 | containerBuilder.RegisterAssemblyTypes(endPointApplicationAssemblies) 29 | .AssignableTo() 30 | .AsImplementedInterfaces() 31 | .SingleInstance(); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/CustomLongToStringConverter.cs: -------------------------------------------------------------------------------- 1 | using System.Buffers; 2 | using System.Buffers.Text; 3 | using System.Globalization; 4 | using System.Text.Json; 5 | 6 | namespace ErSoftDev.Framework.Configuration 7 | { 8 | public class CustomLongToStringConverter : System.Text.Json.Serialization.JsonConverter 9 | { 10 | public CustomLongToStringConverter() 11 | { 12 | 13 | } 14 | public override long Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) 15 | { 16 | if (reader.TokenType == JsonTokenType.String) 17 | { 18 | ReadOnlySpan span = reader.HasValueSequence 19 | ? reader.ValueSequence.ToArray() 20 | : reader.ValueSpan; 21 | if (Utf8Parser.TryParse(span, out long number, out int bytesConsumed) 22 | && span.Length == bytesConsumed) 23 | { 24 | return number; 25 | } 26 | 27 | if (long.TryParse(reader.GetString(), out number)) 28 | { 29 | return number; 30 | } 31 | } 32 | 33 | return reader.GetInt64(); 34 | } 35 | 36 | public override void Write(Utf8JsonWriter writer, long value, JsonSerializerOptions options) 37 | { 38 | writer.WriteStringValue(Convert.ToString(value, CultureInfo.InvariantCulture)); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/EndpointRouteBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using ErSoftDev.Common.Utilities; 3 | using ErSoftDev.Framework.Grpc; 4 | using Microsoft.AspNetCore.Builder; 5 | using Microsoft.AspNetCore.Routing; 6 | 7 | namespace ErSoftDev.Framework.Configuration 8 | { 9 | public static class EndpointRouteBuilderExtensions 10 | { 11 | public static void UseGrpcEndPoint(this IEndpointRouteBuilder routeBuilder) 12 | { 13 | var assemblies = Tools.GetAllAssemblies(); 14 | var grpcServices = 15 | assemblies 16 | .SelectMany(a => a.DefinedTypes) 17 | .Where(t => typeof(IGrpcService).IsAssignableFrom(t) && !t.IsInterface && t.IsClass && t.IsPublic); 18 | 19 | foreach (var service in grpcServices) 20 | { 21 | typeof(GrpcEndpointRouteBuilderExtensions).GetMethod("MapGrpcService", BindingFlags.Static | BindingFlags.Public)? 22 | .MakeGenericMethod(service) 23 | .Invoke(null, new object[] { routeBuilder }); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/Google/ProtoBuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package google.protobuf; 4 | 5 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 6 | option cc_enable_arenas = true; 7 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 8 | option java_package = "com.google.protobuf"; 9 | option java_outer_classname = "WrappersProto"; 10 | option java_multiple_files = true; 11 | option objc_class_prefix = "GPB"; 12 | 13 | // Wrapper message for `double`. 14 | // 15 | // The JSON representation for `DoubleValue` is JSON number. 16 | message DoubleValue { 17 | // The double value. 18 | double value = 1; 19 | } 20 | 21 | // Wrapper message for `float`. 22 | // 23 | // The JSON representation for `FloatValue` is JSON number. 24 | message FloatValue { 25 | // The float value. 26 | float value = 1; 27 | } 28 | 29 | // Wrapper message for `int64`. 30 | // 31 | // The JSON representation for `Int64Value` is JSON string. 32 | message Int64Value { 33 | // The int64 value. 34 | int64 value = 1; 35 | } 36 | 37 | // Wrapper message for `uint64`. 38 | // 39 | // The JSON representation for `UInt64Value` is JSON string. 40 | message UInt64Value { 41 | // The uint64 value. 42 | uint64 value = 1; 43 | } 44 | 45 | // Wrapper message for `int32`. 46 | // 47 | // The JSON representation for `Int32Value` is JSON number. 48 | message Int32Value { 49 | // The int32 value. 50 | int32 value = 1; 51 | } 52 | 53 | // Wrapper message for `uint32`. 54 | // 55 | // The JSON representation for `UInt32Value` is JSON number. 56 | message UInt32Value { 57 | // The uint32 value. 58 | uint32 value = 1; 59 | } 60 | 61 | // Wrapper message for `bool`. 62 | // 63 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 64 | message BoolValue { 65 | // The bool value. 66 | bool value = 1; 67 | } 68 | 69 | // Wrapper message for `string`. 70 | // 71 | // The JSON representation for `StringValue` is JSON string. 72 | message StringValue { 73 | // The string value. 74 | string value = 1; 75 | } 76 | 77 | // Wrapper message for `bytes`. 78 | // 79 | // The JSON representation for `BytesValue` is JSON string. 80 | message BytesValue { 81 | // The bytes value. 82 | bytes value = 1; 83 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/HangfireConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using Hangfire; 2 | using Newtonsoft.Json; 3 | 4 | namespace ErSoftDev.Framework.Configuration 5 | { 6 | public static class HangfireConfigurationExtensions 7 | { 8 | public static void UseMediatR(this IGlobalConfiguration configuration) 9 | { 10 | var jsonSettings = new JsonSerializerSettings 11 | { 12 | TypeNameHandling = TypeNameHandling.All 13 | }; 14 | configuration.UseSerializerSettings(jsonSettings); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/HealthCheckBuilderExtension.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Diagnostics.HealthChecks; 4 | 5 | namespace ErSoftDev.Framework.Configuration 6 | { 7 | public static class HealthCheckBuilderExtension 8 | { 9 | public static void AddCustomCheck(this IHealthChecksBuilder healthChecksBuilder) 10 | { 11 | var assemblies = Tools.GetAllAssemblies(); 12 | var healthCheckClasses = 13 | assemblies 14 | .SelectMany(a => a.DefinedTypes) 15 | .Where(t => typeof(IHealthCheck).IsAssignableFrom(t) && !t.IsInterface && t.IsClass && t.IsPublic); 16 | 17 | foreach (var healthCheckClass in healthCheckClasses) 18 | { 19 | typeof(HealthChecksBuilderAddCheckExtensions).GetMethods().FirstOrDefault( 20 | x => x.Name.Equals("AddCheck", StringComparison.OrdinalIgnoreCase) && 21 | x.IsGenericMethod) 22 | ?.MakeGenericMethod(healthCheckClass) 23 | .Invoke(null, new object[] { healthChecksBuilder, healthCheckClass.Name, null, null }); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/IRegisterType.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Framework.Configuration 2 | { 3 | public interface IScopedDependency 4 | { 5 | 6 | } 7 | public interface ITransientDependency 8 | { 9 | 10 | } 11 | 12 | public interface ISingletonDependency 13 | { 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Configuration/MediatrExtension.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | using ErSoftDev.DomainSeedWork; 3 | using Microsoft.EntityFrameworkCore; 4 | 5 | namespace ErSoftDev.Framework.Configuration 6 | { 7 | public static class MediatorExtension 8 | { 9 | public static async Task DispatchDomainEventsAsync(this IMediator mediator, DbContext dbContext) 10 | { 11 | var domainEntities = dbContext.ChangeTracker 12 | .Entries() 13 | .Where(x => x.Entity.DomainEvents != null && x.Entity.DomainEvents.Any()); 14 | 15 | var domainEvents = domainEntities 16 | .SelectMany(x => x.Entity.DomainEvents) 17 | .ToList(); 18 | 19 | domainEntities.ToList() 20 | .ForEach(entity => entity.Entity.ClearDomainEvents()); 21 | 22 | foreach (var domainEvent in domainEvents) 23 | await mediator.Publish(domainEvent); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Grpc/IGrpcService.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Framework.Grpc 2 | { 3 | public interface IGrpcService 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Jwt/IJwtService.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Framework.Jwt 2 | { 3 | public interface IJwtService 4 | { 5 | Task Generate(TokenRequest tokenRequest); 6 | } 7 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Jwt/JsonWebToken.cs: -------------------------------------------------------------------------------- 1 | using System.Security.Claims; 2 | 3 | namespace ErSoftDev.Framework.Jwt 4 | { 5 | public class TokenRequest 6 | { 7 | public string Audience { get; set; } 8 | public List Subject { get; set; } 9 | 10 | } 11 | public class TokenResponse 12 | { 13 | public string Token { get; set; } 14 | public DateTime TokenExpiry { get; set; } 15 | } 16 | 17 | } 18 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Jwt/JwtService.cs: -------------------------------------------------------------------------------- 1 | using System.IdentityModel.Tokens.Jwt; 2 | using System.Security.Claims; 3 | using System.Text; 4 | using ErSoftDev.DomainSeedWork; 5 | using ErSoftDev.Framework.BaseApp; 6 | using ErSoftDev.Framework.Configuration; 7 | using Microsoft.Extensions.Localization; 8 | using Microsoft.Extensions.Options; 9 | using Microsoft.IdentityModel.Tokens; 10 | 11 | namespace ErSoftDev.Framework.Jwt 12 | { 13 | public class JwtService : IJwtService, IScopedDependency 14 | { 15 | private readonly IOptions _optionsAppSetting; 16 | private readonly IStringLocalizer _stringLocalizer; 17 | 18 | public JwtService(IOptions optionsAppSetting, IStringLocalizer stringLocalizer) 19 | { 20 | _optionsAppSetting = optionsAppSetting; 21 | _stringLocalizer = stringLocalizer; 22 | } 23 | 24 | public async Task Generate(TokenRequest tokenRequest) 25 | { 26 | var secretKey = Encoding.UTF8.GetBytes(HighSecurity.JwtSecretKey); 27 | var encryptKey = Encoding.UTF8.GetBytes(HighSecurity.JwtEncryptKey); 28 | 29 | var signingCredentials = new SigningCredentials(new SymmetricSecurityKey(secretKey), 30 | SecurityAlgorithms.HmacSha256Signature); 31 | var encryptingCredentials = new EncryptingCredentials(new SymmetricSecurityKey(encryptKey), 32 | SecurityAlgorithms.Aes128KW, SecurityAlgorithms.Aes128CbcHmacSha256); 33 | 34 | var tokenExpiry = DateTime.Now.AddSeconds(_optionsAppSetting.Value.Jwt.TokenExpirySecond); 35 | 36 | var descriptor = new SecurityTokenDescriptor() 37 | { 38 | Issuer = _optionsAppSetting.Value.Jwt.Issuer, 39 | Audience = _optionsAppSetting.Value.Jwt.Audience, 40 | IssuedAt = DateTime.Now, 41 | NotBefore = DateTime.Now, 42 | Expires = tokenExpiry, 43 | SigningCredentials = signingCredentials,// Header and Payload coding 44 | //EncryptingCredentials = encryptingCredentials,//Header and Payload coding 45 | Subject = getClaims(tokenRequest.Subject) 46 | }; 47 | 48 | var tokenHandler = new JwtSecurityTokenHandler(); 49 | var securityToken = tokenHandler.CreateToken(descriptor); 50 | var generatedToken = tokenHandler.WriteToken(securityToken); 51 | 52 | return new TokenResponse() 53 | { 54 | Token = generatedToken, 55 | TokenExpiry = tokenExpiry 56 | }; 57 | } 58 | 59 | private ClaimsIdentity getClaims(IEnumerable subject) 60 | { 61 | var claimList = subject.ToList(); 62 | return new ClaimsIdentity(claimList); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Log/ILogger.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Framework.Log 2 | { 3 | public interface ILogger 4 | { 5 | void LogTrace(string message); 6 | void LogTrace(string message, Dictionary tags); 7 | void LogTrace(string message, T obj); 8 | void LogTrace(string message, params object[] args); 9 | void LogTrace(string message, T obj, Dictionary tags); 10 | void LogDebug(string message, T obj); 11 | void LogDebug(string message, params object[] args); 12 | void LogDebug(string message, T obj, Dictionary tags); 13 | void LogDebug(string message); 14 | void LogDebug(string message, Dictionary tags); 15 | void LogInformation(string message, T obj); 16 | void LogInformation(string message, T obj, Dictionary tags); 17 | void LogInformation(string message); 18 | void LogInformation(string message, params object[] args); 19 | void LogInformation(string message, Dictionary tags); 20 | void LogWarning(string message, T obj); 21 | void LogWarning(string message, T obj, Dictionary tags); 22 | void LogWarning(string message); 23 | void LogWarning(string message, params object[] args); 24 | void LogWarning(string message, Dictionary tags); 25 | void LogError(string message, T obj); 26 | void LogError(string message, params object[] args); 27 | void LogError(string message, T obj, Dictionary tags); 28 | void LogError(string message); 29 | void LogError(string message, Dictionary tags); 30 | void LogFatal(string message, T obj); 31 | void LogFatal(string message, params object[] args); 32 | void LogFatal(string message, T obj, Dictionary tags); 33 | void LogFatal(string message); 34 | void LogFatal(string message, Dictionary tags); 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Middlewares/CustomExceptionHandlerMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Framework.BaseApp; 4 | using ErSoftDev.Framework.Log; 5 | using Microsoft.AspNetCore.Http; 6 | using Microsoft.Extensions.Localization; 7 | using Microsoft.Extensions.Options; 8 | using Newtonsoft.Json; 9 | using Newtonsoft.Json.Serialization; 10 | 11 | 12 | namespace ErSoftDev.Framework.Middlewares 13 | { 14 | public class CustomExceptionHandlerMiddleware 15 | { 16 | private readonly RequestDelegate _next; 17 | 18 | private readonly ILogger _logger; 19 | private readonly IStringLocalizer _stringLocalizer; 20 | private readonly IOptions _appSetting; 21 | 22 | public CustomExceptionHandlerMiddleware(RequestDelegate next, ILogger logger, 23 | IStringLocalizer stringLocalizer, 24 | IOptions appSetting) 25 | { 26 | _next = next; 27 | _logger = logger; 28 | _stringLocalizer = stringLocalizer; 29 | _appSetting = appSetting; 30 | } 31 | 32 | 33 | public async Task InvokeAsync(HttpContext httpContext) 34 | { 35 | try 36 | { 37 | await _next(httpContext); 38 | } 39 | catch (AppException ex) 40 | { 41 | _logger.LogFatal("ExceptionHandler", new { Exception = ex }); 42 | 43 | httpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; 44 | if (ex.HttpStatusCode is not null) 45 | httpContext.Response.StatusCode = (int)ex.HttpStatusCode; 46 | 47 | httpContext.Response.ContentType = "Application/json"; 48 | await httpContext.Response.WriteAsync(JsonConvert.SerializeObject( 49 | new ApiResult(ex.StringLocalizer, ex.ApiResultStatusCode), 50 | new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() })); 51 | } 52 | catch (Exception ex) 53 | { 54 | _logger.LogFatal("ExceptionHandler", new { Exception = ex }); 55 | 56 | httpContext.Response.StatusCode = (int)HttpStatusCode.InternalServerError; 57 | httpContext.Response.ContentType = "Application/json"; 58 | await httpContext.Response.WriteAsync(JsonConvert.SerializeObject( 59 | new ApiResult(_stringLocalizer, ApiResultStatusCode.AnUnexpectedErrorHasOccurred, 60 | _appSetting.Value.ShowExceptionMessage ? " - " + ex.Message + " - " + ex.StackTrace : null), 61 | new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() })); 62 | } 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Middlewares/CustomJwtTokenValidationMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authorization; 2 | using Microsoft.AspNetCore.Http; 3 | using System.IdentityModel.Tokens.Jwt; 4 | using System.Net; 5 | using ErSoftDev.DomainSeedWork; 6 | using Microsoft.Extensions.Localization; 7 | using Newtonsoft.Json.Serialization; 8 | using Newtonsoft.Json; 9 | using Microsoft.AspNetCore.Authentication.JwtBearer; 10 | 11 | namespace ErSoftDev.Framework.Middlewares 12 | { 13 | public class CustomJwtTokenValidationMiddleware 14 | { 15 | private readonly RequestDelegate _next; 16 | private readonly IStringLocalizer _stringLocalizer; 17 | 18 | public CustomJwtTokenValidationMiddleware(RequestDelegate next, IStringLocalizer stringLocalizer) 19 | { 20 | _next = next; 21 | _stringLocalizer = stringLocalizer; 22 | } 23 | 24 | public async Task InvokeAsync(HttpContext httpContext) 25 | { 26 | var executingEndpoint = httpContext.GetEndpoint(); 27 | if (executingEndpoint != null) 28 | { 29 | var attributes = executingEndpoint!.Metadata.OfType().ToList(); 30 | if (!attributes.Any()) 31 | { 32 | var token = httpContext.Request.Headers["Authorization"].ToString(); 33 | if (string.IsNullOrWhiteSpace(token) || !token.Contains(JwtBearerDefaults.AuthenticationScheme + " ")) 34 | { 35 | httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized; 36 | httpContext.Response.ContentType = "Application/json"; 37 | await httpContext.Response.WriteAsync(JsonConvert.SerializeObject( 38 | new ApiResult(_stringLocalizer, ApiResultStatusCode.TokenIsNotValid, null), 39 | new JsonSerializerSettings { ContractResolver = new CamelCasePropertyNamesContractResolver() })); 40 | 41 | return; 42 | } 43 | } 44 | } 45 | await _next(httpContext); 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Middlewares/CustomSwaggerUiMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Swashbuckle.AspNetCore.SwaggerUI; 3 | 4 | 5 | namespace ErSoftDev.Framework.Middlewares 6 | { 7 | public static class CustomSwaggerUiMiddleware 8 | { 9 | public static void UseCustomSwaggerUi(this IApplicationBuilder applicationBuilder, BaseApp.Swagger? swagger) 10 | { 11 | if (swagger == null) 12 | return; 13 | 14 | applicationBuilder.UseSwagger(); 15 | 16 | var versionCount = swagger.VersionCount; 17 | decimal versionStart = (decimal)0.9; 18 | const decimal versionStep = (decimal)0.1; 19 | 20 | 21 | applicationBuilder.UseSwaggerUI(options => 22 | { 23 | for (var i = 0; i < versionCount; i++) 24 | { 25 | options.SwaggerEndpoint($"/swagger/v{(versionStart + versionStep)}/swagger.json", 26 | $"version{versionStart + versionStep} - doc"); 27 | versionStart += versionStep; 28 | } 29 | 30 | options.DocExpansion(DocExpansion.None); 31 | }); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Middlewares/RateLimitationMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using ErSoftDev.Framework.Redis; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace ErSoftDev.Framework.Middlewares 6 | { 7 | public class RateLimitationMiddleware 8 | { 9 | private readonly RequestDelegate _next; 10 | private readonly IRedisService _redisService; 11 | 12 | public RateLimitationMiddleware(RequestDelegate next, IRedisService redisService) 13 | { 14 | _next = next; 15 | _redisService = redisService; 16 | } 17 | public async Task InvokeAsync(HttpContext context) 18 | { 19 | var endpoint = context.GetEndpoint(); 20 | var decorator = endpoint?.Metadata.GetMetadata(); 21 | 22 | //var decorator = context.Features.Get().Endpoint.Metadata.GetMetadata(); 23 | 24 | if (decorator is null) 25 | { 26 | await _next(context); 27 | return; 28 | } 29 | var key = GenerateClientKey(context); 30 | var clientStatistics = await GetClientStatisticsByKey(key); 31 | if (clientStatistics != null && 32 | DateTime.UtcNow < clientStatistics.LastSuccessfulResponseTime.AddSeconds(decorator.TimeWindow) && 33 | clientStatistics.NumberOfRequestsCompletedSuccessfully == decorator.MaxRequests) 34 | { 35 | context.Response.StatusCode = (int)HttpStatusCode.TooManyRequests; 36 | return; 37 | } 38 | await _redisService.AddOrUpdateAsync(key, decorator, TimeSpan.FromMinutes(10)); 39 | await _next(context); 40 | } 41 | 42 | private static string GenerateClientKey(HttpContext context) 43 | => $"{context.Request.Path}_{context.Connection.RemoteIpAddress}"; 44 | 45 | private async Task GetClientStatisticsByKey(string key) 46 | { 47 | return await _redisService.GetAsync(key); 48 | } 49 | } 50 | public class ClientStatistics 51 | { 52 | public DateTime LastSuccessfulResponseTime { get; set; } 53 | public int NumberOfRequestsCompletedSuccessfully { get; set; } 54 | } 55 | 56 | [AttributeUsage(AttributeTargets.Method)] 57 | public class LimitRequests : Attribute 58 | { 59 | public int TimeWindow { get; set; } 60 | public int MaxRequests { get; set; } 61 | } 62 | 63 | 64 | } 65 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Mongo/BaseMongoDbContext.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.BaseApp; 2 | using MongoDB.Driver; 3 | 4 | namespace ErSoftDev.Framework.Mongo; 5 | 6 | public class BaseMongoDbContext 7 | { 8 | private readonly IMongoDatabase _database; 9 | 10 | public BaseMongoDbContext(AppSetting appSetting) 11 | { 12 | var client = new MongoClient(appSetting.ConnectionString.MongoConnectionString); 13 | var databaseName = MongoUrl.Create(appSetting.ConnectionString.MongoConnectionString).DatabaseName; 14 | _database = client.GetDatabase(databaseName); 15 | } 16 | 17 | public IMongoCollection GetCollection() 18 | { 19 | return _database.GetCollection(typeof(T).Name); 20 | } 21 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Mongo/IMongoRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | 3 | namespace ErSoftDev.Framework.Mongo; 4 | 5 | public interface IMongoRepository 6 | { 7 | public Task> GetAll(CancellationToken cancellationToken); 8 | public Task GetById(string id, CancellationToken cancellationToken); 9 | public Task Get(Expression> predicate, CancellationToken cancellationToken); 10 | public Task Create(T entity); 11 | public Task Update(T entity); 12 | public Task AddOrUpdate(T entity, CancellationToken cancellationToken); 13 | public Task Delete(string id); 14 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Mongo/MongoRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using ErSoftDev.DomainSeedWork; 3 | using MongoDB.Driver; 4 | 5 | namespace ErSoftDev.Framework.Mongo 6 | { 7 | public class MongoRepository : IMongoRepository where T : BaseEntity 8 | 9 | { 10 | private readonly IMongoCollection _collection; 11 | 12 | public MongoRepository(BaseMongoDbContext context) 13 | { 14 | _collection = context.GetCollection(); 15 | } 16 | 17 | public Task> GetCollection() 18 | { 19 | return Task.FromResult(_collection); 20 | } 21 | 22 | public async Task> GetAll(CancellationToken cancellationToken) 23 | { 24 | return await _collection.Find(_ => true).ToListAsync(cancellationToken); 25 | } 26 | 27 | public async Task GetById(string id, CancellationToken cancellationToken) 28 | { 29 | return await _collection.Find(Builders.Filter.Eq("Id", id)).FirstOrDefaultAsync(cancellationToken); 30 | } 31 | 32 | public async Task Get(Expression> predicate, CancellationToken cancellationToken) 33 | { 34 | return await _collection.Find(predicate).FirstOrDefaultAsync(cancellationToken); 35 | } 36 | 37 | public async Task Create(T entity) 38 | { 39 | await _collection.InsertOneAsync(entity); 40 | } 41 | 42 | public async Task Update(T entity) 43 | { 44 | var result = await _collection.ReplaceOneAsync(Builders.Filter.Eq("Id", entity.Id), entity); 45 | return result.ModifiedCount > 0; 46 | } 47 | 48 | public async Task AddOrUpdate(T entity, CancellationToken cancellationToken) 49 | { 50 | var entityInfo = await _collection.Find(Builders.Filter.Eq("Id", entity.Id)).FirstOrDefaultAsync(cancellationToken); 51 | if (entityInfo != null) 52 | await Update(entity); 53 | else 54 | await Create(entity); 55 | } 56 | 57 | public async Task Delete(string id) 58 | { 59 | var result = await _collection.DeleteOneAsync(Builders.Filter.Eq("Id", id)); 60 | return result.DeletedCount > 0; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/RabbitMq/Connection.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.BaseApp; 2 | using EventBus.RabbitMQ.Standard; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using RabbitMQ.Client; 5 | 6 | namespace ErSoftDev.Framework.RabbitMq 7 | { 8 | public static class Connection 9 | { 10 | public static IServiceCollection? AddRabbitMqConnection(this IServiceCollection services, AppSetting appSetting) 11 | { 12 | if (appSetting.EventBusRabbitMq is null) 13 | return null; 14 | 15 | services.AddSingleton(_ => 16 | { 17 | var factory = new ConnectionFactory 18 | { 19 | HostName = appSetting.EventBusRabbitMq.HostName, 20 | DispatchConsumersAsync = appSetting.EventBusRabbitMq.DispatchConsumerAsync, 21 | VirtualHost = appSetting.EventBusRabbitMq.VirtualHost, 22 | UserName = appSetting.EventBusRabbitMq.Username, 23 | Password = appSetting.EventBusRabbitMq.Password, 24 | Port = appSetting.EventBusRabbitMq.VirtualPort 25 | }; 26 | 27 | var retryCount = appSetting.EventBusRabbitMq.TryCount; 28 | 29 | return new DefaultRabbitMqPersistentConnection(factory, retryCount); 30 | }); 31 | 32 | return services; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/RabbitMq/IIntegrationEventBus.cs: -------------------------------------------------------------------------------- 1 | using EventBus.Base.Standard; 2 | 3 | namespace ErSoftDev.Framework.RabbitMq 4 | { 5 | public interface IIntegrationEventBus 6 | { 7 | Task PublishAsync(TEvent contentObject, CancellationToken cancellationToken) where TEvent : IntegrationEvent; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/RabbitMq/IntegrationEventBus.cs: -------------------------------------------------------------------------------- 1 | using DotNetCore.CAP; 2 | using ErSoftDev.Common.Utilities; 3 | using ErSoftDev.Framework.Configuration; 4 | using EventBus.Base.Standard; 5 | 6 | namespace ErSoftDev.Framework.RabbitMq 7 | { 8 | public class IntegrationEventBus : IIntegrationEventBus, ITransientDependency 9 | { 10 | private readonly ICapPublisher _capPublisher; 11 | public IntegrationEventBus(ICapPublisher capPublisher) 12 | { 13 | _capPublisher = capPublisher; 14 | } 15 | 16 | public async Task PublishAsync(TEvent contentObject, CancellationToken cancellationToken) where TEvent : IntegrationEvent 17 | { 18 | var type = contentObject?.GetType(); 19 | if (type?.GetCustomAttributes(typeof(FullNameAttribute), false).FirstOrDefault() is FullNameAttribute 20 | fullNameAttribute) 21 | await _capPublisher.PublishAsync(fullNameAttribute.Name, contentObject, 22 | cancellationToken: cancellationToken); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/RabbitMq/Registration.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using ErSoftDev.Framework.BaseApp; 3 | using ErSoftDev.Framework.Log; 4 | using EventBus.Base.Standard; 5 | using EventBus.RabbitMQ.Standard; 6 | using Microsoft.Extensions.DependencyInjection; 7 | using Microsoft.Extensions.Options; 8 | 9 | namespace ErSoftDev.Framework.RabbitMq 10 | { 11 | public static class Registration 12 | { 13 | public static IServiceCollection? AddRabbitMqRegistration(this IServiceCollection? services, AppSetting appSetting) 14 | { 15 | if (appSetting.EventBusRabbitMq is null) 16 | return null; 17 | 18 | services.AddSingleton(sp => 19 | { 20 | var rabbitMqPersistentConnection = sp.GetRequiredService(); 21 | var eventBusSubscriptionsManager = sp.GetRequiredService(); 22 | var logger = sp.GetRequiredService>(); 23 | var serviceScopeFactory = sp.GetRequiredService(); 24 | var appSetting = sp.GetRequiredService>(); 25 | var lifeTimeScope = sp.GetRequiredService(); 26 | 27 | var brokerName = appSetting.Value.EventBusRabbitMq.BrokerName; 28 | var queueName = appSetting.Value.EventBusRabbitMq.QueueName; 29 | var retryCount = appSetting.Value.EventBusRabbitMq.TryCount; 30 | var preFetchCount = appSetting.Value.EventBusRabbitMq.PreFetchCount; 31 | 32 | return new EventBusRabbitMqService(appSetting, 33 | rabbitMqPersistentConnection, 34 | eventBusSubscriptionsManager, 35 | lifeTimeScope, 36 | brokerName, 37 | logger, 38 | serviceScopeFactory, 39 | queueName, 40 | retryCount, 41 | preFetchCount 42 | ); 43 | }); 44 | services.AddSingleton(); 45 | return services; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Redis/IRedisService.cs: -------------------------------------------------------------------------------- 1 | using StackExchange.Redis; 2 | 3 | namespace ErSoftDev.Framework.Redis 4 | { 5 | public interface IRedisService 6 | { 7 | /// 8 | /// Set key to hold the string value. If key already holds a value, it is overwritten, regardless of its type. 9 | /// 10 | /// The key of the string. 11 | /// Generic class that convert to json 12 | /// expire timeSpan 13 | /// The flags to use for this operation. 14 | /// True if the string was set, false otherwise. 15 | Task AddOrUpdateAsync(string key, T value, TimeSpan expiry, 16 | CommandFlags flags = CommandFlags.None); 17 | 18 | /// 19 | /// Atomically sets key to value and returns the previous value (if any) stored at 20 | /// 21 | /// The key of the string. 22 | /// /// expire timeSpan 23 | /// Generic class that convert to json 24 | /// The flags to use for this operation. 25 | /// True if the string was set, false otherwise. 26 | Task AddOrUpdateAndGetAsync(string key, T value, TimeSpan expiry, 27 | CommandFlags flags = CommandFlags.None); 28 | 29 | /// 30 | /// Get the T class value of key. If the key does not exist the special value nil is returned. An error is returned if the value stored at key is not a string, because GET only handles string values. 31 | /// 32 | /// The key of the string. 33 | /// The value of key, or nil when key does not exist. 34 | Task GetAsync(string key); 35 | 36 | /// 37 | /// Removes the specified key. A key is ignored if it does not exist. 38 | /// 39 | /// The key to delete. 40 | /// The flags to use for this operation. 41 | /// True if the key was removed. 42 | Task DeleteAsync(string key, CommandFlags flags = CommandFlags.None); 43 | 44 | /// 45 | /// Removes all keys that matched with pattern. 46 | /// 47 | /// The key to delete. pattern is key* 48 | /// The flags to use for this operation. 49 | /// True if the key was removed. 50 | Task DeleteWithLikeAsync(string key, CommandFlags flags = CommandFlags.None); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Swagger/AddHeaderParameter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.OpenApi.Any; 3 | using Microsoft.OpenApi.Models; 4 | using Swashbuckle.AspNetCore.SwaggerGen; 5 | 6 | 7 | namespace ErSoftDev.Framework.Swagger 8 | { 9 | public class AddHeaderParameter : IOperationFilter 10 | { 11 | public void Apply(OpenApiOperation operation, OperationFilterContext context) 12 | { 13 | operation.Parameters.Add(new OpenApiParameter() 14 | { 15 | Name = "Culture", 16 | Description = "This is optional parameter In header", 17 | Required = false, 18 | In = ParameterLocation.Header, 19 | Example = new OpenApiString("fa-IR"), 20 | 21 | }); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Swagger/EnumSchemaFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.OpenApi.Any; 2 | using Microsoft.OpenApi.Models; 3 | using Swashbuckle.AspNetCore.SwaggerGen; 4 | 5 | namespace ErSoftDev.Framework.Swagger 6 | { 7 | public class EnumSchemaFilter : ISchemaFilter 8 | { 9 | public void Apply(OpenApiSchema schema, SchemaFilterContext context) 10 | { 11 | if (context.Type.IsEnum) 12 | { 13 | var enumValues = schema.Enum.ToArray(); 14 | var i = 0; 15 | schema.Enum.Clear(); 16 | foreach (var n in Enum.GetNames(context.Type).ToList()) 17 | { 18 | schema.Enum.Add(new OpenApiString(n + $" = {((OpenApiPrimitive)enumValues[i]).Value}")); 19 | i++; 20 | } 21 | } 22 | } 23 | } 24 | 25 | } 26 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Swagger/RemoveVersionParameter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.OpenApi.Models; 2 | using Swashbuckle.AspNetCore.SwaggerGen; 3 | 4 | namespace ErSoftDev.Framework.Swagger 5 | { 6 | public class RemoveVersionParameter : IOperationFilter 7 | { 8 | public void Apply(OpenApiOperation operation, OperationFilterContext context) 9 | { 10 | // Remove version parameter from all Operations 11 | var versionParameter = operation.Parameters.SingleOrDefault(p => p.Name == "version"); 12 | if (versionParameter != null) 13 | operation.Parameters.Remove(versionParameter); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Swagger/SetVersionInPath.cs: -------------------------------------------------------------------------------- 1 | using Swashbuckle.AspNetCore.SwaggerGen; 2 | using Microsoft.OpenApi.Models; 3 | 4 | namespace ErSoftDev.Framework.Swagger 5 | { 6 | public class SetVersionInPath : IDocumentFilter 7 | { 8 | public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context) 9 | { 10 | var updatedPaths = new OpenApiPaths(); 11 | 12 | 13 | foreach (var entry in swaggerDoc.Paths) 14 | { 15 | updatedPaths.Add( 16 | entry.Key.Replace("v{version}", swaggerDoc.Info.Version), 17 | entry.Value); 18 | } 19 | swaggerDoc.Paths = updatedPaths; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/ErSoftDev.Framework/Swagger/UnauthorizedResponsesOperationFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc.Authorization; 2 | using Microsoft.OpenApi.Models; 3 | using Swashbuckle.AspNetCore.SwaggerGen; 4 | 5 | namespace ErSoftDev.Framework.Swagger 6 | { 7 | public class UnauthorizedResponsesOperationFilter : IOperationFilter 8 | { 9 | private readonly bool _includeUnauthorizedAndForbiddenResponses; 10 | private readonly string _schemeName; 11 | 12 | public UnauthorizedResponsesOperationFilter(bool includeUnauthorizedAndForbiddenResponses, string schemeName = "Bearer") 13 | { 14 | this._includeUnauthorizedAndForbiddenResponses = includeUnauthorizedAndForbiddenResponses; 15 | this._schemeName = schemeName; 16 | } 17 | // Work on all actions that find by swagger 18 | public void Apply(OpenApiOperation operation, OperationFilterContext context) 19 | { 20 | // Get all attribute of action 21 | var filters = context.ApiDescription.ActionDescriptor.FilterDescriptors; 22 | // Action has allow anonymous attribute 23 | var hasAnonymous = filters.Any(p => p.Filter is AllowAnonymousFilter); 24 | if (hasAnonymous) return; 25 | // Don not have authorize attribute , do not do anything 26 | var hasAuthorize = filters.Any(p => p.Filter is AuthorizeFilter); 27 | if (!hasAuthorize) return; 28 | 29 | // Add unAuthorize error for any action than has not access 30 | if (_includeUnauthorizedAndForbiddenResponses) 31 | { 32 | operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" }); 33 | } 34 | 35 | operation.Security = new List() 36 | { 37 | new OpenApiSecurityRequirement() 38 | { 39 | { 40 | new OpenApiSecurityScheme 41 | { 42 | Reference = new OpenApiReference 43 | { 44 | Type = ReferenceType.SecurityScheme, Id = _schemeName 45 | }, 46 | Name = _schemeName, 47 | In = ParameterLocation.Header, 48 | }, new List() 49 | } 50 | } 51 | }; 52 | 53 | 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/Configuration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.BaseApp; 2 | 3 | namespace ErSoftDev.HealthCheck 4 | { 5 | public class Configuration 6 | { 7 | private readonly AppSetting _appSetting; 8 | private readonly string _configKey; 9 | public IConfiguration AppConfiguration { get; } 10 | 11 | public Configuration(IConfiguration appConfiguration, IHostEnvironment environment) 12 | { 13 | AppConfiguration = appConfiguration; 14 | _configKey = $"{nameof(AppSetting)}{environment.EnvironmentName}"; 15 | _appSetting = appConfiguration.GetSection(_configKey).Get()!; 16 | } 17 | 18 | public void ConfigureServices(IServiceCollection services) 19 | { 20 | services.Configure(AppConfiguration.GetSection(_configKey)); 21 | //services.AddSingleton(_appSetting); 22 | services.AddControllers(); 23 | services.AddHealthChecksUI() 24 | .AddInMemoryStorage(); 25 | } 26 | 27 | public void Configure(IApplicationBuilder app, IWebHostEnvironment env, AppSetting appsetting) 28 | { 29 | app.UseHttpsRedirection(); 30 | app.UseRouting(); 31 | app.UseEndpoints(builder => 32 | { 33 | builder.MapGet("/", 34 | async context => { await context.Response.WriteAsync(appsetting.WelcomeNote ?? ""); }); 35 | builder.MapControllers(); 36 | }); 37 | app.UseHealthChecksUI(config => config.UIPath = "/healthCheckUI"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 4 | USER app 5 | WORKDIR /app 6 | EXPOSE 8080 7 | EXPOSE 8081 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 10 | ARG BUILD_CONFIGURATION=Release 11 | WORKDIR /src 12 | COPY ["src/HealthCheck/ErSoftDev.HealthCheck/ErSoftDev.HealthCheck.csproj", "src/HealthCheck/ErSoftDev.HealthCheck/"] 13 | COPY ["src/ErSoftDev.Framework/ErSoftDev.Framework.csproj", "src/ErSoftDev.Framework/"] 14 | COPY ["src/ErSoftDev.Common/ErSoftDev.Common.csproj", "src/ErSoftDev.Common/"] 15 | COPY ["src/ErSoftDev.DomainSeedWork/ErSoftDev.DomainSeedWork.csproj", "src/ErSoftDev.DomainSeedWork/"] 16 | RUN dotnet restore "./src/HealthCheck/ErSoftDev.HealthCheck/ErSoftDev.HealthCheck.csproj" 17 | COPY . . 18 | WORKDIR "/src/src/HealthCheck/ErSoftDev.HealthCheck" 19 | RUN dotnet build "./ErSoftDev.HealthCheck.csproj" -c $BUILD_CONFIGURATION -o /app/build 20 | 21 | FROM build AS publish 22 | ARG BUILD_CONFIGURATION=Release 23 | RUN dotnet publish "./ErSoftDev.HealthCheck.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 24 | 25 | FROM base AS final 26 | WORKDIR /app 27 | COPY --from=publish /app/publish . 28 | ENTRYPOINT ["dotnet", "ErSoftDev.HealthCheck.dll"] -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/Dockerfile.original: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 4 | USER app 5 | WORKDIR /app 6 | EXPOSE 8080 7 | EXPOSE 8081 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 10 | ARG BUILD_CONFIGURATION=Release 11 | WORKDIR /src 12 | COPY ["src/HealthCheck/ErSoftDev.HealthCheck/ErSoftDev.HealthCheck.csproj", "src/HealthCheck/ErSoftDev.HealthCheck/"] 13 | RUN dotnet restore "./src/HealthCheck/ErSoftDev.HealthCheck/./ErSoftDev.HealthCheck.csproj" 14 | COPY . . 15 | WORKDIR "/src/src/HealthCheck/ErSoftDev.HealthCheck" 16 | RUN dotnet build "./ErSoftDev.HealthCheck.csproj" -c $BUILD_CONFIGURATION -o /app/build 17 | 18 | FROM build AS publish 19 | ARG BUILD_CONFIGURATION=Release 20 | RUN dotnet publish "./ErSoftDev.HealthCheck.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 21 | 22 | FROM base AS final 23 | WORKDIR /app 24 | COPY --from=publish /app/publish . 25 | ENTRYPOINT ["dotnet", "ErSoftDev.HealthCheck.dll"] -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/ErSoftDev.HealthCheck.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | true 8 | 3f938a19-c886-4368-9030-4d87aa891911 9 | Linux 10 | ..\..\.. 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/ErSoftDev.HealthCheck.http: -------------------------------------------------------------------------------- 1 | @ErSoftDev.HealthCheck_HostAddress = http://localhost:5186 2 | 3 | GET {{ErSoftDev.HealthCheck_HostAddress}}/weatherforecast/ 4 | Accept: application/json 5 | 6 | ### 7 | -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/Program.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Extensions.DependencyInjection; 3 | using ErSoftDev.Framework.BaseApp; 4 | using ErSoftDev.Framework.Configuration; 5 | 6 | var builder = WebApplication.CreateBuilder(args); 7 | 8 | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer( 9 | (context, containerBuilder) => containerBuilder.RegisterModule(new AutofacConfigurationExtension())); 10 | 11 | var appSettings = builder.Configuration 12 | .GetSection($"{nameof(AppSetting)}{builder.Environment.EnvironmentName}") 13 | .Get(); 14 | 15 | var startup = new ErSoftDev.HealthCheck.Configuration(builder.Configuration, builder.Environment); 16 | startup.ConfigureServices(builder.Services); 17 | 18 | var app = builder.Build(); 19 | 20 | startup.Configure(app, builder.Environment, appSettings); 21 | 22 | await app.RunAsync(); -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "weatherforecast", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "http://localhost:5186" 12 | }, 13 | "https": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "weatherforecast", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "https://localhost:7298;http://localhost:5186" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "weatherforecast", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Development": { 32 | "commandName": "Project", 33 | "launchBrowser": true, 34 | "launchUrl": "healthCheckUI", 35 | "environmentVariables": { 36 | "ASPNETCORE_ENVIRONMENT": "Development" 37 | } 38 | }, 39 | "Docker": { 40 | "commandName": "Docker", 41 | "launchBrowser": true, 42 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/healthCheckUI", 43 | "environmentVariables": { 44 | "ASPNETCORE_ENVIRONMENT": "Docker" 45 | }, 46 | "publishAllPorts": true, 47 | "useSSL": false, 48 | "httpPort": 5023 49 | } 50 | }, 51 | "$schema": "http://json.schemastore.org/launchsettings.json", 52 | "iisSettings": { 53 | "windowsAuthentication": false, 54 | "anonymousAuthentication": true, 55 | "iisExpress": { 56 | "applicationUrl": "http://localhost:34929", 57 | "sslPort": 44347 58 | } 59 | } 60 | } -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSettingDevelopment": { 3 | 4 | }, 5 | "HealthChecksUI": { 6 | "HealthChecks": [ 7 | { 8 | "Name": "Identity", 9 | "Uri": "https://localhost:5002/health" 10 | }, 11 | { 12 | "Name": "ApiGateway", 13 | "Uri": "https://localhost:5003/health" 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/appsettings.Docker.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSettingDocker": { 3 | 4 | }, 5 | "HealthChecksUI": { 6 | "HealthChecks": [ 7 | { 8 | "Name": "Identity", 9 | "Uri": "http://host.docker.internal:5202/health" 10 | }, 11 | { 12 | "Name": "ApiGateway", 13 | "Uri": "http://host.docker.internal:5203/health" 14 | } 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/HealthCheck/ErSoftDev.HealthCheck/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/AddRoleCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class AddRoleCommand : IRequest 7 | { 8 | public string Title { get; set; } 9 | public string Description { get; set; } 10 | public bool Active { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/AddRoleCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 3 | using IdGen; 4 | using MediatR; 5 | using Microsoft.Extensions.Localization; 6 | 7 | namespace ErSoftDev.Identity.Application.Command 8 | { 9 | public class AddRoleCommandHandler : IRequestHandler 10 | { 11 | private readonly IRoleRepository _roleRepository; 12 | private readonly IStringLocalizer _stringLocalizer; 13 | private readonly IIdGenerator _idGenerator; 14 | 15 | public AddRoleCommandHandler(IRoleRepository roleRepository, IStringLocalizer stringLocalizer, 16 | IIdGenerator idGenerator) 17 | { 18 | _roleRepository = roleRepository; 19 | _stringLocalizer = stringLocalizer; 20 | _idGenerator = idGenerator; 21 | } 22 | 23 | public async Task Handle(AddRoleCommand request, CancellationToken cancellationToken) 24 | { 25 | var role = await _roleRepository.Get(role => role.Title == request.Title, cancellationToken); 26 | if (role is not null) 27 | throw new AppException(ApiResultStatusCode.AlreadyExists); 28 | 29 | var newRole = new Role(_idGenerator.CreateId(), request.Title, request.Description, request.Active); 30 | await _roleRepository.Add(newRole, cancellationToken); 31 | await _roleRepository.UnitOfWork.SaveChangesAsync(cancellationToken); 32 | 33 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/DeleteRoleCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class DeleteRoleCommand : IRequest 7 | { 8 | public long Id { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/DeleteRoleCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 3 | using MediatR; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace ErSoftDev.Identity.Application.Command 7 | { 8 | public class DeleteRoleCommandHandler : IRequestHandler 9 | { 10 | private readonly IRoleRepository _roleRepository; 11 | private readonly IStringLocalizer _stringLocalizer; 12 | 13 | public DeleteRoleCommandHandler(IRoleRepository roleRepository, 14 | IStringLocalizer stringLocalizer) 15 | { 16 | _roleRepository = roleRepository; 17 | _stringLocalizer = stringLocalizer; 18 | } 19 | 20 | public async Task Handle(DeleteRoleCommand request, CancellationToken cancellationToken) 21 | { 22 | var role = await _roleRepository.Get(role => role.Id == request.Id, cancellationToken); 23 | if (role == null) 24 | throw new AppException(_stringLocalizer, ApiResultStatusCode.NotFound); 25 | 26 | _roleRepository.Delete(role); 27 | 28 | await _roleRepository.UnitOfWork.SaveChangesAsync(cancellationToken); 29 | 30 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/DeleteUserCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class DeleteUserCommand : IRequest 7 | { 8 | public long UserId { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/DeleteUserCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 4 | using MediatR; 5 | using Microsoft.Extensions.Localization; 6 | 7 | namespace ErSoftDev.Identity.Application.Command 8 | { 9 | public class DeleteUserCommandHandler : IRequestHandler 10 | { 11 | private readonly IUserRepository _userRepository; 12 | private readonly IStringLocalizer _stringLocalizer; 13 | 14 | public DeleteUserCommandHandler(IUserRepository userRepository, IStringLocalizer stringLocalizer) 15 | { 16 | _userRepository = userRepository; 17 | _stringLocalizer = stringLocalizer; 18 | } 19 | public async Task Handle(DeleteUserCommand request, CancellationToken cancellationToken) 20 | { 21 | var user = await _userRepository.Get(u => u.Id == request.UserId, cancellationToken); 22 | if (user is null) 23 | throw new AppException(_stringLocalizer, ApiResultStatusCode.NotFound); 24 | 25 | _userRepository.Delete(user); 26 | 27 | await _userRepository.UnitOfWork.SaveChangesAsync(cancellationToken); 28 | 29 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/GetRefreshTokenCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class GetRefreshTokenCommand : IRequest> 7 | { 8 | public string RefreshToken { get; set; } 9 | } 10 | 11 | public class RefreshTokenResponse 12 | { 13 | public string Token { get; set; } 14 | public DateTime TokenExpiry { get; set; } 15 | public string RefreshToken { get; set; } 16 | public DateTime RefreshTokenExpiry { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/LoginCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class LoginCommand : IRequest> 7 | { 8 | public string Username { get; set; } 9 | public string Password { get; set; } 10 | public string? DeviceName { get; set; } 11 | public string? DeviceUniqueId { get; set; } 12 | public string? FcmToken { get; set; } 13 | public string? Browser { get; set; } 14 | } 15 | 16 | public class LoginResponse 17 | { 18 | public string Token { get; set; } 19 | public DateTime TokenExpiry { get; set; } 20 | public string RefreshToken { get; set; } 21 | public DateTime RefreshTokenExpiry { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/RegisterUserCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class RegisterUserCommand : IRequest 7 | { 8 | public string Firstname { get; set; } 9 | public string Lastname { get; set; } 10 | public string Username { get; set; } 11 | public string Password { get; set; } 12 | public string CheckPassword { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/RegisterUserCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 4 | using IdGen; 5 | using MediatR; 6 | using Microsoft.Extensions.Localization; 7 | 8 | namespace ErSoftDev.Identity.Application.Command 9 | { 10 | public class RegisterUserCommandHandler : IRequestHandler 11 | { 12 | private readonly IIdGenerator _idGenerator; 13 | private readonly IUserRepository _userRepository; 14 | private readonly IStringLocalizer _stringLocalizer; 15 | 16 | public RegisterUserCommandHandler(IIdGenerator idGenerator, IUserRepository userRepository, IStringLocalizer stringLocalizer) 17 | { 18 | _idGenerator = idGenerator; 19 | _userRepository = userRepository; 20 | _stringLocalizer = stringLocalizer; 21 | } 22 | 23 | public async Task Handle(RegisterUserCommand request, CancellationToken cancellationToken) 24 | { 25 | var user = await _userRepository.Get( 26 | u => u.Username.ToLower() == request.Username.ToLower() && u.IsDeleted == false, 27 | cancellationToken); 28 | if (user != null) 29 | throw new AppException(ApiResultStatusCode.AlreadyExists); 30 | 31 | var md5Password = SecurityHelper.GetMd5(request.Password); 32 | 33 | var newUser = new User(_idGenerator.CreateId(), request.Firstname, 34 | request.Lastname, request.Username, 35 | md5Password.EncrypedData, SecurityHelper.GetMd5(request.CheckPassword, md5Password.Salt).EncrypedData, 36 | md5Password.Salt, true); 37 | await _userRepository.Add(newUser, cancellationToken); 38 | await _userRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); 39 | 40 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/RevokeRefreshTokenCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class RevokeRefreshTokenCommand : IRequest 7 | { 8 | public string RefreshToken { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/RevokeRefreshTokenCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 3 | using MediatR; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace ErSoftDev.Identity.Application.Command 7 | { 8 | public class RevokeRefreshTokenCommandHandler : IRequestHandler 9 | { 10 | private readonly IUserRepository _userRepository; 11 | private readonly IStringLocalizer _stringLocalizer; 12 | 13 | public RevokeRefreshTokenCommandHandler(IUserRepository userRepository, IStringLocalizer stringLocalizer) 14 | { 15 | _userRepository = userRepository; 16 | _stringLocalizer = stringLocalizer; 17 | } 18 | public async Task Handle(RevokeRefreshTokenCommand request, CancellationToken cancellationToken) 19 | { 20 | var user = await _userRepository.GetByRefreshToken(request.RefreshToken, cancellationToken); 21 | if (user == null) 22 | throw new AppException(ApiResultStatusCode.NotFound); 23 | 24 | user.RevokeRefreshToken(request.RefreshToken); 25 | 26 | await _userRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); 27 | 28 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/UpdateRoleCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using MediatR; 3 | 4 | namespace ErSoftDev.Identity.Application.Command 5 | { 6 | public class UpdateRoleCommand : IRequest 7 | 8 | { 9 | public long Id { get; set; } 10 | public string? Title { get; set; } 11 | public string? Description { get; set; } 12 | public bool? IsActive { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/UpdateRoleCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 3 | using MediatR; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace ErSoftDev.Identity.Application.Command 7 | { 8 | public class UpdateRoleCommandHandler : IRequestHandler 9 | { 10 | private readonly IRoleRepository _roleRepository; 11 | private readonly IStringLocalizer _stringLocalizer; 12 | 13 | public UpdateRoleCommandHandler(IRoleRepository roleRepository, IStringLocalizer stringLocalizer) 14 | { 15 | _roleRepository = roleRepository; 16 | _stringLocalizer = stringLocalizer; 17 | } 18 | public async Task Handle(UpdateRoleCommand request, CancellationToken cancellationToken) 19 | { 20 | var role = await _roleRepository.Get(role => role.Id == request.Id, cancellationToken); 21 | if (role == null) 22 | throw new AppException(ApiResultStatusCode.NotFound); 23 | 24 | role.Update(request.Title, request.Description, request.IsActive); 25 | await _roleRepository.UnitOfWork.SaveChangesAsync(cancellationToken); 26 | 27 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/UpdateUserCommand.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 3 | using MediatR; 4 | 5 | namespace ErSoftDev.Identity.Application.Command 6 | { 7 | public class UpdateUserCommand : IRequest 8 | { 9 | public long Id { get; set; } 10 | public string? Firstname { get; set; } 11 | public string? Lastname { get; set; } 12 | public string? CellPhone { get; set; } 13 | public string? Email { get; set; } 14 | public Address? Address { get; set; } 15 | public bool? IsActive { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Command/UpdateUserCommandHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 3 | using MediatR; 4 | using Microsoft.Extensions.Localization; 5 | 6 | namespace ErSoftDev.Identity.Application.Command 7 | { 8 | public class UpdateUserCommandHandler : IRequestHandler 9 | { 10 | private readonly IUserRepository _userRepository; 11 | private readonly IStringLocalizer _stringLocalizer; 12 | 13 | public UpdateUserCommandHandler(IUserRepository userRepository, IStringLocalizer stringLocalizer) 14 | { 15 | _userRepository = userRepository; 16 | _stringLocalizer = stringLocalizer; 17 | } 18 | public async Task Handle(UpdateUserCommand request, CancellationToken cancellationToken) 19 | { 20 | var user = await _userRepository.Get(user => user.Id == request.Id, cancellationToken); 21 | if (user is null) 22 | throw new AppException(ApiResultStatusCode.NotFound); 23 | 24 | user.Update(request.Firstname, request.Lastname, request.CellPhone, request.Email, request.Address, 25 | request.IsActive); 26 | 27 | await _userRepository.UnitOfWork.SaveEntitiesAsync(cancellationToken); 28 | 29 | return new ApiResult(_stringLocalizer, ApiResultStatusCode.Success); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Dtos/OperateDto.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Identity.Application.Dtos 2 | { 3 | public class OperateDto 4 | { 5 | public string Title { get; set; } 6 | public string Description { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Dtos/RoleDto.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Identity.Application.Dtos 2 | { 3 | public class RoleDto 4 | { 5 | public string Id { get; set; } 6 | public string Title { get; set; } 7 | public string Description { get; set; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/ErSoftDev.Identity.Application.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/HealthChecks/CapEventBusPublishHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using DotNetCore.CAP; 2 | using EventBus.Base.Standard; 3 | using Microsoft.Extensions.Diagnostics.HealthChecks; 4 | 5 | namespace ErSoftDev.Identity.Application.HealthChecks 6 | { 7 | public class CapEventBusPublishHealthCheck : IHealthCheck 8 | { 9 | private readonly ICapPublisher _capPublisher; 10 | 11 | public CapEventBusPublishHealthCheck(ICapPublisher capPublisher) 12 | { 13 | _capPublisher = capPublisher; 14 | } 15 | 16 | public async Task CheckHealthAsync(HealthCheckContext context, 17 | CancellationToken cancellationToken = new CancellationToken()) 18 | { 19 | try 20 | { 21 | await _capPublisher.PublishAsync( 22 | "ErSoftDev.Identity.Application.HealthChecks.RabbitMqHealthCheckIntegrationEvent", 23 | new CapHealthCheckIntegrationEvent(), cancellationToken: cancellationToken); 24 | 25 | return HealthCheckResult.Healthy(); 26 | } 27 | catch 28 | { 29 | return HealthCheckResult.Unhealthy(); 30 | } 31 | } 32 | } 33 | 34 | public class CapHealthCheckIntegrationEvent : IntegrationEvent 35 | { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/HealthChecks/CapEventBusSubscribeHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using DotNetCore.CAP; 2 | using EventBus.Base.Standard; 3 | using Microsoft.Extensions.Diagnostics.HealthChecks; 4 | 5 | namespace ErSoftDev.Identity.Application.HealthChecks 6 | { 7 | public class CapEventBusSubscribeHealthCheck : IHealthCheck, IIntegrationEventHandler, ICapSubscribe 8 | { 9 | [CapSubscribe("ErSoftDev.Identity.Application.HealthChecks.RabbitMqHealthCheckIntegrationEvent")] 10 | public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) 11 | { 12 | return HealthCheckResult.Healthy(); 13 | } 14 | 15 | public async Task Handle(CapHealthCheckIntegrationEvent @event) 16 | { 17 | 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/HealthChecks/DataBaseHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Infrastructure; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Diagnostics.HealthChecks; 4 | 5 | namespace ErSoftDev.Identity.Application.HealthChecks 6 | { 7 | public class DataBaseHealthCheck : IHealthCheck 8 | { 9 | private readonly IdentityDbContext _identityDbContext; 10 | 11 | public DataBaseHealthCheck(IdentityDbContext identityDbContext) 12 | { 13 | _identityDbContext = identityDbContext; 14 | } 15 | public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) 16 | { 17 | try 18 | { 19 | _identityDbContext.Database.SqlQuery($"SELECT 1"); 20 | return HealthCheckResult.Healthy(); 21 | } 22 | catch 23 | { 24 | return HealthCheckResult.Unhealthy(); 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/HealthChecks/RedisHealthCheck.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.Redis; 2 | using Microsoft.Extensions.Diagnostics.HealthChecks; 3 | 4 | namespace ErSoftDev.Identity.Application.HealthChecks 5 | { 6 | public class RedisHealthCheck : IHealthCheck 7 | { 8 | private readonly IRedisService _redisService; 9 | 10 | public RedisHealthCheck(IRedisService redisService) 11 | { 12 | _redisService = redisService; 13 | } 14 | public async Task CheckHealthAsync(HealthCheckContext context, CancellationToken cancellationToken = new CancellationToken()) 15 | { 16 | var result = await _redisService.AddOrUpdateAsync("TestKey", 1, TimeSpan.FromSeconds(10)); 17 | return result ? HealthCheckResult.Healthy() : HealthCheckResult.Unhealthy(); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/IntegrationEvents/IntegrationEventExtension.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Application.HealthChecks; 2 | using EventBus.Base.Standard; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace ErSoftDev.Identity.Application.IntegrationEvents 7 | { 8 | public static class IntegrationEventExtension 9 | { 10 | public static IEnumerable GetHandlers() 11 | { 12 | return new List 13 | { 14 | new CapEventBusSubscribeHealthCheck() 15 | }; 16 | } 17 | 18 | public static IApplicationBuilder SubscribeToEvents(this IApplicationBuilder app) 19 | { 20 | var eventBus = app.ApplicationServices.GetRequiredService(); 21 | eventBus.Subscribe(); 22 | 23 | return app; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/CheckAuthenticateAndAuthorizationQuery.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace ErSoftDev.Identity.Application.Queries 4 | { 5 | public class CheckAuthenticateAndAuthorizationQuery : IRequest 6 | { 7 | public string SecurityStampToken { get; set; } 8 | public string Operate { get; set; } 9 | 10 | public CheckAuthenticateAndAuthorizationQuery(string securityStampToken, string operate) 11 | { 12 | SecurityStampToken = securityStampToken; 13 | Operate = operate; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/CheckAuthorizeQuery.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace ErSoftDev.Identity.Application.Queries 4 | { 5 | public class CheckAuthorizeQuery : IRequest 6 | { 7 | public string SecurityStampToken { get; set; } 8 | public string Operate { get; set; } 9 | 10 | public CheckAuthorizeQuery(string securityStampToken, string operate) 11 | { 12 | SecurityStampToken = securityStampToken; 13 | Operate = operate; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/CheckAuthorizeQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.Redis; 2 | using ErSoftDev.Identity.Application.Queries; 3 | using ErSoftDev.Identity.Domain.AggregatesModel.OperateAggregate; 4 | using ErSoftDev.Identity.Domain.SeedWorks; 5 | using ErSoftDev.Identity.Infrastructure; 6 | using MediatR; 7 | using Microsoft.EntityFrameworkCore; 8 | 9 | namespace ErSoftDev.Identity.Application.Queries 10 | { 11 | public class CheckAuthorizeQueryHandler : IRequestHandler 12 | { 13 | private readonly IRedisService _redisService; 14 | private readonly IdentityQueryDbContext _identityQueryDbContext; 15 | 16 | public CheckAuthorizeQueryHandler(IRedisService redisService, IdentityQueryDbContext identityQueryDbContext) 17 | { 18 | _redisService = redisService; 19 | _identityQueryDbContext = identityQueryDbContext; 20 | } 21 | public async Task Handle(CheckAuthorizeQuery request, CancellationToken cancellationToken) 22 | { 23 | var authorizeFromCache = 24 | await _redisService.GetAsync>(CacheKey.UserOperates + ":" + request.SecurityStampToken); 25 | if (authorizeFromCache != null!) 26 | { 27 | if (authorizeFromCache.Any(operate => operate.Title == request.Operate)) 28 | return true; 29 | return false; 30 | } 31 | 32 | var authorizeQuery = 33 | from user in _identityQueryDbContext.Users 34 | join userRole in _identityQueryDbContext.UserRoles 35 | on user.Id equals userRole.UserId into userGrouping 36 | from userRole in userGrouping 37 | where user.SecurityStampToken == request.SecurityStampToken 38 | 39 | join roleOperate in _identityQueryDbContext.RoleOperates 40 | on userRole.RoleId equals roleOperate.RoleId into roleOperateGrouping 41 | from roleOperate in roleOperateGrouping 42 | 43 | join operate in _identityQueryDbContext.Operates 44 | on roleOperate.OperateId equals operate.Id into operateGrouping 45 | from operate in operateGrouping 46 | select operate; 47 | var authorize = await authorizeQuery.ToListAsync(cancellationToken); 48 | 49 | await _redisService.AddOrUpdateAsync(CacheKey.UserOperates + ":" + request.SecurityStampToken, authorize, 50 | TimeSpan.FromMinutes(10)); 51 | 52 | return authorize.Count > 0 && 53 | authorize.Any(operate => operate.Title == request.Operate); 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/GetOperatesQuery.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Application.Dtos; 4 | using MediatR; 5 | 6 | namespace ErSoftDev.Identity.Application.Queries 7 | { 8 | public class GetOperatesQuery : PagingRequest, IRequest>> 9 | { 10 | public string? Title { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/GetOperatesQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Application.Dtos; 4 | using ErSoftDev.Identity.Application.Queries; 5 | using ErSoftDev.Identity.Infrastructure; 6 | using MediatR; 7 | using Microsoft.EntityFrameworkCore; 8 | using Microsoft.Extensions.Localization; 9 | 10 | namespace ErSoftDev.Identity.Application.Queries 11 | { 12 | public class GetOperatesQueryHandler : IRequestHandler>> 13 | { 14 | private readonly IdentityQueryDbContext _identityQueryDbContext; 15 | private readonly IStringLocalizer _stringLocalizer; 16 | 17 | public GetOperatesQueryHandler(IdentityQueryDbContext identityQueryDbContext, IStringLocalizer stringLocalizer) 18 | { 19 | _identityQueryDbContext = identityQueryDbContext; 20 | _stringLocalizer = stringLocalizer; 21 | } 22 | public async Task>> Handle(GetOperatesQuery request, CancellationToken cancellationToken) 23 | { 24 | var operates = await _identityQueryDbContext.Operates.Where(operate => 25 | (request.Title == null || EF.Functions.Like(operate.Title, "%" + request.Title + "%"))).Select( 26 | operate => new 27 | { 28 | operate.Id, 29 | operate.Title, 30 | operate.Description 31 | }).OrderBy(request.OrderBy, request.OrderType.ToString()) 32 | .GetPaged(request.PageNumber, request.PageSize, cancellationToken); 33 | 34 | return new ApiResult>(_stringLocalizer, ApiResultStatusCode.Success, 35 | operates.MapTo>()); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/GetRolesQuery.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Application.Dtos; 4 | using MediatR; 5 | 6 | namespace ErSoftDev.Identity.Application.Queries 7 | { 8 | public class GetRolesQuery : PagingRequest, IRequest>> 9 | { 10 | public long? Id { get; set; } 11 | public string? Title { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/GetRolesQueryHandlers.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Application.Dtos; 4 | using ErSoftDev.Identity.Infrastructure; 5 | using MediatR; 6 | using Microsoft.EntityFrameworkCore; 7 | using Microsoft.Extensions.Localization; 8 | 9 | namespace ErSoftDev.Identity.Application.Queries 10 | { 11 | internal class GetRolesQueryHandlers : IRequestHandler>> 12 | { 13 | private readonly IdentityQueryDbContext _identityQueryDbContext; 14 | private readonly IStringLocalizer _stringLocalizer; 15 | 16 | public GetRolesQueryHandlers(IdentityQueryDbContext identityQueryDbContext, 17 | IStringLocalizer stringLocalizer) 18 | { 19 | _identityQueryDbContext = identityQueryDbContext; 20 | _stringLocalizer = stringLocalizer; 21 | } 22 | 23 | public async Task>> Handle(GetRolesQuery request, 24 | CancellationToken cancellationToken) 25 | { 26 | var roles = await _identityQueryDbContext.Roles.Where(role => 27 | (request.Id == null || role.Id == request.Id) && 28 | (request.Title == null || EF.Functions.Like(role.Title, "%" + request.Title + "%"))) 29 | .Select(role => new { role.Id, role.Title, role.Description }) 30 | .OrderBy(request.OrderBy, request.OrderType.ToString()) 31 | .GetPaged(request.PageNumber, request.PageSize, cancellationToken); 32 | 33 | return new ApiResult>(_stringLocalizer, ApiResultStatusCode.Success, 34 | roles.MapTo>()); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/IsSecurityStampTokenQuery.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | 3 | namespace ErSoftDev.Identity.Application.Queries 4 | { 5 | public class IsSecurityStampTokenValidQuery : IRequest 6 | { 7 | public IsSecurityStampTokenValidQuery(string securityStampToken) 8 | { 9 | SecurityStampToken = securityStampToken; 10 | } 11 | public string SecurityStampToken { get; set; } 12 | public string ActionName { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Application/Queries/IsSecurityStampTokenQueryHandler.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Application.Queries; 2 | using ErSoftDev.Identity.Infrastructure; 3 | using MediatR; 4 | using Microsoft.EntityFrameworkCore; 5 | 6 | namespace ErSoftDev.Identity.Application.Queries 7 | { 8 | public class IsSecurityStampTokenQueryHandler : IRequestHandler 9 | { 10 | private readonly IdentityQueryDbContext _identityQueryDbContext; 11 | 12 | public IsSecurityStampTokenQueryHandler(IdentityQueryDbContext identityQueryDbContext) 13 | { 14 | _identityQueryDbContext = identityQueryDbContext; 15 | } 16 | public async Task Handle(IsSecurityStampTokenValidQuery request, CancellationToken cancellationToken) 17 | { 18 | var userInfo = 19 | await _identityQueryDbContext.Users.FirstOrDefaultAsync(user => 20 | user.SecurityStampToken == request.SecurityStampToken, cancellationToken); 21 | if (userInfo is null) 22 | return false; 23 | return true; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/OperateAggregate/Operate.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using ErSoftDev.DomainSeedWork; 3 | 4 | namespace ErSoftDev.Identity.Domain.AggregatesModel.OperateAggregate 5 | { 6 | public class Operate : BaseEntity, IAggregateRoot 7 | { 8 | public string Title { get; private set; } 9 | public string Description { get; private set; } 10 | private Operate() { } 11 | 12 | public Operate(string title, string description) 13 | { 14 | var parameterValidation = new StringBuilder(); 15 | if (string.IsNullOrWhiteSpace(title)) 16 | parameterValidation.Append(nameof(title) + " | "); 17 | if (string.IsNullOrWhiteSpace(description)) 18 | parameterValidation.Append(nameof(description) + " "); 19 | if (parameterValidation.Length > 0) 20 | throw new AppException(ApiResultStatusCode.ParametersAreNotValid, 21 | parameterValidation.ToString()); 22 | 23 | Title = title; 24 | Description = description; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/RoleAggregate/IRoleRepository.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate 4 | { 5 | public interface IRoleRepository : IRepository 6 | { 7 | 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/RoleAggregate/Role.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using ErSoftDev.DomainSeedWork; 3 | 4 | namespace ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate 5 | { 6 | public class Role : BaseEntity, IAggregateRoot 7 | { 8 | public string Title { get; private set; } 9 | public string Description { get; private set; } 10 | public bool IsActive { get; private set; } 11 | 12 | private readonly List _roleOperates; 13 | public IReadOnlyCollection RoleOperates => _roleOperates; 14 | 15 | private Role() { } 16 | 17 | public Role(long id, string title, string description, bool isActive) 18 | { 19 | var parameterValidation = new StringBuilder(); 20 | if (string.IsNullOrWhiteSpace(title)) 21 | parameterValidation.Append(nameof(title) + " | "); 22 | if (string.IsNullOrWhiteSpace(description)) 23 | parameterValidation.Append(nameof(description) + " "); 24 | if (parameterValidation.Length > 0) 25 | throw new AppException(ApiResultStatusCode.ParametersAreNotValid, 26 | parameterValidation.ToString()); 27 | 28 | Id = id; 29 | Title = title; 30 | Description = description; 31 | IsActive = isActive; 32 | } 33 | 34 | public void Update(string? title, string? description, bool? isActive) 35 | { 36 | Title = title ?? Title; 37 | Description = description ?? Description; 38 | IsActive = isActive ?? IsActive; 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/RoleAggregate/RoleOperate.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate 4 | { 5 | public class RoleOperate : BaseEntity 6 | { 7 | public long RoleId { get; private set; } 8 | public long OperateId { get; private set; } 9 | public Role Role { get; private set; } 10 | 11 | private RoleOperate() { } 12 | public RoleOperate(long roleId, long actionId) 13 | { 14 | RoleId = roleId; 15 | OperateId = actionId; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/UserAggregate/Address.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate 4 | { 5 | public class Address : ValueObject 6 | 7 | { 8 | public long StateId { get; private set; } 9 | public string StateName { get; private set; } 10 | public long CityId { get; private set; } 11 | public string CityName { get; private set; } 12 | public string AddressLine { get; private set; } 13 | public string Plaque { get; private set; } 14 | public string Unit { get; private set; } 15 | public string PostalCode { get; private set; } 16 | 17 | private Address() 18 | { 19 | 20 | } 21 | 22 | public Address(string addressLine, string plaque, string unit, string postalCode, long stateId, 23 | string stateName, long cityId, string cityName) 24 | { 25 | AddressLine = addressLine; 26 | Plaque = plaque; 27 | Unit = unit; 28 | PostalCode = postalCode; 29 | StateId = stateId; 30 | CityId = cityId; 31 | CityName = cityName; 32 | AddressLine = addressLine; 33 | } 34 | 35 | protected override IEnumerable GetEqualityComponents() 36 | { 37 | yield return StateId; 38 | yield return StateName; 39 | yield return CityId; 40 | yield return CityName; 41 | yield return AddressLine; 42 | yield return Plaque; 43 | yield return Unit; 44 | yield return PostalCode; 45 | } 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/UserAggregate/IUserRepository.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate 4 | { 5 | public interface IUserRepository : IRepository 6 | { 7 | Task GetByUsernameAndPassword(string username, string password, CancellationToken cancellationToken); 8 | 9 | Task GetUser(long id, CancellationToken cancellationToken); 10 | 11 | Task GetUserByUsername(string username, CancellationToken cancellationToken); 12 | 13 | Task GetByRefreshToken(string refreshToken, CancellationToken cancellationToken); 14 | 15 | //Task GetUserBySecurityStampToken(string securityStampToken, CancellationToken cancellationToken); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/UserAggregate/UserLogin.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Domain.SeedWorks; 4 | 5 | namespace ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate 6 | { 7 | public class UserLogin : BaseEntity, ISoftDelete 8 | { 9 | public long UserId { get; private set; } 10 | public string? DeviceName { get; private set; } 11 | public string? DeviceUniqueId { get; private set; } 12 | public string? FcmToken { get; private set; } 13 | public string? Browser { get; private set; } 14 | public bool IsDeleted { get; set; } 15 | public long? DeleterUserId { get; set; } 16 | public DateTime? DeletedAt { get; set; } 17 | 18 | public User User { get; private set; } 19 | 20 | private UserLogin() 21 | { 22 | } 23 | 24 | public UserLogin(long id, long userId, string? deviceName, string? deviceUniqueId, string? fcmToken, string? browser) 25 | { 26 | var parameterValidation = new StringBuilder(); 27 | if (id == 0) 28 | parameterValidation.Append(nameof(id) + " "); 29 | if (userId == 0) 30 | parameterValidation.Append(nameof(userId)); 31 | if (parameterValidation.Length > 0) 32 | throw new AppException(ApiResultStatusCode.ParametersAreNotValid, 33 | parameterValidation.ToString()); 34 | 35 | //if (string.IsNullOrWhiteSpace(deviceName) && string.IsNullOrWhiteSpace(browser)) 36 | // throw new AppException(IdentityResultStatusCode.OneOfTheBrowserOrDeviceNameMustBeFill); 37 | 38 | Id = id; 39 | UserId = userId; 40 | DeviceName = deviceName; 41 | DeviceUniqueId = deviceUniqueId; 42 | FcmToken = fcmToken; 43 | Browser = browser; 44 | CreatorUserId = userId; 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/UserAggregate/UserRefreshToken.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using ErSoftDev.DomainSeedWork; 3 | 4 | namespace ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate 5 | { 6 | public class UserRefreshToken : BaseEntity, ISoftDelete 7 | { 8 | public long UserId { get; private set; } 9 | public string Token { get; private set; } 10 | public bool IsActive { get; private set; } 11 | public bool IsUse { get; private set; } 12 | public bool IsRevoke { get; private set; } 13 | public DateTime ExpireAt { get; private set; } 14 | public bool IsDeleted { get; set; } 15 | public long? DeleterUserId { get; set; } 16 | public DateTime? DeletedAt { get; set; } 17 | 18 | public User User { get; private set; } 19 | 20 | private UserRefreshToken() 21 | { 22 | 23 | } 24 | 25 | public UserRefreshToken(long id, long userId, string token, bool isActive, bool isUse, bool isRevoke, DateTime expireAt) 26 | { 27 | var parameterValidation = new StringBuilder(); 28 | if (id == 0) 29 | parameterValidation.Append(nameof(id) + " "); 30 | if (userId == 0) 31 | parameterValidation.Append(nameof(userId)); 32 | if (parameterValidation.Length > 0) 33 | throw new AppException(ApiResultStatusCode.ParametersAreNotValid, 34 | parameterValidation.ToString()); 35 | 36 | Id = id; 37 | UserId = userId; 38 | Token = token; 39 | IsActive = isActive; 40 | IsUse = isUse; 41 | IsRevoke = isRevoke; 42 | ExpireAt = expireAt; 43 | CreatorUserId = userId; 44 | } 45 | 46 | public void DeleteRefreshToken() 47 | { 48 | IsDeleted = true; 49 | DeletedAt = DateTime.Now; 50 | DeleterUserId = UserId; 51 | } 52 | 53 | public void UseRefreshToken() 54 | { 55 | IsUse = true; 56 | } 57 | 58 | public void RevokeRefreshToken() 59 | { 60 | IsRevoke = true; 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/AggregatesModel/UserAggregate/UserRole.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate 4 | { 5 | public class UserRole : BaseEntity, ISoftDelete 6 | { 7 | public long UserId { get; private set; } 8 | public long RoleId { get; private set; } 9 | public bool IsDeleted { get; set; } 10 | public long? DeleterUserId { get; set; } 11 | public DateTime? DeletedAt { get; set; } 12 | 13 | public User User { get; private set; } 14 | 15 | private UserRole() 16 | { 17 | 18 | } 19 | 20 | public UserRole(long userId, long roleId) 21 | { 22 | UserId = userId; 23 | RoleId = roleId; 24 | } 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/ErSoftDev.Identity.Domain.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | True 20 | True 21 | IdentityTranslate.resx 22 | 23 | 24 | 25 | 26 | 27 | ResXFileCodeGenerator 28 | IdentityTranslate.Designer.cs 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/IdentityTranslate.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Identity.Domain 2 | { 3 | public class IdentityTranslate 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/SeedWorks/CacheKey.cs: -------------------------------------------------------------------------------- 1 | namespace ErSoftDev.Identity.Domain.SeedWorks 2 | { 3 | public enum CacheKey 4 | { 5 | Login = 0, 6 | UserOperates = 1 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Domain/SeedWorks/IdentityResultErrorCode.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Domain.SeedWorks 4 | { 5 | public class IdentityResultStatusCode : ApiResultStatusCode 6 | { 7 | public static IdentityResultStatusCode UsernameOrPasswordIsNotCorrect => 8 | new(100, nameof(UsernameOrPasswordIsNotCorrect)); 9 | public static IdentityResultStatusCode PasswordsAreNotEqual => new(101, nameof(PasswordsAreNotEqual)); 10 | public static IdentityResultStatusCode RefreshTokenIsDeActive => new(102, nameof(RefreshTokenIsDeActive)); 11 | public static IdentityResultStatusCode RefreshTokenIsUsed => new(103, nameof(RefreshTokenIsUsed)); 12 | public static IdentityResultStatusCode RefreshTokenIsRevoked => new(104, nameof(RefreshTokenIsRevoked)); 13 | public static IdentityResultStatusCode RefreshTokenIsExpire => new(105, nameof(RefreshTokenIsExpire)); 14 | public static IdentityResultStatusCode AllFieldsOfAddressMustBeFillOrNonOfFields => new(106, nameof(AllFieldsOfAddressMustBeFillOrNonOfFields)); 15 | public static IdentityResultStatusCode OneOfTheBrowserOrDeviceNameMustBeFill => new(107, nameof(OneOfTheBrowserOrDeviceNameMustBeFill)); 16 | public static IdentityResultStatusCode UserIsNotLogin => new(108, nameof(UserIsNotLogin)); 17 | public static IdentityResultStatusCode UserNotFound => new(109, nameof(UserNotFound)); 18 | public static IdentityResultStatusCode UserIsNotActive => new(109, nameof(UserIsNotActive)); 19 | public static IdentityResultStatusCode Test => new(110, nameof(Test)); 20 | 21 | protected IdentityResultStatusCode(int id, string name) : base(id, name) 22 | { 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Configuration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.BaseApp; 2 | using ErSoftDev.Identity.Application.IntegrationEvents; 3 | using ErSoftDev.Identity.Infrastructure; 4 | using EventBus.Base.Standard.Configuration; 5 | using Microsoft.EntityFrameworkCore; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace ErSoftDev.Identity.EndPoint 9 | { 10 | public class Configuration : BaseConfig 11 | { 12 | 13 | private readonly AppSetting _appSetting; 14 | public Configuration(IConfiguration configuration, IHostEnvironment environment) : base(configuration, environment) 15 | { 16 | _appSetting = configuration.GetSection($"{nameof(AppSetting)}{environment.EnvironmentName}") 17 | .Get()!; 18 | } 19 | 20 | public override void ConfigureServices(IServiceCollection services, IWebHostEnvironment webHostEnvironment) 21 | { 22 | services.AddDbContext(builder => 23 | builder.UseSqlServer(_appSetting.ConnectionString.AppConnectionString)); 24 | services.AddDbContext(builder => 25 | builder.UseSqlServer(_appSetting.ConnectionString.AppConnectionString) 26 | .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking)); 27 | 28 | services.AddLocalization(options => options.ResourcesPath = "Resources"); 29 | 30 | services.AddEventBusHandling(IntegrationEventExtension.GetHandlers()); 31 | base.ConfigureServices(services, webHostEnvironment); 32 | } 33 | 34 | public override void Configure(IApplicationBuilder app, IWebHostEnvironment env, AppSetting appsetting) 35 | { 36 | app.SubscribeToEvents(); 37 | base.Configure(app, env, appsetting); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Controllers/IdentityBaseController.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.Filters; 2 | using MediatR; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace ErSoftDev.Identity.EndPoint.Controllers 6 | { 7 | [Route("Identity/api/v{version:apiVersion}/[controller]")] 8 | [ApiController] 9 | [ApiResultFilter] 10 | [Consumes("application/json")] 11 | [Produces("application/json")] 12 | public class IdentityBaseController : ControllerBase 13 | { 14 | private readonly IMediator _mediator; 15 | public IdentityBaseController(IMediator mediator) 16 | { 17 | _mediator = mediator; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Controllers/v1/AccountController.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Identity.Application.Command; 3 | using MediatR; 4 | using Microsoft.AspNetCore.Mvc; 5 | using Microsoft.AspNetCore.Authorization; 6 | 7 | namespace ErSoftDev.Identity.EndPoint.Controllers.v1 8 | { 9 | [ApiVersion("1.0")] 10 | public class AccountController : IdentityBaseController 11 | { 12 | private readonly IMediator _mediator; 13 | 14 | public AccountController(IMediator mediator) : base(mediator) 15 | { 16 | _mediator = mediator; 17 | } 18 | 19 | [HttpPost("[action]")] 20 | [AllowAnonymous] 21 | public async Task Register(RegisterUserCommand request, CancellationToken cancellationToken) 22 | { 23 | return await _mediator.Send(request, cancellationToken); 24 | } 25 | 26 | [HttpPost("[action]")] 27 | [AllowAnonymous] 28 | public async Task> Login(LoginCommand request, CancellationToken cancellationToken) 29 | { 30 | return await _mediator.Send(request, cancellationToken); 31 | } 32 | 33 | [HttpPost("[action]")] 34 | [AllowAnonymous] 35 | public async Task> GetRefreshToken(GetRefreshTokenCommand request, 36 | CancellationToken cancellationToken) 37 | { 38 | return await _mediator.Send(request, cancellationToken); 39 | } 40 | 41 | [HttpPost("[action]")] 42 | [AllowAnonymous] 43 | public async Task RevokeRefreshToken(RevokeRefreshTokenCommand request, 44 | CancellationToken cancellationToken) 45 | { 46 | return await _mediator.Send(request, cancellationToken); 47 | } 48 | 49 | [HttpPut("[action]")] 50 | public async Task Update(UpdateUserCommand request, 51 | CancellationToken cancellationToken) 52 | { 53 | return await _mediator.Send(request, cancellationToken); 54 | } 55 | 56 | [HttpDelete("[action]")] 57 | public async Task Delete(DeleteUserCommand request, 58 | CancellationToken cancellationToken) 59 | { 60 | return await _mediator.Send(request, cancellationToken); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Controllers/v1/RoleController.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Common.Utilities; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Identity.Application.Command; 4 | using ErSoftDev.Identity.Application.Dtos; 5 | using ErSoftDev.Identity.Application.Queries; 6 | using MediatR; 7 | using Microsoft.AspNetCore.Authorization; 8 | using Microsoft.AspNetCore.Mvc; 9 | 10 | namespace ErSoftDev.Identity.EndPoint.Controllers.v1 11 | { 12 | [ApiVersion("1.0")] 13 | [AllowAnonymous] 14 | public class RoleController : IdentityBaseController 15 | { 16 | private readonly IMediator _mediator; 17 | 18 | public RoleController(IMediator mediator) : base(mediator) 19 | { 20 | _mediator = mediator; 21 | } 22 | 23 | [HttpPost("[action]")] 24 | public async Task AddRole(AddRoleCommand request, CancellationToken cancellationToken) 25 | { 26 | return await _mediator.Send(request, cancellationToken); 27 | } 28 | 29 | [HttpGet("[action]")] 30 | public async Task>> GetRoles([FromQuery] GetRolesQuery request, CancellationToken cancellationToken) 31 | { 32 | return await _mediator.Send(request, cancellationToken); 33 | } 34 | 35 | [HttpPut("[action]")] 36 | public async Task UpdateRole(UpdateRoleCommand request, CancellationToken cancellationToken) 37 | { 38 | return await _mediator.Send(request, cancellationToken); 39 | } 40 | 41 | [HttpDelete("[action]")] 42 | public async Task DeleteRole(DeleteRoleCommand request, CancellationToken cancellationToken) 43 | { 44 | return await _mediator.Send(request, cancellationToken); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Dockerfile: -------------------------------------------------------------------------------- 1 | #See https://aka.ms/customizecontainer to learn how to customize your debug container and how Visual Studio uses this Dockerfile to build your images for faster debugging. 2 | 3 | FROM mcr.microsoft.com/dotnet/aspnet:8.0 AS base 4 | USER app 5 | WORKDIR /app 6 | EXPOSE 8080 7 | EXPOSE 8081 8 | 9 | FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build 10 | ARG BUILD_CONFIGURATION=Release 11 | WORKDIR /src 12 | COPY ["src/Identity/ErSoftDev.Identity.EndPoint/ErSoftDev.Identity.EndPoint.csproj", "src/Identity/ErSoftDev.Identity.EndPoint/"] 13 | COPY ["src/Identity/ErSoftDev.Identity.Application/ErSoftDev.Identity.Application.csproj", "src/Identity/ErSoftDev.Identity.Application/"] 14 | COPY ["src/Identity/ErSoftDev.Identity.Domain/ErSoftDev.Identity.Domain.csproj", "src/Identity/ErSoftDev.Identity.Domain/"] 15 | COPY ["src/ErSoftDev.DomainSeedWork/ErSoftDev.DomainSeedWork.csproj", "src/ErSoftDev.DomainSeedWork/"] 16 | COPY ["src/Identity/ErSoftDev.Identity.Infrastructure/ErSoftDev.Identity.Infrastructure.csproj", "src/Identity/ErSoftDev.Identity.Infrastructure/"] 17 | COPY ["src/ErSoftDev.Framework/ErSoftDev.Framework.csproj", "src/ErSoftDev.Framework/"] 18 | COPY ["src/ErSoftDev.Common/ErSoftDev.Common.csproj", "src/ErSoftDev.Common/"] 19 | RUN dotnet restore "./src/Identity/ErSoftDev.Identity.EndPoint/ErSoftDev.Identity.EndPoint.csproj" 20 | COPY . . 21 | WORKDIR "/src/src/Identity/ErSoftDev.Identity.EndPoint" 22 | RUN dotnet build "./ErSoftDev.Identity.EndPoint.csproj" -c $BUILD_CONFIGURATION -o /app/build 23 | 24 | FROM build AS publish 25 | ARG BUILD_CONFIGURATION=Release 26 | RUN dotnet publish "./ErSoftDev.Identity.EndPoint.csproj" -c $BUILD_CONFIGURATION -o /app/publish /p:UseAppHost=false 27 | 28 | FROM base AS final 29 | WORKDIR /app 30 | COPY --from=publish /app/publish . 31 | ENTRYPOINT ["dotnet", "ErSoftDev.Identity.EndPoint.dll"] -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/ErSoftDev.Identity.EndPoint.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 86a6d71b-2123-4a94-b5b5-959d45e767ce 8 | Linux 9 | ..\..\.. 10 | True 11 | IdentityXmlComment.xml 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers; buildtransitive 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Grpc/Google/ProtoBuf/wrappers.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package google.protobuf; 4 | 5 | option csharp_namespace = "Google.Protobuf.WellKnownTypes"; 6 | option cc_enable_arenas = true; 7 | option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; 8 | option java_package = "com.google.protobuf"; 9 | option java_outer_classname = "WrappersProto"; 10 | option java_multiple_files = true; 11 | option objc_class_prefix = "GPB"; 12 | 13 | // Wrapper message for `double`. 14 | // 15 | // The JSON representation for `DoubleValue` is JSON number. 16 | message DoubleValue { 17 | // The double value. 18 | double value = 1; 19 | } 20 | 21 | // Wrapper message for `float`. 22 | // 23 | // The JSON representation for `FloatValue` is JSON number. 24 | message FloatValue { 25 | // The float value. 26 | float value = 1; 27 | } 28 | 29 | // Wrapper message for `int64`. 30 | // 31 | // The JSON representation for `Int64Value` is JSON string. 32 | message Int64Value { 33 | // The int64 value. 34 | int64 value = 1; 35 | } 36 | 37 | // Wrapper message for `uint64`. 38 | // 39 | // The JSON representation for `UInt64Value` is JSON string. 40 | message UInt64Value { 41 | // The uint64 value. 42 | uint64 value = 1; 43 | } 44 | 45 | // Wrapper message for `int32`. 46 | // 47 | // The JSON representation for `Int32Value` is JSON number. 48 | message Int32Value { 49 | // The int32 value. 50 | int32 value = 1; 51 | } 52 | 53 | // Wrapper message for `uint32`. 54 | // 55 | // The JSON representation for `UInt32Value` is JSON number. 56 | message UInt32Value { 57 | // The uint32 value. 58 | uint32 value = 1; 59 | } 60 | 61 | // Wrapper message for `bool`. 62 | // 63 | // The JSON representation for `BoolValue` is JSON `true` and `false`. 64 | message BoolValue { 65 | // The bool value. 66 | bool value = 1; 67 | } 68 | 69 | // Wrapper message for `string`. 70 | // 71 | // The JSON representation for `StringValue` is JSON string. 72 | message StringValue { 73 | // The string value. 74 | string value = 1; 75 | } 76 | 77 | // Wrapper message for `bytes`. 78 | // 79 | // The JSON representation for `BytesValue` is JSON string. 80 | message BytesValue { 81 | // The bytes value. 82 | bytes value = 1; 83 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Grpc/Protos/AccountProto.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option csharp_namespace = "ErSoftDev.Identity.EndPoint.Grpc.Protos"; 3 | package AccountGrpcService; 4 | import "google/protobuf/wrappers.proto"; 5 | 6 | service AccountGrpcService{ 7 | rpc IsSecurityStampTokenValid(IsSecurityStampTokenRequestGrpc) returns (IsSecurityStampTokenResponseGrpc); 8 | rpc CheckAuthorize(CheckAuthorizeRequestGrpc) returns (CheckAuthorizeResponseGrpc); 9 | rpc CheckAuthenticationAndAuthorization(CheckAuthenticationAndAuthorizationGrpcRequest) returns (CheckAuthenticationAndAuthorizationGrpcResponse); 10 | } 11 | 12 | message IsSecurityStampTokenRequestGrpc{ 13 | string SecurityStampToken=1; 14 | } 15 | message IsSecurityStampTokenResponseGrpc{ 16 | int32 Status=1; 17 | string Description=2; 18 | .google.protobuf.Int32Value ErrorCode=3; 19 | .google.protobuf.StringValue ErrorDescription=4; 20 | } 21 | 22 | message CheckAuthorizeRequestGrpc{ 23 | string SecurityStampToken=1; 24 | string Operate=2; 25 | } 26 | message CheckAuthorizeResponseGrpc{ 27 | int32 Status=1; 28 | string Description=2; 29 | .google.protobuf.Int32Value ErrorCode=3; 30 | .google.protobuf.StringValue ErrorDescription=4; 31 | } 32 | 33 | message CheckAuthenticationAndAuthorizationGrpcRequest{ 34 | string SecurityStampToken=1; 35 | string Operate=2; 36 | } 37 | message CheckAuthenticationAndAuthorizationGrpcResponse{ 38 | int32 Status=1; 39 | string Description=2; 40 | .google.protobuf.Int32Value ErrorCode=3; 41 | .google.protobuf.StringValue ErrorDescription=4; 42 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Grpc/Services/AccountService.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | using ErSoftDev.Framework.Grpc; 3 | using ErSoftDev.Identity.Application.Queries; 4 | using ErSoftDev.Identity.Domain.SeedWorks; 5 | using ErSoftDev.Identity.EndPoint.Grpc.Protos; 6 | using Grpc.Core; 7 | using MediatR; 8 | 9 | namespace ErSoftDev.Identity.EndPoint.Grpc.Services 10 | { 11 | public class AccountService : AccountGrpcService.AccountGrpcServiceBase, IGrpcService 12 | { 13 | private readonly IMediator _mediator; 14 | 15 | public AccountService(IMediator mediator) 16 | { 17 | _mediator = mediator; 18 | } 19 | 20 | public override async Task IsSecurityStampTokenValid( 21 | IsSecurityStampTokenRequestGrpc request, ServerCallContext context) 22 | { 23 | var isSecurityStampTokenValid = await _mediator.Send( 24 | new IsSecurityStampTokenValidQuery(request.SecurityStampToken) 25 | , context.CancellationToken); 26 | if (isSecurityStampTokenValid) 27 | return new IsSecurityStampTokenResponseGrpc() { Status = ApiResultStatusCode.Success.Code }; 28 | return new IsSecurityStampTokenResponseGrpc() { Status = IdentityResultStatusCode.TokenIsNotValid.Code }; 29 | } 30 | 31 | public override async Task CheckAuthorize(CheckAuthorizeRequestGrpc request, 32 | ServerCallContext context) 33 | { 34 | var isAuthorize = await _mediator.Send(new CheckAuthorizeQuery(request.SecurityStampToken, request.Operate), 35 | context.CancellationToken); 36 | if (isAuthorize) 37 | return new CheckAuthorizeResponseGrpc() { Status = ApiResultStatusCode.Success.Code }; 38 | return new CheckAuthorizeResponseGrpc() { Status = ApiResultStatusCode.TokenIsNotValid.Code }; 39 | } 40 | 41 | public override async Task CheckAuthenticationAndAuthorization(CheckAuthenticationAndAuthorizationGrpcRequest request, 42 | ServerCallContext context) 43 | { 44 | var isAuthenticateAndAuthorize = 45 | await _mediator.Send( 46 | new CheckAuthenticateAndAuthorizationQuery(request.SecurityStampToken, request.Operate), 47 | context.CancellationToken); 48 | if (isAuthenticateAndAuthorize) 49 | return new CheckAuthenticationAndAuthorizationGrpcResponse() 50 | { Status = ApiResultStatusCode.Success.Code }; 51 | return new CheckAuthenticationAndAuthorizationGrpcResponse() { Status = ApiResultStatusCode.TokenIsNotValid.Code }; 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Program.cs: -------------------------------------------------------------------------------- 1 | using Autofac; 2 | using Autofac.Extensions.DependencyInjection; 3 | using ErSoftDev.Framework.BaseApp; 4 | using ErSoftDev.Framework.Configuration; 5 | using Configuration = ErSoftDev.Identity.EndPoint.Configuration; 6 | 7 | var builder = WebApplication.CreateBuilder(args); 8 | 9 | builder.Host.UseServiceProviderFactory(new AutofacServiceProviderFactory()).ConfigureContainer( 10 | (context, containerBuilder) => containerBuilder.RegisterModule(new AutofacConfigurationExtension())); 11 | 12 | var appSettings = builder.Configuration 13 | .GetSection($"{nameof(AppSetting)}{builder.Environment.EnvironmentName}") 14 | .Get(); 15 | 16 | var startup = new Configuration(builder.Configuration, builder.Environment); 17 | startup.ConfigureServices(builder.Services, builder.Environment); 18 | 19 | var app = builder.Build(); 20 | 21 | startup.Configure(app, builder.Environment, appSettings); 22 | 23 | await app.RunAsync(); -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "http": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "dotnetRunMessages": true, 11 | "applicationUrl": "http://localhost:5297" 12 | }, 13 | "https": { 14 | "commandName": "Project", 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "environmentVariables": { 18 | "ASPNETCORE_ENVIRONMENT": "Development" 19 | }, 20 | "dotnetRunMessages": true, 21 | "applicationUrl": "https://localhost:7282;http://localhost:5297" 22 | }, 23 | "IIS Express": { 24 | "commandName": "IISExpress", 25 | "launchBrowser": true, 26 | "launchUrl": "swagger", 27 | "environmentVariables": { 28 | "ASPNETCORE_ENVIRONMENT": "Development" 29 | } 30 | }, 31 | "Development": { 32 | "commandName": "Project", 33 | "launchBrowser": true, 34 | "launchUrl": "swagger", 35 | "environmentVariables": { 36 | "ASPNETCORE_ENVIRONMENT": "Development" 37 | }, 38 | "applicationUrl": "https://localhost:5002;http://localhost:5102", 39 | }, 40 | "Docker": { 41 | "commandName": "Docker", 42 | "launchBrowser": true, 43 | "launchUrl": "{Scheme}://{ServiceHost}:{ServicePort}/swagger", 44 | "publishAllPorts": true, 45 | "useSSL": false, 46 | "environmentVariables": { 47 | "ASPNETCORE_ENVIRONMENT": "Docker" 48 | }, 49 | "httpPort": 5202 50 | } 51 | }, 52 | "$schema": "https://json.schemastore.org/launchsettings.json", 53 | "iisSettings": { 54 | "windowsAuthentication": false, 55 | "anonymousAuthentication": true, 56 | "iisExpress": { 57 | "applicationUrl": "http://localhost:51398", 58 | "sslPort": 44337 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSettingDevelopment": { 3 | "ConnectionString": { 4 | "AppConnectionString": "data source=(localdb)\\MSSqlLocalDb;initial catalog=Identity;integrated security=True", 5 | "AppConnectionStringReadOnly": "data source=(localdb)\\MSSqlLocalDb;initial catalog=Identity;integrated security=True;ApplicationIntent=READONLY", 6 | "MongoConnectionString": "mongodb://mongo:simplePassword@localhost:27017/test?authSource=admin" 7 | }, 8 | "ShowExceptionMessage": true, 9 | "Logging": { 10 | "LogLevel": "information", 11 | "Microsoft": "fatal", 12 | "system": "fatal" 13 | }, 14 | "ElasticSearch": { 15 | "Url": "http://localhost:9200" 16 | }, 17 | "AllowedHosts": "*", 18 | "Jwt": { 19 | "Issuer": "Identity", 20 | "Audience": "ApiUsers", 21 | "TokenExpirySecond": 600, 22 | "RefreshTokenExpirySecond": 2592000 23 | }, 24 | "Swagger": { 25 | "SpecificationTitle": "Identity Project", 26 | "XmlCommentFileName": "IdentityXmlComment.xml", 27 | "VersionCount": 1 28 | }, 29 | "Configurations": [ 30 | 31 | ], 32 | "EventBusRabbitMq": { 33 | "HostName": "localhost", 34 | "QueueName": "Identity", 35 | "VirtualPort": 5672, 36 | "TryCount": 5, 37 | "DispatchConsumerAsync": "False", 38 | "VirtualHost": "/", 39 | "BrokerName": "RabbitMQBroker", 40 | "Username": "guest", 41 | "Password": "guest", 42 | "PreFetchCount": 1, 43 | "FailedRetryInterval": 5 44 | }, 45 | "Redis": { 46 | "Password": "", 47 | "User": "", 48 | "AllowAdmin": false, 49 | "Ssl": false, 50 | "ConnectTimeout": 1000, 51 | "ConnectRetry": 5, 52 | "Hosts": [ 53 | { 54 | "Host": "65.21.45.146", 55 | "Port": "6379" 56 | } 57 | ], 58 | "ClientName": "Identity" 59 | }, 60 | "NotificationEmail": { 61 | "Sender": "info@ersoftdev.net", 62 | "Recipient": "ehsan.rezaee021@gmail.com" 63 | }, 64 | "Jaeger": { 65 | "Host": "localhost", 66 | "Port": 5775, 67 | "SamplingRate": 0.5 68 | }, 69 | "WelcomeNote": "

Welcome to ErSoftDev services

", 70 | "ServiceDiscoveryConfig": { 71 | "ConsulUrl": "http://localhost:8500/", 72 | "Host": "localhost", 73 | "Port": "5002", 74 | "NameOfService": "Identity", 75 | "IdOfService": "419ae5380e7b4afe99cf03961b1d4b91" 76 | }, 77 | "Hangfire": { 78 | "CommandBatchMaxTimeout": 1, 79 | "SlidingInvisibilityTimeout": 1, 80 | "UseRecommendedIsolationLevel": true, 81 | "DisableGlobalLocks": true, 82 | "PrepareSchemaIfNecessary": true 83 | } 84 | } 85 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/appsettings.Docker.json: -------------------------------------------------------------------------------- 1 | { 2 | "AppSettingDocker": { 3 | "ConnectionString": { 4 | "AppConnectionString": "data source=host.docker.internal,1433;Persist Security Info=False;User ID=sa;Password=1Secure*Password1;initial catalog=Identity;TrustServerCertificate=true", 5 | "AppConnectionStringReadOnly": "data source=host.docker.internal,1433;Persist Security Info=False;User ID=sa;Password=1Secure*Password1;initial catalog=Identity;TrustServerCertificate=trueApplicationIntent=READONLY" 6 | }, 7 | "ShowExceptionMessage": true, 8 | "Logging": { 9 | "LogLevel": "information", 10 | "Microsoft": "fatal", 11 | "system": "fatal" 12 | }, 13 | "ElasticSearch": { 14 | "Url": "http://host.docker.internal:9200" 15 | }, 16 | "AllowedHosts": "*", 17 | "Jwt": { 18 | "Issuer": "Identity", 19 | "Audience": "ApiUsers", 20 | "TokenExpirySecond": 600, 21 | "RefreshTokenExpirySecond": 2592000 22 | }, 23 | "Swagger": { 24 | "SpecificationTitle": "Identity Project", 25 | "XmlCommentFileName": "IdentityXmlComment.xml", 26 | "VersionCount": 1 27 | }, 28 | "Configurations": [ 29 | 30 | ], 31 | "EventBusRabbitMq": { 32 | "HostName": "host.docker.internal", 33 | "QueueName": "Identity", 34 | "VirtualPort": 5672, 35 | "TryCount": 5, 36 | "DispatchConsumerAsync": "False", 37 | "VirtualHost": "/", 38 | "BrokerName": "RabbitMQBroker", 39 | "Username": "guest", 40 | "Password": "guest", 41 | "PreFetchCount": 1, 42 | "FailedRetryInterval": 5 43 | }, 44 | "Redis": { 45 | "Password": "", 46 | "User": "", 47 | "AllowAdmin": false, 48 | "Ssl": false, 49 | "ConnectTimeout": 1000, 50 | "ConnectRetry": 5, 51 | "Hosts": [ 52 | { 53 | "Host": "host.docker.internal", 54 | "Port": "6379" 55 | } 56 | ], 57 | "ClientName": "Identity" 58 | }, 59 | "NotificationEmail": { 60 | "Sender": "info@ersoftdev.net", 61 | "Recipient": "ehsan.rezaee021@gmail.com" 62 | }, 63 | "Jaeger": { 64 | "Host": "host.docker.internal", 65 | "Port": 5775, 66 | "SamplingRate": 0.5 67 | }, 68 | "WelcomeNote": "

Welcome to ErSoftDev services

", 69 | "ServiceDiscoveryConfig": { 70 | "ConsulUrl": "http://host.docker.internal:8500/", 71 | "Host": "host.docker.internal", 72 | "Port": "5202", 73 | "NameOfService": "Identity", 74 | "IdOfService": "419ae5380e7b4afe99cf03961b1d4b91" 75 | }, 76 | "Hangfire": { 77 | "CommandBatchMaxTimeout": 1, 78 | "SlidingInvisibilityTimeout": 1, 79 | "UseRecommendedIsolationLevel": true, 80 | "DisableGlobalLocks": true, 81 | "PrepareSchemaIfNecessary": true 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | }, 8 | "AllowedHosts": "*" 9 | } 10 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.EndPoint/failures.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ehsanrezaee/DotNetBackend/6140150d231006937412603d0217926961a3f13a/src/Identity/ErSoftDev.Identity.EndPoint/failures.txt -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/EntityConfigurations/OperateEntityTypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Domain.AggregatesModel.OperateAggregate; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.EntityConfigurations 6 | { 7 | public class OperateEntityTypeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("Operates", IdentityDbContext.DefaultSchema); 12 | 13 | builder.HasKey(operate => operate.Id); 14 | builder.Property(operate => operate.Id).ValueGeneratedNever(); 15 | builder.Property(operate => operate.Title).HasColumnType("nvarchar").HasMaxLength(100).IsRequired(); 16 | builder.Property(operate => operate.Description).HasColumnType("nvarchar").HasMaxLength(500).IsRequired(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/EntityConfigurations/RoleEntityTypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.EntityConfigurations 6 | { 7 | public class RoleEntityTypeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("Roles", IdentityDbContext.DefaultSchema); 12 | 13 | builder.HasKey(role => role.Id); 14 | builder.Property(role => role.Id).ValueGeneratedNever(); 15 | builder.Property(role => role.Title).HasMaxLength(100).IsRequired(); 16 | builder.Property(role => role.Description).HasMaxLength(500).IsRequired(false); 17 | 18 | builder.HasMany(role => role.RoleOperates).WithOne(userRole => userRole.Role) 19 | .HasForeignKey(userRole => userRole.RoleId).OnDelete(DeleteBehavior.Cascade); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/EntityConfigurations/RoleOperateEntityTypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.EntityConfigurations 6 | { 7 | public class RoleOperateEntityTypeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("RoleOperates", IdentityDbContext.DefaultSchema); 12 | 13 | builder.HasKey(operate => operate.Id); 14 | builder.Property(operate => operate.Id).ValueGeneratedNever(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/EntityConfigurations/UserLoginEntityTypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.EntityConfigurations 6 | { 7 | public class UserLoginEntityTypeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("UserLogins", IdentityDbContext.DefaultSchema); 12 | 13 | builder.HasKey(login => login.Id); 14 | builder.Property(login => login.Id).ValueGeneratedNever(); 15 | builder.Property(login => login.UserId).IsRequired(); 16 | builder.Property(login => login.Browser).HasMaxLength(100).IsRequired(false); 17 | builder.Property(login => login.DeviceName).HasMaxLength(100).IsRequired(false); 18 | builder.Property(login => login.DeviceUniqueId).HasMaxLength(100).IsRequired(false); 19 | builder.Property(login => login.FcmToken).HasMaxLength(100).IsRequired(false); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/EntityConfigurations/UserRefreshTokenEntityTypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.EntityConfigurations 6 | { 7 | public class UserRefreshTokenEntityTypeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("UserRefreshTokens", IdentityDbContext.DefaultSchema); 12 | 13 | builder.HasKey(token => token.Id); 14 | builder.Property(token => token.Id).ValueGeneratedNever(); 15 | builder.Property(token => token.ExpireAt).IsRequired(); 16 | builder.Property(token => token.IsActive).IsRequired(); 17 | builder.Property(token => token.IsRevoke).IsRequired(); 18 | builder.Property(token => token.IsUse).IsRequired(); 19 | builder.Property(token => token.UserId).IsRequired(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/EntityConfigurations/UserRoleEntityTypeConfiguration.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Metadata.Builders; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.EntityConfigurations 6 | { 7 | public class UserRoleEntityTypeConfiguration : IEntityTypeConfiguration 8 | { 9 | public void Configure(EntityTypeBuilder builder) 10 | { 11 | builder.ToTable("UserRoles", IdentityDbContext.DefaultSchema); 12 | 13 | builder.HasKey(role => role.Id); 14 | builder.Property(role => role.Id).ValueGeneratedNever(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/ErSoftDev.Identity.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net8.0 5 | enable 6 | enable 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/IdentityDbContext.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.BaseApp; 2 | using ErSoftDev.Framework.BaseModel; 3 | using ErSoftDev.Identity.Domain.AggregatesModel.OperateAggregate; 4 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 5 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 6 | using MediatR; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.EntityFrameworkCore; 9 | using Microsoft.Extensions.Options; 10 | 11 | namespace ErSoftDev.Identity.Infrastructure 12 | { 13 | public class IdentityDbContext : BaseDbContext 14 | { 15 | public const string DefaultSchema = "dbo"; 16 | 17 | private readonly IMediator _mediator; 18 | private readonly IHttpContextAccessor _httpContextAccessor; 19 | 20 | public IdentityDbContext(DbContextOptions options, IOptions appSetting, 21 | IMediator mediator, IHttpContextAccessor httpContextAccessor) : base( 22 | options, appSetting, mediator, httpContextAccessor) 23 | { 24 | _mediator = mediator; 25 | _httpContextAccessor = httpContextAccessor; 26 | } 27 | 28 | public DbSet Users { get; set; } 29 | public DbSet Roles { get; set; } 30 | public DbSet RoleActions { get; set; } 31 | public DbSet UserRoles { get; set; } 32 | public DbSet UserLogins { get; set; } 33 | public DbSet RefreshTokens { get; set; } 34 | public DbSet Operates { get; set; } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/IdentityQueryDbContext.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.BaseApp; 2 | using ErSoftDev.Framework.BaseModel; 3 | using ErSoftDev.Identity.Domain.AggregatesModel.OperateAggregate; 4 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 5 | using ErSoftDev.Identity.Domain.AggregatesModel.UserAggregate; 6 | using MediatR; 7 | using Microsoft.AspNetCore.Http; 8 | using Microsoft.EntityFrameworkCore; 9 | using Microsoft.Extensions.Options; 10 | 11 | namespace ErSoftDev.Identity.Infrastructure 12 | { 13 | public class IdentityQueryDbContext : BaseDbContext 14 | { 15 | public IdentityQueryDbContext(DbContextOptions options, IOptions appSetting, 16 | IMediator mediator, IHttpContextAccessor httpContextAccessor) : base(options, appSetting, mediator 17 | , httpContextAccessor) 18 | { 19 | } 20 | 21 | public DbSet Users { get; set; } 22 | public DbSet Roles { get; set; } 23 | public DbSet UserRoles { get; set; } 24 | public DbSet UserLogins { get; set; } 25 | public DbSet RefreshTokens { get; set; } 26 | public DbSet RoleOperates { get; set; } 27 | public DbSet Operates { get; set; } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/NoSql/Models/Instrument.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.DomainSeedWork; 2 | 3 | namespace ErSoftDev.Identity.Infrastructure.NoSql.Models 4 | { 5 | public class Instrument : BaseEntity 6 | { 7 | public string FirstName { get; set; } 8 | public string LastName { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/NoSql/Repositories/IInstrumentMongoRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using ErSoftDev.Framework.Mongo; 3 | using ErSoftDev.Identity.Infrastructure.NoSql.Models; 4 | using MongoDB.Driver; 5 | 6 | namespace ErSoftDev.Identity.Infrastructure.NoSql.Repositories; 7 | 8 | public interface IInstrumentMongoRepository : IMongoRepository 9 | { 10 | 11 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/NoSql/Repositories/InstrumentMongoRepository.cs: -------------------------------------------------------------------------------- 1 | using ErSoftDev.Framework.Configuration; 2 | using ErSoftDev.Framework.Mongo; 3 | using ErSoftDev.Identity.Infrastructure.NoSql.Models; 4 | 5 | namespace ErSoftDev.Identity.Infrastructure.NoSql.Repositories; 6 | 7 | public class InstrumentMongoRepository : MongoRepository, ITransientDependency, IInstrumentMongoRepository 8 | { 9 | public InstrumentMongoRepository(BaseMongoDbContext context) : base(context) 10 | { 11 | } 12 | } -------------------------------------------------------------------------------- /src/Identity/ErSoftDev.Identity.Infrastructure/Repositories/RoleRepository.cs: -------------------------------------------------------------------------------- 1 | using System.Linq.Expressions; 2 | using ErSoftDev.DomainSeedWork; 3 | using ErSoftDev.Framework.Configuration; 4 | using ErSoftDev.Identity.Domain.AggregatesModel.RoleAggregate; 5 | using Microsoft.EntityFrameworkCore; 6 | 7 | namespace ErSoftDev.Identity.Infrastructure.Repositories 8 | { 9 | public class RoleRepository : IRoleRepository, ITransientDependency 10 | { 11 | private readonly IdentityDbContext _identityDbContext; 12 | public IUnitOfWork UnitOfWork => _identityDbContext; 13 | 14 | public RoleRepository(IdentityDbContext identityDbContext) 15 | { 16 | _identityDbContext = identityDbContext; 17 | } 18 | 19 | public async Task Add(Role tObject, CancellationToken cancellationToken) 20 | { 21 | await _identityDbContext.Roles.AddAsync(tObject, cancellationToken); 22 | } 23 | 24 | public async Task Get(long id, CancellationToken cancellationToken) 25 | { 26 | return await _identityDbContext.Roles.FirstOrDefaultAsync(role => role.Id == id, cancellationToken); 27 | } 28 | 29 | public async Task Get(Expression> predicate, CancellationToken cancellationToken) 30 | { 31 | return await _identityDbContext.Roles.FirstOrDefaultAsync(predicate, cancellationToken); 32 | } 33 | 34 | public async Task?> GetList(Expression> predicate, CancellationToken cancellationToken) 35 | { 36 | return await _identityDbContext.Roles.Where(predicate).ToListAsync(cancellationToken); 37 | } 38 | 39 | public void Delete(Role tObject) 40 | { 41 | _identityDbContext.Remove(tObject); 42 | } 43 | } 44 | } 45 | --------------------------------------------------------------------------------