├── samples ├── WebNotifier │ ├── Env │ │ ├── config.dev.json │ │ └── config.prod.json │ ├── Pages │ │ ├── _ViewImports.cshtml │ │ ├── Index.cshtml │ │ ├── Counter.cshtml │ │ ├── Notification.cshtml │ │ └── FetchData.cshtml │ ├── .dockerignore │ ├── start.sh │ ├── build.sh │ ├── wwwroot │ │ ├── css │ │ │ └── open-iconic │ │ │ │ ├── font │ │ │ │ └── fonts │ │ │ │ │ ├── open-iconic.eot │ │ │ │ │ ├── open-iconic.otf │ │ │ │ │ ├── open-iconic.ttf │ │ │ │ │ └── open-iconic.woff │ │ │ │ └── ICON-LICENSE │ │ ├── index.html │ │ └── sample-data │ │ │ └── weather.json │ ├── _ViewImports.cshtml │ ├── App.cshtml │ ├── nginx.conf │ ├── k8s │ │ ├── webnotifier-svc.yaml │ │ └── webnotifier-dep.yaml │ ├── Shared │ │ ├── MainLayout.cshtml │ │ ├── SurveyPrompt.cshtml │ │ └── NavMenu.cshtml │ ├── build_image.sh │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Dockerfile │ ├── Startup.cs │ └── NetCoreKit.Samples.WebNotifier.csproj ├── TodoApi │ ├── App_Data │ │ └── readme.txt │ ├── .dockerignore │ ├── App_Build │ │ ├── start.sh │ │ ├── build.sh │ │ ├── k8s │ │ │ ├── todolist-secrets.yaml │ │ │ ├── todolist-svc.yaml │ │ │ ├── todolist-job.yaml │ │ │ └── todolist-dep.yaml │ │ ├── gen.sh │ │ └── build_image.sh │ ├── Domain │ │ ├── TaskDeleted.cs │ │ ├── TaskUpdated.cs │ │ ├── IUserGateway.cs │ │ ├── ProjectCreated.cs │ │ ├── TaskCreated.cs │ │ └── Project.cs │ ├── Dtos │ │ ├── ProjectDto.cs │ │ ├── TaskDto.cs │ │ └── AuthorDto.cs │ ├── v1 │ │ ├── UseCases │ │ │ ├── ClearTasks │ │ │ │ ├── Payloads.cs │ │ │ │ └── RequestHandler.cs │ │ │ ├── GetTasks │ │ │ │ ├── Payloads.cs │ │ │ │ └── RequestHandler.cs │ │ │ ├── DeleteTask │ │ │ │ ├── Payloads.cs │ │ │ │ └── RequestHandler.cs │ │ │ ├── UpdateTask │ │ │ │ ├── Payloads.cs │ │ │ │ └── RequestHandler.cs │ │ │ ├── CreateProject │ │ │ │ ├── Payloads.cs │ │ │ │ └── RequestHandler.cs │ │ │ └── AddTask │ │ │ │ ├── Payloads.cs │ │ │ │ └── RequestHandler.cs │ │ ├── PubSub │ │ │ ├── NotifEnvelopeSubscriber.cs │ │ │ ├── KafkaNotifPublisher.cs │ │ │ └── RedisNotifPublisher.cs │ │ └── Mappers │ │ │ └── ProjectProfile.cs │ ├── Infrastructure │ │ ├── Db │ │ │ ├── TodoListDbContext.cs │ │ │ └── TodoListDbModelBuilder.cs │ │ └── Gateways │ │ │ └── UserGateway.cs │ ├── Extensions │ │ ├── TaskExtensions.cs │ │ └── ProjectExtensions.cs │ ├── appsettings.Development.json │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.json │ └── NetCoreKit.Samples.TodoApi.csproj ├── BiMonetaryApi │ ├── .dockerignore │ ├── README.md │ ├── App_Build │ │ ├── k8s │ │ │ ├── bimonetary-svc.yaml │ │ │ └── bimonetary-dep.yaml │ │ ├── build_image.sh │ │ └── gen.sh │ ├── appsettings.Development.json │ ├── Program.cs │ ├── Dockerfile │ ├── Properties │ │ └── launchSettings.json │ ├── v1 │ │ └── Controllers │ │ │ └── PingController.cs │ ├── Startup.cs │ ├── appsettings.json │ └── NetCoreKit.Samples.BiMonetaryApi.csproj ├── ExchangeService │ ├── .dockerignore │ ├── hostsettings.json │ ├── README.md │ ├── App_Build │ │ ├── k8s │ │ │ ├── exchange-svc.yaml │ │ │ └── exchange-dep.yaml │ │ ├── build_image.sh │ │ └── gen.sh │ ├── appsettings.json │ ├── v1 │ │ └── Services │ │ │ ├── HealthImpl.cs │ │ │ └── ExchangeServiceImpl.cs │ └── Dockerfile ├── Notifier │ ├── hostsettings.json │ ├── appsettings.json │ └── App_Build │ │ └── gen.sh ├── SignalRNotifier │ ├── App_Build │ │ ├── start.sh │ │ ├── build.sh │ │ ├── k8s │ │ │ ├── signalrnotifier-secrets.yaml │ │ │ ├── signalrnotifier-svc.yaml │ │ │ └── signalrnotifier-dep.yaml │ │ ├── gen.sh │ │ └── build_image.sh │ ├── appsettings.Development.json │ ├── Services │ │ ├── Events │ │ │ ├── ProjectCreated.cs │ │ │ └── TaskCreated.cs │ │ ├── Mappers │ │ │ └── ProjectProfile.cs │ │ └── HostedService.cs │ ├── appsettings.json │ ├── Dockerfile │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ └── NetCoreKit.Samples.SignalRNotifier.csproj ├── _deploys │ ├── mongo │ │ ├── mongodb-svc.yaml │ │ └── mongodb-dep.yaml │ ├── scripts │ │ ├── apply-k8s.ps1 │ │ ├── delete-k8s.ps1 │ │ ├── build-images.sh │ │ └── build-server-images.sh │ ├── redis-commander │ │ ├── service.yaml │ │ └── deployment.yaml │ ├── kafka-topics-ui │ │ ├── readme.md │ │ └── kafka-topics-ui.yaml │ └── kafka │ │ ├── kafka-manager.yml │ │ └── kafka-server.yaml ├── _protos │ └── v1 │ │ ├── project.proto │ │ └── bimonetary.proto └── readme.md ├── global.json ├── .vs └── netcorekit │ ├── v15 │ └── .suo │ ├── v16 │ └── .suo │ └── DesignTimeBuild │ └── .dtbcache ├── artwork └── msa_architecture.png ├── src ├── NetCoreKit.Infrastructure.EfCore.Tests │ ├── appsettings.json │ └── NetCoreKit.Infrastructure.EfCore.Tests.csproj ├── NetCoreKit.Infrastructure.EfCore │ ├── Db │ │ ├── IDbConnStringFactory.cs │ │ ├── ICustomModelBuilder.cs │ │ └── IExtendDbContextOptionsBuilder.cs │ ├── Migration │ │ ├── ISeedData.cs │ │ └── SeedDataBase.cs │ ├── Extensions │ │ ├── DbContextExtensions.cs │ │ └── UnitOfWorkExtensions.cs │ ├── NetCoreKit.Infrastructure.EfCore.csproj │ └── ServiceCollectionExtensions.cs ├── NetCoreKit.Utils │ ├── Attributes │ │ └── AutoScanAwarenessAttribute.cs │ ├── Helpers │ │ ├── DateTimeHelper.cs │ │ ├── IdHelper.cs │ │ ├── CryptoRandomHelper.cs │ │ └── EnumHelper.cs │ ├── KeyValueResponse.cs │ ├── README.md │ ├── Extensions │ │ ├── TypeConversionExtensions.cs │ │ ├── DynamicExtensions.cs │ │ ├── ByteArrayExtensions.cs │ │ └── AssemblyExtensions.cs │ └── NetCoreKit.Utils.csproj ├── NetCoreKit.Infrastructure.Bus.Kafka │ ├── KafkaOptions.cs │ ├── ProtoSerializer.cs │ ├── ProtoDeserializer.cs │ ├── NetCoreKit.Infrastructure.Bus.Kafka.csproj │ └── ServiceCollectionExtensions.cs ├── NetCoreKit.Infrastructure │ ├── IExternalSystem.cs │ ├── Features │ │ ├── IFeature.cs │ │ ├── FeatureExtensions.cs │ │ └── Feature.cs │ ├── Mappers │ │ └── AutoMapperProfileExtension.cs │ ├── NetCoreKit.Infrastructure.csproj │ ├── OrderByExtensions.cs │ └── ConfigurationExtensions.cs ├── NetCoreKit.Infrastructure.Mongo │ ├── MongoSettings.cs │ ├── IMongoQueryRepository.cs │ ├── MongoContext.cs │ ├── QueryRepositoryFactory.cs │ ├── NetCoreKit.Infrastructure.Mongo.csproj │ └── UnitOfWorkAsync.cs ├── NetCoreKit.Infrastructure.AspNetCore │ ├── Validation │ │ ├── ValidationError.cs │ │ └── ValidationProblemDetails.cs │ ├── Authz │ │ ├── AuthNOptions.cs │ │ └── AuthAttribute.cs │ ├── ProxyService.cs │ ├── HATEOAS │ │ ├── LinkItem.cs │ │ └── CriterionExtensions.cs │ ├── ModelBase.cs │ ├── Rest │ │ ├── HttpResponseExtensions.cs │ │ ├── HttpRequestExtensions.cs │ │ └── ServiceCollectionExtensions.cs │ └── Middlewares │ │ ├── LogHandlerMiddleware.cs │ │ └── ErrorHandlerMiddleware.cs ├── NetCoreKit.Infrastructure.AspNetCore.OpenApi │ ├── SwaggerExcludeAttribute.cs │ ├── OpenApiOptions.cs │ ├── SwaggerExcludeSchemaFilter.cs │ ├── NetCoreKit.Infrastructure.AspNetCore.OpenApi.csproj │ ├── AuthorizeCheckOperationFilter.cs │ ├── SecurityRequirementsOperationFilter.cs │ └── DefaultValuesOperationFilter.cs ├── NetCoreKit.Infrastructure.GrpcHost │ └── CheckPolicyAttribute.cs ├── NetCoreKit.Infrastructure.EfCore.SqlServer │ ├── Options │ │ └── DbOptions.cs │ ├── NetCoreKit.Infrastructure.EfCore.SqlServer.csproj │ ├── DbContextOptionsBuilderFactory.cs │ ├── ServiceCollectionExtensions.cs │ └── DatabaseConnectionStringFactory.cs ├── NetCoreKit.Infrastructure.Bus │ ├── IDispatchedEventBus.cs │ ├── ServiceCollectionExtensions.cs │ ├── DomainEventBus.cs │ ├── Envelopes.cs │ └── NetCoreKit.Infrastructure.Bus.csproj ├── NetCoreKit.Infrastructure.AspNetCore.All │ └── Controllers │ │ ├── ErrorController.cs │ │ ├── HomeController.cs │ │ └── DbMigrationController.cs ├── NetCoreKit.Infrastructure.AspNetCore.CleanArch │ ├── ServiceCollectionExtensions.cs │ ├── PresenterExtensions.cs │ ├── IEventHandler.cs │ ├── RequestHandlerBase.cs │ ├── EventAggregatorExtensions.cs │ ├── TxRequestHandlerBase.cs │ ├── NetCoreKit.Infrastructure.AspNetCore.CleanArch.csproj │ └── UnitOfWorkBehavior.cs ├── NetCoreKit.Infrastructure.EfCore.MySql │ ├── DbOptions.cs │ ├── NetCoreKit.Infrastructure.EfCore.MySql.csproj │ ├── ServiceCollectionExtensions.cs │ ├── DbContextOptionsBuilderFactory.cs │ └── DatabaseConnectionStringFactory.cs ├── NetCoreKit.Domain │ ├── QueryRepository.cs │ ├── NetCoreKit.Domain.csproj │ ├── Exception.cs │ ├── UnitOfWork.cs │ ├── Entity.cs │ ├── Event.cs │ ├── ValueObject.cs │ ├── Identity.cs │ └── Dto.cs └── NetCoreKit.Infrastructure.Bus.Redis │ ├── ServiceCollectionExtensions.cs │ ├── RedisStore.cs │ └── NetCoreKit.Infrastructure.Bus.Redis.csproj ├── .dockerignore ├── .github └── FUNDING.yml ├── appveyor.yml ├── netcorekit.sln.DotSettings └── LICENSE /samples/WebNotifier/Env/config.dev.json: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Data/readme.txt: -------------------------------------------------------------------------------- 1 | Don't delete me! 2 | -------------------------------------------------------------------------------- /samples/WebNotifier/Pages/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @layout MainLayout 2 | -------------------------------------------------------------------------------- /samples/TodoApi/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !src 3 | !*.sln 4 | **/bin 5 | **/obj -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "2.2.100" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !src 3 | !*.sln 4 | **/bin 5 | **/obj -------------------------------------------------------------------------------- /samples/WebNotifier/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !src 3 | !*.sln 4 | **/bin 5 | **/obj -------------------------------------------------------------------------------- /samples/ExchangeService/.dockerignore: -------------------------------------------------------------------------------- 1 | * 2 | !src 3 | !*.sln 4 | **/bin 5 | **/obj -------------------------------------------------------------------------------- /samples/Notifier/hostsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "environment": "Development" 3 | } 4 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | dotnet run 5 | -------------------------------------------------------------------------------- /samples/ExchangeService/hostsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "environment": "Development" 3 | } 4 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | dotnet run 5 | -------------------------------------------------------------------------------- /samples/WebNotifier/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -x 4 | 5 | dotnet run 6 | -------------------------------------------------------------------------------- /samples/WebNotifier/Env/config.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "SignalRBaseUrl": "http://localhost:32502" 3 | } 4 | -------------------------------------------------------------------------------- /.vs/netcorekit/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/.vs/netcorekit/v15/.suo -------------------------------------------------------------------------------- /.vs/netcorekit/v16/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/.vs/netcorekit/v16/.suo -------------------------------------------------------------------------------- /artwork/msa_architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/artwork/msa_architecture.png -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | export ASPNETCORE_ENVIRONMENT Development 5 | dotnet build 6 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | export ASPNETCORE_ENVIRONMENT Development 5 | dotnet build 6 | -------------------------------------------------------------------------------- /samples/WebNotifier/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -e 3 | set -x 4 | 5 | export ASPNETCORE_ENVIRONMENT Development 6 | dotnet build 7 | -------------------------------------------------------------------------------- /.vs/netcorekit/DesignTimeBuild/.dtbcache: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/.vs/netcorekit/DesignTimeBuild/.dtbcache -------------------------------------------------------------------------------- /samples/WebNotifier/Pages/Index.cshtml: -------------------------------------------------------------------------------- 1 | @page "/hello" 2 | 3 |

Hello, world!

4 | 5 | Welcome to your new app. 6 | 7 | 8 | -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.eot -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.otf -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.ttf -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cloudnative-netcore/netcorekit/HEAD/samples/WebNotifier/wwwroot/css/open-iconic/font/fonts/open-iconic.woff -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.Tests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "QualifiedAssemblyPattern": "NetCoreKit.*", 3 | "EfCore": { 4 | "Cache": { 5 | "ExpiredTime": 60 // seconds 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Db/IDbConnStringFactory.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.EfCore.Db 2 | { 3 | public interface IDbConnStringFactory 4 | { 5 | string Create(); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /samples/TodoApi/Domain/TaskDeleted.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | using NetCoreKit.Domain; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Domain 5 | { 6 | public class TaskDeleted : EventBase 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/TodoApi/Domain/TaskUpdated.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | using NetCoreKit.Domain; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Domain 5 | { 6 | public class TaskUpdated : EventBase 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Attributes/AutoScanAwarenessAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Utils.Attributes 4 | { 5 | public sealed class AutoScanAwarenessAttribute : Attribute 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/Notifier/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Kafka": { 3 | "FQDN": "kafka-server:9092" 4 | }, 5 | "Logging": { 6 | "LogLevel": { 7 | "Default": "Warning" 8 | } 9 | }, 10 | "AllowedHosts": "*" 11 | } 12 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/k8s/signalrnotifier-secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: signalrnotifier-secrets 5 | namespace: netcorekit 6 | type: Opaque 7 | data: 8 | RedisPassword: bGV0bWVpbg== -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Kafka/KafkaOptions.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.Bus.Kafka 2 | { 3 | public class KafkaOptions 4 | { 5 | public string Fqdn { get; set; } = "127.0.0.1:9092"; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/README.md: -------------------------------------------------------------------------------- 1 | ### Generating gRPC 2 | 3 | ``` 4 | > cd App_Build 5 | > bash 6 | > ./gen.sh 7 | ``` 8 | 9 | _Notes_: 10 | - Install necessary libs at https://gist.github.com/thangchung/89c21402b8ffe047267a70d917d2a83e -------------------------------------------------------------------------------- /samples/ExchangeService/README.md: -------------------------------------------------------------------------------- 1 | ### Generating gRPC 2 | 3 | ``` 4 | > cd App_Build 5 | > bash 6 | > ./gen.sh 7 | ``` 8 | 9 | _Notes_: 10 | - Install necessary libs at https://gist.github.com/thangchung/89c21402b8ffe047267a70d917d2a83e -------------------------------------------------------------------------------- /samples/WebNotifier/_ViewImports.cshtml: -------------------------------------------------------------------------------- 1 | @using System.Net.Http 2 | @using Microsoft.AspNetCore.Blazor.Layouts 3 | @using Microsoft.AspNetCore.Blazor.Routing 4 | @using Microsoft.JSInterop 5 | @using WebNotifier 6 | @using WebNotifier.Shared 7 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/IExternalSystem.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | 3 | namespace NetCoreKit.Infrastructure 4 | { 5 | public interface IExternalSystem 6 | { 7 | Task Connect(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/k8s/todolist-secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: todolist-secrets 5 | namespace: netcorekit 6 | type: Opaque 7 | data: 8 | MySqlDbPassword: UEBzc3cwcmQ= 9 | RedisPassword: bGV0bWVpbg== -------------------------------------------------------------------------------- /samples/WebNotifier/App.cshtml: -------------------------------------------------------------------------------- 1 | 5 | 6 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Features": { 3 | "Redis": { 4 | "FQDN": "127.0.0.1:30904", 5 | "Password": "letmein" 6 | }, 7 | "Kafka": { 8 | "FQDN": "127.0.0.1:9092" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Mongo/MongoSettings.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.Mongo 2 | { 3 | public class MongoSettings 4 | { 5 | public string ConnString { get; set; } 6 | public string Database { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /samples/_deploys/mongo/mongodb-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: mongodb 5 | namespace: netcorekit 6 | labels: 7 | app: mongodb 8 | spec: 9 | ports: 10 | - port: 27017 11 | name: mongo 12 | selector: 13 | app: mongodb -------------------------------------------------------------------------------- /samples/TodoApi/Domain/IUserGateway.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using NetCoreKit.Samples.TodoAPI.Dtos; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Domain 5 | { 6 | public interface IUserGateway 7 | { 8 | Task GetAuthorAsync(); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Validation/ValidationError.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.AspNetCore.Validation 2 | { 3 | public class ValidationError 4 | { 5 | public string Name { get; set; } 6 | public string Description { get; set; } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Db/ICustomModelBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace NetCoreKit.Infrastructure.EfCore.Db 4 | { 5 | public interface ICustomModelBuilder 6 | { 7 | void Build(ModelBuilder modelBuilder); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/SwaggerExcludeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Infrastructure.AspNetCore.OpenApi 4 | { 5 | [AttributeUsage(AttributeTargets.Property)] 6 | public class SwaggerExcludeAttribute : Attribute 7 | { 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /samples/_deploys/scripts/apply-k8s.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "Apply for TODO API..." 2 | kubectl apply -f samples/TodoApi/App_Build/k8s/ 3 | 4 | Write-Host "Apply for SignalR..." 5 | kubectl apply -f samples/SignalRNotifier/k8s/ 6 | 7 | Write-Host "Apply for Web Notifier..." 8 | kubectl apply -f samples/WebNotifier/k8s/ 9 | -------------------------------------------------------------------------------- /samples/WebNotifier/nginx.conf: -------------------------------------------------------------------------------- 1 | events { } 2 | http { 3 | include /etc/nginx/mime.types; 4 | 5 | server { 6 | listen 80; 7 | 8 | location / { 9 | root /usr/share/nginx/html; 10 | try_files $uri $uri/ /Index.html =404; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/_deploys/scripts/delete-k8s.ps1: -------------------------------------------------------------------------------- 1 | Write-Host "Delete from TODO API..." 2 | kubectl delete -f samples/TodoApi/App_Build/k8s/ 3 | 4 | Write-Host "Delete from SignalR..." 5 | kubectl delete -f samples/SignalRNotifier/k8s/ 6 | 7 | Write-Host "Delete from Web Notifier..." 8 | kubectl delete -f samples/WebNotifier/k8s/ 9 | -------------------------------------------------------------------------------- /samples/_deploys/scripts/build-images.sh: -------------------------------------------------------------------------------- 1 | chmod +x ./samples/TodoApi/App_Build/build_image.sh 2 | ./samples/TodoApi/build_image.sh 3 | 4 | chmod +x ./samples/SignalRNotifier/build_image.sh 5 | ./samples/SignalRNotifier/build_image.sh 6 | 7 | chmod +x ./samples/WebNotifier/build_image.sh 8 | ./samples/WebNotifier/build_image.sh 9 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Helpers/DateTimeHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Utils.Helpers 4 | { 5 | public static class DateTimeHelper 6 | { 7 | public static DateTime GenerateDateTime() 8 | { 9 | return DateTimeOffset.Now.UtcDateTime; 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/ExchangeService/App_Build/k8s/exchange-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: exchange 5 | namespace: netcorekit 6 | labels: 7 | app: exchange 8 | spec: 9 | ports: 10 | - name: grpc 11 | port: 5000 12 | targetPort: 5000 13 | type: ClusterIP 14 | selector: 15 | app: exchange 16 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Mongo/IMongoQueryRepository.cs: -------------------------------------------------------------------------------- 1 | using NetCoreKit.Domain; 2 | 3 | namespace NetCoreKit.Infrastructure.Mongo 4 | { 5 | public interface IMongoQueryRepository : IQueryRepository 6 | where TEntity : IAggregateRoot 7 | { 8 | DbContext DbContext { get; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Helpers/IdHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Utils.Helpers 4 | { 5 | public static class IdHelper 6 | { 7 | public static Guid GenerateId(string guid = "") 8 | { 9 | return string.IsNullOrEmpty(guid) ? Guid.NewGuid() : new Guid(guid); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/Notifier/App_Build/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PROJ_DIR=`pwd` 4 | GRPC_PATH=${HOME}/.nuget/packages/grpc.tools/1.17.1/tools/linux_x64 5 | PROTO_PATH=${PROJ_DIR}/../../_protos/v1 6 | OUTPUT_PATH=${PROJ_DIR}/../Rpc 7 | 8 | $GRPC_PATH/protoc -I $PROTO_PATH -I /usr/local/include \ 9 | --csharp_out $OUTPUT_PATH $PROTO_PATH/project.proto 10 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | PROJ_DIR=`pwd` 4 | GRPC_PATH=${HOME}/.nuget/packages/grpc.tools/1.17.1/tools/linux_x64 5 | PROTO_PATH=${PROJ_DIR}/../../_protos/v1 6 | OUTPUT_PATH=${PROJ_DIR}/../Rpc 7 | 8 | $GRPC_PATH/protoc -I $PROTO_PATH -I /usr/local/include \ 9 | --csharp_out $OUTPUT_PATH $PROTO_PATH/project.proto 10 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/Features/IFeature.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.Features 2 | { 3 | /// 4 | /// Reference at https://github.com/anuraj/AspNetCoreSamples/tree/master/FeatureToggle 5 | /// 6 | public interface IFeature 7 | { 8 | bool IsEnabled(string feature); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | PROJ_DIR=`pwd` 5 | GRPC_PATH=${HOME}/.nuget/packages/grpc.tools/1.17.1/tools/linux_x64 6 | PROTO_PATH=${PROJ_DIR}/../../_protos/v1 7 | OUTPUT_PATH=${PROJ_DIR}/../v1/Grpc 8 | 9 | $GRPC_PATH/protoc -I $PROTO_PATH -I /usr/local/include \ 10 | --csharp_out $OUTPUT_PATH $PROTO_PATH/project.proto 11 | -------------------------------------------------------------------------------- /samples/WebNotifier/Pages/Counter.cshtml: -------------------------------------------------------------------------------- 1 | @page "/counter" 2 | 3 |

Counter

4 | 5 |

Current count: @currentCount

6 | 7 | 8 | 9 | @functions { 10 | int currentCount = 0; 11 | 12 | void IncrementCount() 13 | { 14 | currentCount++; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/TodoApi/Dtos/ProjectDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Dtos 5 | { 6 | public class ProjectDto 7 | { 8 | public Guid Id { get; set; } 9 | public string Name { get; set; } 10 | public List Tasks { get; set; } = new List(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/WebNotifier/k8s/webnotifier-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: webnotifier 5 | namespace: netcorekit 6 | labels: 7 | app: webnotifier 8 | spec: 9 | ports: 10 | - port: 80 11 | targetPort: 80 12 | nodePort: 32503 13 | protocol: TCP 14 | name: http 15 | type: NodePort 16 | selector: 17 | app: webnotifier -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/KeyValueResponse.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Utils 2 | { 3 | public class KeyValueObject 4 | { 5 | public KeyValueObject(TKey key, string value) 6 | { 7 | Key = key; 8 | Value = value; 9 | } 10 | 11 | public TKey Key { get; } 12 | public string Value { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | TAG=${TAG:=$(git rev-parse --short HEAD)} 5 | NAMESPACE=${NAMESPACE:="vndg"} 6 | 7 | echo "namespace: ${NAMESPACE} and tag: ${TAG}" 8 | echo "start to build TodoApi..." 9 | 10 | docker build -f samples/TodoApi/Dockerfile \ 11 | -t $NAMESPACE/todo-api:$TAG \ 12 | -t $NAMESPACE/todo-api:latest . 13 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.GrpcHost/CheckPolicyAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Infrastructure.GrpcHost 4 | { 5 | public class CheckPolicyAttribute : Attribute 6 | { 7 | public CheckPolicyAttribute(string name) 8 | { 9 | Name = name; 10 | } 11 | 12 | public string Name { get; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/k8s/todolist-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: todolist 5 | namespace: netcorekit 6 | labels: 7 | app: todolist 8 | spec: 9 | ports: 10 | - port: 32501 11 | targetPort: 80 12 | nodePort: 32501 13 | protocol: TCP 14 | name: http 15 | type: LoadBalancer 16 | selector: 17 | app: todolist 18 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Services/Events/ProjectCreated.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MediatR; 3 | 4 | namespace NetCoreKit.Samples.SignalRNotifier.Services.Events 5 | { 6 | public class ProjectCreated : INotification 7 | { 8 | public Guid Id { get; set; } 9 | public string Name { get; set; } 10 | public DateTime OccurredOn { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/TodoApi/Dtos/TaskDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Samples.TodoAPI.Dtos 4 | { 5 | public class TaskDto 6 | { 7 | public Guid Id { get; set; } 8 | public string Title { get; set; } 9 | public int Order { get; set; } 10 | public bool Completed { get; set; } 11 | public string AuthorName { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/WebNotifier/Shared/MainLayout.cshtml: -------------------------------------------------------------------------------- 1 | @inherits BlazorLayoutComponent 2 | 3 | 6 | 7 |
8 |
9 | About 10 |
11 | 12 |
13 | @Body 14 |
15 |
16 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Validation/ValidationProblemDetails.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace NetCoreKit.Infrastructure.AspNetCore.Validation 5 | { 6 | public class ValidationProblemDetails : ProblemDetails 7 | { 8 | public ICollection ValidationErrors { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /samples/WebNotifier/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | TAG=${TAG:=$(git rev-parse --short HEAD)} 5 | NAMESPACE=${NAMESPACE:="vndg"} 6 | 7 | echo "namespace: ${NAMESPACE} and tag: ${TAG}" 8 | echo "start to build WebNotifier..." 9 | 10 | docker build -f samples/WebNotifier/Dockerfile \ 11 | -t vndg/webnotifier:$(git rev-parse --short HEAD) \ 12 | -t vndg/webnotifier:latest . 13 | -------------------------------------------------------------------------------- /samples/_deploys/redis-commander/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: redis-commander 5 | namespace: redis 6 | labels: 7 | app: redis-commander 8 | spec: 9 | ports: 10 | - port: 8081 11 | targetPort: 8081 12 | protocol: TCP 13 | nodePort: 30010 14 | name: redis-commander 15 | type: NodePort 16 | selector: 17 | app: redis-commander -------------------------------------------------------------------------------- /samples/BiMonetaryApi/App_Build/k8s/bimonetary-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: bimonetary-api 5 | namespace: netcorekit 6 | labels: 7 | app: bimonetary-api 8 | spec: 9 | ports: 10 | - port: 32503 11 | targetPort: 80 12 | nodePort: 32503 13 | protocol: TCP 14 | name: http 15 | type: LoadBalancer 16 | selector: 17 | app: bimonetary-api 18 | -------------------------------------------------------------------------------- /samples/ExchangeService/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_VERSION": "1.0", 3 | "SERVICE_VERSION": "0.0.1", 4 | "QualifiedAssemblyPattern": "NetCoreKit.Samples.*", 5 | "Hosts": { 6 | "Local": { 7 | "Host": "localhost", 8 | "Port": "5000" 9 | } 10 | }, 11 | "Logging": { 12 | "LogLevel": { 13 | "Default": "Warning" 14 | } 15 | }, 16 | "AllowedHosts": "*" 17 | } 18 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Hosts": { 3 | "Externals": { 4 | "CurrentUri": "http://localhost:5002", 5 | "Auth": { 6 | "Uri": "http://localhost:5001" 7 | } 8 | } 9 | }, 10 | "Logging": { 11 | "LogLevel": { 12 | "Default": "Debug", 13 | "System": "Information", 14 | "Microsoft": "Information" 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/k8s/signalrnotifier-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: signalrnotifier 5 | namespace: netcorekit 6 | labels: 7 | app: signalrnotifier 8 | spec: 9 | ports: 10 | - port: 32502 11 | targetPort: 80 12 | nodePort: 32502 13 | protocol: TCP 14 | name: http 15 | type: LoadBalancer 16 | selector: 17 | app: signalrnotifier 18 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Authz/AuthNOptions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NetCoreKit.Infrastructure.AspNetCore.Authz 4 | { 5 | public class AuthNOptions 6 | { 7 | public Dictionary ClaimToScopeMap { get; set; } 8 | public Dictionary Scopes { get; set; } 9 | public string Audience { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/App_Build/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | readonly TAG=${TAG:=$(git rev-parse --short HEAD)} 5 | readonly NAMESPACE=${NAMESPACE:="vndg"} 6 | 7 | echo "namespace: ${NAMESPACE} and tag: ${TAG}" 8 | echo "start to build BiMonetaryApi..." 9 | 10 | docker build -f samples/BiMonetaryApi/Dockerfile \ 11 | -t $NAMESPACE/bimonetary-api:$TAG \ 12 | -t $NAMESPACE/bimonetary-api:latest . 13 | -------------------------------------------------------------------------------- /samples/_deploys/scripts/build-server-images.sh: -------------------------------------------------------------------------------- 1 | TAG=${TAG:=$(git rev-parse --short HEAD)} 2 | NAMESPACE=${NAMESPACE:="vndg"} 3 | echo "${NAMESPACE} and ${TAG}" 4 | 5 | echo "Build TODO API..." 6 | docker build -f samples/TodoApi/Dockerfile -t vndg/todoapi:$TAG -t vndg/todoapi:latest . 7 | 8 | echo "Build SignalR..." 9 | docker build -f samples/SignalRNotifier/Dockerfile -t vndg/signalrnotifier:$TAG -t vndg/signalrnotifier:latest . -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/ProxyService.cs: -------------------------------------------------------------------------------- 1 | using NetCoreKit.Infrastructure.AspNetCore.Rest; 2 | 3 | namespace NetCoreKit.Infrastructure.AspNetCore 4 | { 5 | public abstract class ProxyServiceBase 6 | { 7 | protected readonly RestClient RestClient; 8 | 9 | protected ProxyServiceBase(RestClient rest) 10 | { 11 | RestClient = rest; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Db/IExtendDbContextOptionsBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace NetCoreKit.Infrastructure.EfCore.Db 4 | { 5 | public interface IExtendDbContextOptionsBuilder 6 | { 7 | DbContextOptionsBuilder Extend(DbContextOptionsBuilder optionsBuilder, 8 | IDbConnStringFactory connectionStringFactory, string assemblyName); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/Features/FeatureExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace NetCoreKit.Infrastructure.Features 4 | { 5 | public static class FeatureExtensions 6 | { 7 | public static void AddFeatureToggle(this IServiceCollection services) 8 | { 9 | services.AddSingleton(typeof(IFeature), typeof(Feature)); 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /samples/ExchangeService/App_Build/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | readonly TAG=${TAG:=$(git rev-parse --short HEAD)} 5 | readonly NAMESPACE=${NAMESPACE:="vndg"} 6 | 7 | echo "namespace: ${NAMESPACE} and tag: ${TAG}" 8 | echo "start to build ExchangeService..." 9 | 10 | docker build -f samples/ExchangeService/Dockerfile \ 11 | -t $NAMESPACE/exchange-service:$TAG \ 12 | -t $NAMESPACE/exchange-service:latest . 13 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/build_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | set -ex 3 | 4 | TAG=${TAG:=$(git rev-parse --short HEAD)} 5 | NAMESPACE=${NAMESPACE:="vndg"} 6 | 7 | echo "namespace: ${NAMESPACE} and tag: ${TAG}" 8 | echo "start to build SignalRNotifier..." 9 | 10 | 11 | docker build -f samples/SignalRNotifier/Dockerfile \ 12 | -t vndg/signalrnotifier:$(git rev-parse --short HEAD) \ 13 | -t vndg/signalrnotifier:latest . 14 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Services/Events/TaskCreated.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MediatR; 3 | 4 | namespace NetCoreKit.Samples.SignalRNotifier.Services.Events 5 | { 6 | public class TaskCreated : INotification 7 | { 8 | public Guid Id { get; set; } 9 | public string Title { get; set; } 10 | public Guid ProjectId { get; set; } 11 | public DateTime OccurredOn { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /samples/TodoApi/Dtos/AuthorDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Samples.TodoAPI.Dtos 4 | { 5 | public class AuthorDto 6 | { 7 | public Guid Id { get; set; } 8 | public string FirstName { get; set; } 9 | public string LastName { get; set; } 10 | 11 | public string GetFullName() 12 | { 13 | return $"{FirstName} {LastName}"; 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.SqlServer/Options/DbOptions.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.EfCore.SqlServer.Options 2 | { 3 | public class DbOptions 4 | { 5 | public string Host { get; set; } 6 | public string Port { get; set; } 7 | public string Database { get; set; } 8 | public string UserName { get; set; } 9 | public string Password { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /.dockerignore: -------------------------------------------------------------------------------- 1 | .dockerignore 2 | .env 3 | .git 4 | .gitignore 5 | .vs 6 | .vscode 7 | docker-compose*.yml 8 | docker-compose.dcproj 9 | *.sln 10 | *.md 11 | LICENSE 12 | *.testsettings 13 | vsts-docs 14 | test 15 | README 16 | **/bin/ 17 | **/obj/ 18 | **/node_modules/ 19 | **/bower_components/ 20 | **/appsettings.localhost.json 21 | **/build/ 22 | !**/web/build/ 23 | **/dist/ 24 | deployment 25 | assets 26 | docs 27 | **/*.csproj.user 28 | -------------------------------------------------------------------------------- /samples/TodoApi/Domain/ProjectCreated.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NetCoreKit.Domain; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Domain 5 | { 6 | public class ProjectCreated : EventBase 7 | { 8 | public ProjectCreated(Guid id, string name) 9 | { 10 | Id = id; 11 | Name = name; 12 | } 13 | 14 | public Guid Id { get; } 15 | public string Name { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/WebNotifier/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Blazor.Hosting; 2 | 3 | namespace WebNotifier 4 | { 5 | public class Program 6 | { 7 | public static void Main(string[] args) 8 | { 9 | CreateHostBuilder(args).Build().Run(); 10 | } 11 | 12 | public static IWebAssemblyHostBuilder CreateHostBuilder(string[] args) => 13 | BlazorWebAssemblyHost.CreateDefaultBuilder() 14 | .UseBlazorStartup(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus/IDispatchedEventBus.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Google.Protobuf; 3 | 4 | namespace NetCoreKit.Infrastructure.Bus 5 | { 6 | public interface IDispatchedEventBus 7 | { 8 | Task PublishAsync(TMessage msg, params string[] channels) where TMessage : IMessage; 9 | Task SubscribeAsync(params string[] channels) where TMessage : IMessage, new(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/ClearTasks/Payloads.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MediatR; 3 | using NetCoreKit.Infrastructure.AspNetCore.OpenApi; 4 | 5 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.ClearTasks 6 | { 7 | public class ClearTasksRequest : IRequest 8 | { 9 | [SwaggerExclude] public Guid ProjectId { get; set; } 10 | } 11 | 12 | public class ClearTasksResponse 13 | { 14 | public bool Result { get; set; } = true; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.All/Controllers/ErrorController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace NetCoreKit.Infrastructure.AspNetCore.All.Controllers 4 | { 5 | [Route("")] 6 | [ApiVersionNeutral] 7 | [ApiExplorerSettings(IgnoreApi = true)] 8 | public class ErrorController : Controller 9 | { 10 | [HttpGet("/error")] 11 | public IActionResult Index() 12 | { 13 | return new BadRequestResult(); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Authz/AuthAttribute.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Authentication.JwtBearer; 2 | using Microsoft.AspNetCore.Authorization; 3 | 4 | namespace NetCoreKit.Infrastructure.AspNetCore.Authz 5 | { 6 | public class AuthAttribute : AuthorizeAttribute 7 | { 8 | public AuthAttribute(string policy = null) 9 | { 10 | AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme; 11 | Policy = policy; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/HATEOAS/LinkItem.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.AspNetCore.HATEOAS 2 | { 3 | public class LinkItem 4 | { 5 | public LinkItem(string href, string rel, string method) 6 | { 7 | Href = href; 8 | Rel = rel; 9 | Method = method; 10 | } 11 | 12 | public string Href { get; set; } 13 | public string Rel { get; set; } 14 | public string Method { get; set; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Migration/ISeedData.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.EntityFrameworkCore; 3 | 4 | namespace NetCoreKit.Infrastructure.EfCore.Migration 5 | { 6 | public interface ISeedData 7 | where TDbContext : DbContext 8 | { 9 | Task SeedAsync(TDbContext context); 10 | } 11 | 12 | public interface IAuthConfigSeedData : ISeedData 13 | where TDbContext : DbContext 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "QualifiedAssemblyPattern": "NetCoreKit.Samples.*", 3 | "Hosts": { 4 | "BasePath": "/" 5 | }, 6 | "Logging": { 7 | "IncludeScopes": false, 8 | "Debug": { 9 | "LogLevel": { 10 | "Default": "Warning" 11 | } 12 | }, 13 | "Console": { 14 | "LogLevel": { 15 | "Default": "Debug", 16 | "System": "Information", 17 | "Microsoft": "Information" 18 | } 19 | } 20 | }, 21 | "AllowedHosts": "*" 22 | } 23 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/GetTasks/Payloads.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MediatR; 3 | using NetCoreKit.Infrastructure.AspNetCore.OpenApi; 4 | using NetCoreKit.Samples.TodoAPI.Dtos; 5 | 6 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.GetTasks 7 | { 8 | public class GetTasksRequest : IRequest 9 | { 10 | [SwaggerExclude] public Guid ProjectId { get; set; } 11 | } 12 | 13 | public class GetTasksResponse 14 | { 15 | public ProjectDto Result { get; set; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Samples.WebNotifier 7 | 8 | 9 | 10 | 11 | 12 | Loading... 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /samples/TodoApi/Domain/TaskCreated.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using NetCoreKit.Domain; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Domain 5 | { 6 | public class TaskCreated : EventBase 7 | { 8 | public TaskCreated(Guid id, string title, Guid projectId) 9 | { 10 | Id = id; 11 | Title = title; 12 | ProjectId = projectId; 13 | } 14 | 15 | public Guid Id { get; } 16 | public string Title { get; } 17 | public Guid ProjectId { get; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/DeleteTask/Payloads.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MediatR; 3 | using NetCoreKit.Infrastructure.AspNetCore.OpenApi; 4 | 5 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.DeleteTask 6 | { 7 | public class DeleteTaskRequest : IRequest 8 | { 9 | [SwaggerExclude] public Guid ProjectId { get; set; } 10 | 11 | public Guid TaskId { get; set; } 12 | } 13 | 14 | public class DeleteTaskResponse 15 | { 16 | public Guid Result { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static IServiceCollection AddCleanArch(this IServiceCollection services) 9 | { 10 | services.AddScoped(typeof(IPipelineBehavior<,>), typeof(UnitOfWorkBehavior<,>)); 11 | return services; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/Features/Feature.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | 3 | namespace NetCoreKit.Infrastructure.Features 4 | { 5 | public class Feature : IFeature 6 | { 7 | private readonly IConfiguration _config; 8 | 9 | public Feature(IConfiguration config) 10 | { 11 | _config = config; 12 | } 13 | 14 | public bool IsEnabled(string feature) 15 | { 16 | return _config.GetSection($"Features:{feature}").Exists(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/_protos/v1/project.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package TodoApi; 4 | 5 | option csharp_namespace = "NetCoreKit.Samples.Contracts.TodoApi.v1.Grpc"; 6 | 7 | import "google/protobuf/timestamp.proto"; 8 | 9 | message ProjectCreatedMsg { 10 | string Key = 1; 11 | string Id = 2; 12 | string Name = 3; 13 | google.protobuf.Timestamp OccurredOn = 4; 14 | } 15 | 16 | message TaskCreatedMsg { 17 | string Key = 1; 18 | string Id = 2; 19 | string Title = 3; 20 | string ProjectId = 4; 21 | google.protobuf.Timestamp OccurredOn = 5; 22 | } 23 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/README.md: -------------------------------------------------------------------------------- 1 | # NetCoreKit.Utils module 2 | 3 | This utils library contains ultility functions and helpers (e.g. string, bytes, hash, modular) that need for the web development. 4 | 5 | # List of utility helper and function 6 | 7 | - Extension functions 8 | - StringExtensions 9 | - AssemblyExtensions 10 | - ByteArrayExtensions 11 | - HashExtensions 12 | - MyModularLookupExtensions 13 | 14 | - Helpers 15 | - CryptoRandomHelper 16 | - DateTimeHelper 17 | - EnumHelper 18 | - IdHelper 19 | - TotpHelper 20 | 21 | - Guard 22 | 23 | -------------------------------------------------------------------------------- /samples/_deploys/kafka-topics-ui/readme.md: -------------------------------------------------------------------------------- 1 | ### Setup Kafka & its ecosystem 2 | 3 | ```bash 4 | > git clone https://github.com/confluentinc/cp-helm-charts.git 5 | > kubectl create ns kafka 6 | > helm install . --name kafka --namespace kafka 7 | > # helm install cp-helm-charts --name kafka --namespace kafka 8 | ``` 9 | 10 | ### Setup kafka-topics-ui 11 | 12 | ```bash 13 | > kubectl create -f kafka-topics-ui.yaml 14 | ``` 15 | 16 | ### Dashbard 17 | 18 | ```bash 19 | > http://localhost:8000 20 | ``` 21 | 22 | Notes: https://github.com/Landoop/kafka-topics-ui/issues/91 -------------------------------------------------------------------------------- /samples/TodoApi/Infrastructure/Db/TodoListDbContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.Extensions.Configuration; 3 | using NetCoreKit.Domain; 4 | using NetCoreKit.Infrastructure.EfCore.Db; 5 | 6 | namespace NetCoreKit.Samples.TodoAPI.Infrastructure.Db 7 | { 8 | public class TodoListDbContext : AppDbContext 9 | { 10 | public TodoListDbContext(DbContextOptions options, IConfiguration config, IDomainEventDispatcher eventBus) 11 | : base(options, config, eventBus) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /samples/WebNotifier/Shared/SurveyPrompt.cshtml: -------------------------------------------------------------------------------- 1 | 11 | 12 | @functions { 13 | [Parameter] 14 | string Title { get; set; } // Demonstrates how a parent component can supply parameters 15 | } 16 | -------------------------------------------------------------------------------- /samples/WebNotifier/Pages/Notification.cshtml: -------------------------------------------------------------------------------- 1 | @using Blazor.Extensions 2 | @page "/" 3 | @inherits WebNotifier.Pages.NotificationComponent 4 |

Notification:

5 | @if (Messages.Count <= 0) 6 | { 7 |

N/A

8 | } 9 |
    10 | @foreach (var m in Messages) 11 | { 12 |
  • @m
  • 13 | } 14 |
15 | 16 |

Projects:

17 | @if (Projects.Count <= 0) 18 | { 19 |

N/A

20 | } 21 | @foreach (var p in Projects) 22 | { 23 |
@p.Name #@p.Id
24 |
    25 | @foreach (var t in p.Tasks) 26 | { 27 |
  • @t.Title #@t.Id
  • 28 | } 29 |
30 | } 31 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/PubSub/NotifEnvelopeSubscriber.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using MediatR; 3 | using NetCoreKit.Infrastructure.Bus; 4 | using Task = System.Threading.Tasks.Task; 5 | 6 | namespace NetCoreKit.Samples.TodoApi.v1.PubSub 7 | { 8 | public class NotifEnvelopeSubscriber : INotificationHandler 9 | { 10 | public async Task Handle(NotificationEnvelope notif, CancellationToken cancellationToken) 11 | { 12 | // do something with @event 13 | //... 14 | 15 | await Task.FromResult(notif); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.DependencyInjection.Extensions; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus 6 | { 7 | public static class ServiceCollectionExtensions 8 | { 9 | public static IServiceCollection AddDomainEventBus(this IServiceCollection services) 10 | { 11 | services.Replace(ServiceDescriptor.Singleton()); 12 | return services; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/App_Build/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | readonly ROOT_DIR=`pwd` 5 | readonly SERVICE_DIR=${ROOT_DIR}/samples/BiMonetaryApi 6 | 7 | readonly GRPC_PATH=${HOME}/.nuget/packages/grpc.tools/1.17.1/tools/linux_x64 8 | readonly PROTO_PATH=${ROOT_DIR}/samples/_protos/v1 9 | readonly OUTPUT_PATH=${SERVICE_DIR}/v1/Grpc 10 | readonly PROTO_FILE=bimonetary.proto 11 | 12 | $GRPC_PATH/protoc -I $PROTO_PATH -I /usr/local/include \ 13 | --csharp_out $OUTPUT_PATH \ 14 | --grpc_out $OUTPUT_PATH $PROTO_PATH/bimonetary.proto \ 15 | --plugin=protoc-gen-grpc=${GRPC_PATH}/grpc_csharp_plugin 16 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.MySql/DbOptions.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.EfCore.MySql 2 | { 3 | public class DbOptions 4 | { 5 | public string Host { get; set; } 6 | public string Port { get; set; } 7 | public string Database { get; set; } 8 | public string UserName { get; set; } 9 | public string Password { get; set; } 10 | public string DbInfo { get; set; } = "5.7.14-mysql"; 11 | public string ConnString { get; set; } = "server={0};port={1};uid={2};pwd={3};database={4}"; 12 | public string FQDN { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/PresenterExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 5 | { 6 | public static class PresenterExtensions 7 | { 8 | public static IActionResult PresentFor(this TInput input, Func mapTo = null) 9 | where TInput : class 10 | { 11 | if (input == null) return new NoContentResult(); 12 | 13 | return mapTo == null ? new OkObjectResult(input) : new OkObjectResult(mapTo(input)); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.2.0-aspnetcore-runtime-alpine AS base 2 | WORKDIR /app 3 | 4 | ENV ASPNETCORE_URLS http://+:80 5 | EXPOSE 80 6 | 7 | FROM microsoft/dotnet:2.2.100-sdk-alpine AS build 8 | WORKDIR . 9 | COPY . . 10 | 11 | WORKDIR /samples/SignalRNotifier 12 | 13 | RUN dotnet restore -nowarn:msb3202,nu1503 14 | RUN dotnet build --no-restore -c Release -o /app 15 | 16 | FROM build AS publish 17 | RUN dotnet publish --no-restore -c Release -o /app 18 | 19 | FROM base AS final 20 | WORKDIR /app 21 | COPY --from=publish /app . 22 | ENTRYPOINT ["dotnet", "NetCoreKit.Samples.SignalRNotifier.dll"] 23 | -------------------------------------------------------------------------------- /samples/TodoApi/Extensions/TaskExtensions.cs: -------------------------------------------------------------------------------- 1 | using NetCoreKit.Samples.TodoAPI.Domain; 2 | using NetCoreKit.Samples.TodoAPI.Dtos; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Extensions 5 | { 6 | public static class TaskExtensions 7 | { 8 | public static TaskDto ToDto(this Task task) 9 | { 10 | return new TaskDto 11 | { 12 | Id = task.Id, 13 | Title = task.Title, 14 | Completed = task.Completed ?? false, 15 | Order = task.Order ?? 1, 16 | AuthorName = task.AuthorName 17 | }; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/IEventHandler.cs: -------------------------------------------------------------------------------- 1 | using MediatR; 2 | using NetCoreKit.Domain; 3 | 4 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 5 | { 6 | public interface IEventHandler : IRequestHandler 7 | where TRequest : IRequest 8 | { 9 | IQueryRepositoryFactory QueryFactory { get; } 10 | } 11 | 12 | public interface ITxEventHandler : IEventHandler 13 | where TRequest : IRequest 14 | { 15 | IUnitOfWorkAsync CommandFactory { get; } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Extensions/TypeConversionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel; 3 | 4 | namespace NetCoreKit.Utils.Extensions 5 | { 6 | public static class TypeConversionExtensions 7 | { 8 | public static T ConvertTo(this string input) 9 | { 10 | try 11 | { 12 | var converter = TypeDescriptor.GetConverter(typeof(T)); 13 | return (T)converter.ConvertFromString(input); 14 | } 15 | catch (NotSupportedException) 16 | { 17 | return default(T); 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/_deploys/redis-commander/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: redis-commander-v1 5 | namespace: redis 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: redis-commander 12 | version: v1 13 | spec: 14 | containers: 15 | - name: redis-commander 16 | image: rediscommander/redis-commander 17 | imagePullPolicy: IfNotPresent 18 | env: 19 | - name: REDIS_HOSTS 20 | value: k8s:redis-master:6379:0:letmein 21 | ports: 22 | - name: redis-commander 23 | containerPort: 8081 -------------------------------------------------------------------------------- /samples/ExchangeService/App_Build/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -ex 3 | 4 | readonly ROOT_DIR=`pwd` 5 | readonly SERVICE_DIR=${ROOT_DIR}/samples/ExchangeService 6 | 7 | readonly GRPC_PATH=${HOME}/.nuget/packages/grpc.tools/1.17.1/tools/linux_x64 8 | readonly PROTO_PATH=${ROOT_DIR}/samples/_protos/v1 9 | readonly OUTPUT_PATH=${SERVICE_DIR}/v1/Grpc 10 | readonly PROTO_FILE=bimonetary.proto 11 | 12 | cd `$SERVICE_DIR/App_Build` 13 | 14 | $GRPC_PATH/protoc -I $PROTO_PATH -I /usr/local/include \ 15 | --csharp_out $OUTPUT_PATH \ 16 | --grpc_out $OUTPUT_PATH $PROTO_PATH/$PROTO_FILE \ 17 | --plugin=protoc-gen-grpc=${GRPC_PATH}/grpc_csharp_plugin 18 | 19 | cd - 20 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Extensions/DynamicExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.ComponentModel; 3 | using System.Dynamic; 4 | 5 | namespace NetCoreKit.Utils.Extensions 6 | { 7 | public static class DynamicExtensions 8 | { 9 | public static dynamic ToDynamic(this object value) 10 | { 11 | IDictionary expando = new ExpandoObject(); 12 | 13 | foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(value.GetType())) 14 | expando.Add(property.Name, property.GetValue(value)); 15 | 16 | return expando as ExpandoObject; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/_deploys/mongo/mongodb-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: mongodb-v1 5 | namespace: netcorekit 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: mongodb 12 | version: v1 13 | spec: 14 | containers: 15 | - name: mongodb 16 | image: bitnami/mongodb:latest 17 | imagePullPolicy: IfNotPresent 18 | ports: 19 | - containerPort: 27017 20 | resources: 21 | requests: 22 | memory: "500Mi" 23 | cpu: "100m" 24 | limits: 25 | memory: "500Mi" 26 | cpu: "100m" -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Migration/SeedDataBase.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Configuration; 4 | 5 | namespace NetCoreKit.Infrastructure.EfCore.Migration 6 | { 7 | public abstract class SeedDataBase : IAuthConfigSeedData 8 | where TDbContext : DbContext 9 | { 10 | protected SeedDataBase(IConfiguration configuration) 11 | { 12 | Configuration = configuration; 13 | } 14 | 15 | protected IConfiguration Configuration { get; } 16 | 17 | public abstract Task SeedAsync(TDbContext context); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace NetCoreKit.Samples.BiMonetaryApi 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateWebHostBuilder(args).Build().Run(); 12 | } 13 | 14 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) 15 | { 16 | return WebHost.CreateDefaultBuilder(args) 17 | .ConfigureLogging(builder => builder.AddConsole().AddDebug()) 18 | .UseStartup(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/TodoApi/Extensions/ProjectExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using NetCoreKit.Samples.TodoAPI.Dtos; 4 | 5 | namespace NetCoreKit.Samples.TodoAPI.Extensions 6 | { 7 | public static class ProjectExtensions 8 | { 9 | public static ProjectDto ToDto(this Domain.Project prj) 10 | { 11 | return new ProjectDto 12 | { 13 | Id = prj.Id, 14 | Name = prj.Name, 15 | Tasks = prj.Tasks == null 16 | ? new List() 17 | : prj.Tasks.Select(t => t.ToDto()).ToList() 18 | }; 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/WebNotifier/k8s/webnotifier-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: webnotifier-v1 5 | namespace: netcorekit 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: webnotifier 12 | version: v1 13 | spec: 14 | containers: 15 | - name: webnotifier 16 | image: vndg/webnotifier:latest 17 | imagePullPolicy: IfNotPresent 18 | ports: 19 | - containerPort: 80 20 | resources: 21 | requests: 22 | memory: "64Mi" 23 | cpu: "250m" 24 | limits: 25 | memory: "128Mi" 26 | cpu: "500m" -------------------------------------------------------------------------------- /samples/ExchangeService/v1/Services/HealthImpl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Grpc.Core; 4 | using Grpc.Health.V1; 5 | 6 | namespace NetCoreKit.Samples.ExchangeService.v1.Services 7 | { 8 | public class HealthImpl : Health.HealthBase 9 | { 10 | public override Task Check(HealthCheckRequest request, ServerCallContext context) 11 | { 12 | Console.WriteLine("Checking ExchangeService Health..."); 13 | 14 | return Task.FromResult(new HealthCheckResponse 15 | { 16 | Status = HealthCheckResponse.Types.ServingStatus.Serving 17 | }); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace NetCoreKit.Samples.SignalRNotifier 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateWebHostBuilder(args).Build().Run(); 12 | } 13 | 14 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) 15 | { 16 | return WebHost.CreateDefaultBuilder(args) 17 | .ConfigureLogging(builder => builder.AddConsole().AddDebug()) 18 | .UseStartup(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/TodoApi/Infrastructure/Db/TodoListDbModelBuilder.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using NetCoreKit.Infrastructure.EfCore.Db; 3 | 4 | namespace NetCoreKit.Samples.TodoAPI.Infrastructure.Db 5 | { 6 | public class TodoListDbModelBuilder : ICustomModelBuilder 7 | { 8 | public void Build(ModelBuilder modelBuilder) 9 | { 10 | modelBuilder.Entity(b => 11 | { 12 | b.HasMany(t => t.Tasks) 13 | .WithOne(a => a.Project) 14 | .HasForeignKey(k => k.ProjectId) 15 | .OnDelete(DeleteBehavior.Cascade); 16 | }); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /samples/TodoApi/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Hosts": { 3 | "Externals": { 4 | "CurrentUri": "http://localhost:5001" 5 | } 6 | }, 7 | "Features": { 8 | "EfCore": { 9 | "MySqlDb": { 10 | "FQDN": "127.0.0.1:3306", 11 | "Password": "P@ssw0rd" 12 | } 13 | }, 14 | "Redis": { 15 | "FQDN": "127.0.0.1:30904", 16 | "Password": "letmein" 17 | }, 18 | "Kafka": { 19 | "FQDN": "127.0.0.1:9092" 20 | } 21 | }, 22 | "Logging": { 23 | "IncludeScopes": false, 24 | "LogLevel": { 25 | "Default": "Debug", 26 | "System": "Information", 27 | "Microsoft": "Information" 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus/DomainEventBus.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using MediatR; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus 6 | { 7 | public class DomainEventDispatcher : IDomainEventDispatcher 8 | { 9 | private readonly IMediator _mediator; 10 | 11 | public DomainEventDispatcher(IMediator mediator) 12 | { 13 | _mediator = mediator; 14 | } 15 | 16 | public async Task Dispatch(IEvent @event) 17 | { 18 | await _mediator.Publish(new NotificationEnvelope(@event)); 19 | } 20 | 21 | public void Dispose() 22 | { 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: thangchung 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with a single custom sponsorship URL 13 | -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/sample-data/weather.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "date": "2018-05-06", 4 | "temperatureC": 1, 5 | "summary": "Freezing", 6 | "temperatureF": 33 7 | }, 8 | { 9 | "date": "2018-05-07", 10 | "temperatureC": 14, 11 | "summary": "Bracing", 12 | "temperatureF": 57 13 | }, 14 | { 15 | "date": "2018-05-08", 16 | "temperatureC": -13, 17 | "summary": "Freezing", 18 | "temperatureF": 9 19 | }, 20 | { 21 | "date": "2018-05-09", 22 | "temperatureC": -16, 23 | "summary": "Balmy", 24 | "temperatureF": 4 25 | }, 26 | { 27 | "date": "2018-05-10", 28 | "temperatureC": -2, 29 | "summary": "Chilly", 30 | "temperatureF": 29 31 | } 32 | ] 33 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/OpenApiOptions.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Infrastructure.AspNetCore.OpenApi 2 | { 3 | public class OpenApiOptions 4 | { 5 | public string Title { get; set; } = "API"; 6 | public string Description { get; set; } = "An application with Swagger, Swashbuckle, and API versioning."; 7 | public string ContactName { get; set; } = "Vietnam Devs"; 8 | public string ContactEmail { get; set; } = "vietnam.devs.group@gmail.com"; 9 | public string TermOfService { get; set; } = "Shareware"; 10 | public string LicenseName { get; set; } = "MIT"; 11 | public string LicenseUrl { get; set; } = "https://opensource.org/licenses/MIT"; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Kafka/ProtoSerializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Confluent.Kafka.Serialization; 3 | using Google.Protobuf; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus.Kafka 6 | { 7 | public class ProtoSerializer : ISerializer where T : IMessage 8 | { 9 | public IEnumerable> 10 | Configure(IEnumerable> config, bool isKey) 11 | { 12 | return config; 13 | } 14 | 15 | public void Dispose() 16 | { 17 | } 18 | 19 | public byte[] Serialize(string topic, T data) 20 | { 21 | return data.ToByteArray(); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/QueryRepository.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | 4 | namespace NetCoreKit.Domain 5 | { 6 | public interface IQueryRepositoryFactory 7 | { 8 | IQueryRepositoryWithId QueryRepository() where TEntity : class, IAggregateRootWithId; 9 | IQueryRepository QueryRepository() where TEntity : class, IAggregateRoot; 10 | } 11 | 12 | public interface IQueryRepository : IQueryRepositoryWithId where TEntity : IAggregateRoot 13 | { 14 | } 15 | 16 | public interface IQueryRepositoryWithId where TEntity : IAggregateRootWithId 17 | { 18 | IQueryable Queryable(); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /samples/TodoApi/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.2.0-aspnetcore-runtime-alpine AS base 2 | WORKDIR /app 3 | 4 | ARG service_version 5 | ENV SERVICE_VERSION ${service_version:-0.0.1} 6 | 7 | ARG api_version 8 | ENV API_VERSION ${api_version:-1.0} 9 | 10 | ENV ASPNETCORE_URLS http://+:80 11 | EXPOSE 80 12 | 13 | FROM microsoft/dotnet:2.2.100-sdk-alpine AS build 14 | WORKDIR . 15 | COPY . . 16 | 17 | WORKDIR /samples/TodoApi 18 | 19 | RUN dotnet restore -nowarn:msb3202,nu1503 20 | RUN dotnet build --no-restore -c Release -o /app 21 | 22 | FROM build AS publish 23 | RUN dotnet publish --no-restore -c Release -o /app 24 | 25 | FROM base AS final 26 | WORKDIR /app 27 | COPY --from=publish /app . 28 | ENTRYPOINT ["dotnet", "NetCoreKit.Samples.TodoApi.dll"] 29 | -------------------------------------------------------------------------------- /samples/TodoApi/Infrastructure/Gateways/UserGateway.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using NetCoreKit.Samples.TodoAPI.Domain; 4 | using NetCoreKit.Samples.TodoAPI.Dtos; 5 | using Task = System.Threading.Tasks.Task; 6 | 7 | namespace NetCoreKit.Samples.TodoAPI.Infrastructure.Gateways 8 | { 9 | public class UserGateway : IUserGateway 10 | { 11 | public Task GetAuthorAsync() 12 | { 13 | return Task.FromResult( 14 | new AuthorDto 15 | { 16 | Id = new Guid("E8F0B717-E325-466B-A87C-1AF1AA951599"), 17 | FirstName = "Tom", 18 | LastName = "Cruise" 19 | }); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/ModelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.ComponentModel.DataAnnotations; 4 | 5 | namespace NetCoreKit.Infrastructure.AspNetCore 6 | { 7 | public abstract class ModelBase 8 | { 9 | } 10 | 11 | public abstract class IdModelBase : ModelBase 12 | { 13 | [Required] public Guid Id { get; set; } 14 | } 15 | 16 | public abstract class RequestModelBase : ModelBase 17 | { 18 | public IEnumerable> Headers { get; set; } 19 | } 20 | 21 | public abstract class RequestIdModelBase : IdModelBase 22 | { 23 | public IEnumerable> Headers { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/TodoApi/Program.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Logging; 4 | 5 | namespace NetCoreKit.Samples.TodoAPI 6 | { 7 | public class Program 8 | { 9 | public static void Main(string[] args) 10 | { 11 | CreateWebHostBuilder(args).Build().Run(); 12 | } 13 | 14 | public static IWebHostBuilder CreateWebHostBuilder(string[] args) 15 | { 16 | return WebHost.CreateDefaultBuilder(args) 17 | .ConfigureLogging(builder => builder.AddConsole().AddDebug()) 18 | .UseStartup() 19 | .UseDefaultServiceProvider(o => o.ValidateScopes = false /* because of MySQL */); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5002", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "webnotifier": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:5002" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/RequestHandlerBase.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MediatR; 4 | using NetCoreKit.Domain; 5 | 6 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 7 | { 8 | public abstract class RequestHandlerBase : IEventHandler 9 | where TRequest : IRequest 10 | { 11 | protected RequestHandlerBase(IQueryRepositoryFactory queryRepositoryFactory) 12 | { 13 | QueryFactory = queryRepositoryFactory; 14 | } 15 | 16 | public IQueryRepositoryFactory QueryFactory { get; } 17 | 18 | public abstract Task Handle(TRequest request, CancellationToken cancellationToken); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Mongo/MongoContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Options; 2 | using MongoDB.Driver; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.Mongo 6 | { 7 | public class DbContext 8 | { 9 | private readonly IMongoDatabase _database; 10 | 11 | public DbContext(IOptions settings) 12 | { 13 | var client = new MongoClient(settings.Value.ConnString); 14 | _database = client.GetDatabase(settings.Value.Database); 15 | } 16 | 17 | public IMongoCollection Collection() 18 | where TEntity : IAggregateRoot 19 | { 20 | return _database.GetCollection(typeof(TEntity).FullName); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/k8s/todolist-job.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: batch/v1 2 | kind: Job 3 | metadata: 4 | name: todolist-db-schema-migration 5 | namespace: netcorekit 6 | spec: 7 | template: 8 | spec: 9 | containers: 10 | - name: todolist-db-schema-migration 11 | image: vndg/todoapi:latest 12 | imagePullPolicy: Always 13 | env: 14 | - name: Hosts__BasePath 15 | value: / 16 | command: 17 | - "/bin/sh" 18 | - "-c" 19 | - "until nc -z -v -w30 mysql 3306; do echo 'Waiting for database connection...'; sleep 5; done; until nc -z -v -w30 todolist 32501; do echo 'Waiting for todoapi connection...'; sleep 5; done; apk add --no-cache curl; curl http://todolist:32501/db-migration" 20 | restartPolicy: Never 21 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/UpdateTask/Payloads.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using MediatR; 4 | using NetCoreKit.Infrastructure.AspNetCore.OpenApi; 5 | using NetCoreKit.Samples.TodoAPI.Dtos; 6 | 7 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.UpdateTask 8 | { 9 | public class UpdateTaskRequest : IRequest 10 | { 11 | [SwaggerExclude] public Guid ProjectId { get; set; } 12 | 13 | internal Guid TaskId { get; set; } 14 | public int? Order { get; set; } = 1; 15 | [Required] public string Title { get; set; } 16 | public bool? Completed { get; set; } = false; 17 | } 18 | 19 | public class UpdateTaskResponse 20 | { 21 | public ProjectDto Result { get; set; } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /samples/WebNotifier/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5003/", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "NetCoreKit.Samples.WebNotifier": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:5003/" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /samples/WebNotifier/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.2.100-sdk-alpine AS build 2 | WORKDIR . 3 | COPY . . 4 | WORKDIR /samples/WebNotifier 5 | 6 | RUN dotnet restore -nowarn:msb3202,nu1503 7 | RUN dotnet build --no-restore -c Release -o /app 8 | 9 | FROM build AS publish 10 | RUN dotnet publish --no-restore -c Release -o /app/ 11 | WORKDIR /app 12 | RUN ls -an 13 | 14 | FROM nginx:alpine 15 | WORKDIR /app 16 | COPY --from=publish /app/WebNotifier/dist /usr/share/nginx/html/ 17 | WORKDIR /usr/share/nginx/html/ 18 | RUN ls -an 19 | COPY --from=build /samples/WebNotifier/nginx.conf /etc/nginx/nginx.conf 20 | COPY --from=build /samples/WebNotifier/mime.types /etc/nginx/mime.types 21 | RUN chmod 0644 /etc/nginx/nginx.conf 22 | RUN chmod 0644 /etc/nginx/nginx.conf 23 | 24 | CMD ["nginx", "-g", "daemon off;"] 25 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.All/Controllers/HomeController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | using Microsoft.Extensions.Configuration; 3 | using NetCoreKit.Infrastructure.AspNetCore.Configuration; 4 | 5 | namespace NetCoreKit.Infrastructure.AspNetCore.All.Controllers 6 | { 7 | [Route("")] 8 | [ApiVersionNeutral] 9 | [ApiExplorerSettings(IgnoreApi = true)] 10 | public class HomeController : Controller 11 | { 12 | private readonly string _basePath; 13 | 14 | public HomeController(IConfiguration config) 15 | { 16 | _basePath = config.GetBasePath() ?? "/"; 17 | } 18 | 19 | [HttpGet] 20 | public IActionResult Index() 21 | { 22 | return Redirect($"~{_basePath}swagger"); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.2.0-aspnetcore-runtime-alpine AS base 2 | RUN apk update && apk add libc6-compat 3 | WORKDIR /app 4 | 5 | ARG service_version 6 | ENV SERVICE_VERSION ${service_version:-0.0.1} 7 | 8 | ARG api_version 9 | ENV API_VERSION ${api_version:-1.0} 10 | 11 | ENV ASPNETCORE_URLS http://+:80 12 | EXPOSE 80 13 | 14 | FROM microsoft/dotnet:2.2.100-sdk-alpine AS build 15 | WORKDIR . 16 | COPY . . 17 | 18 | WORKDIR /samples/BiMonetaryApi 19 | 20 | RUN dotnet restore -nowarn:msb3202,nu1503 21 | RUN dotnet build --no-restore -c Release -o /app 22 | 23 | FROM build AS publish 24 | RUN dotnet publish --no-restore -c Release -o /app 25 | 26 | FROM base AS final 27 | WORKDIR /app 28 | COPY --from=publish /app . 29 | ENTRYPOINT ["dotnet", "NetCoreKit.Samples.BiMonetaryApi.dll"] 30 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Extensions/ByteArrayExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace NetCoreKit.Utils.Extensions 5 | { 6 | public static class ByteArrayExtensions 7 | { 8 | public static string ToBase64String(this byte[] input) 9 | { 10 | return Convert.ToBase64String(input); 11 | } 12 | 13 | public static string ToUrlSuitable(this byte[] input) 14 | { 15 | return input.ToBase64String().Replace("+", "-").Replace("/", "_").Replace("=", "%3d"); 16 | } 17 | 18 | public static string ToHexString(this byte[] bytes) 19 | { 20 | var hex = new StringBuilder(bytes.Length * 2); 21 | foreach (var b in bytes) hex.AppendFormat("{0:x2}", b); 22 | 23 | return hex.ToString(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Extensions/DbContextExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Migrations; 5 | 6 | namespace NetCoreKit.Infrastructure.EfCore.Extensions 7 | { 8 | public static class DbContextExtensions 9 | { 10 | public static bool AllMigrationsApplied(this DbContext context) 11 | { 12 | var applied = context.GetService() 13 | .GetAppliedMigrations() 14 | .Select(m => m.MigrationId); 15 | 16 | var total = context.GetService() 17 | .Migrations 18 | .Select(m => m.Key); 19 | 20 | return !total.Except(applied).Any(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/NetCoreKit.Utils.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Utils 7 | 0.0.0 8 | NetCoreKit.Utils 9 | NetCoreKit.Utils 10 | This utils library contains ultility functions and helpers (e.g. string, bytes, hash, modular). 11 | This utils library contains ultility functions and helpers (e.g. string, bytes, hash, modular) that need for the web development. 12 | netstandard2.0 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /samples/_protos/v1/bimonetary.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | 3 | package BiMonetary; 4 | 5 | option csharp_namespace = "NetCoreKit.Samples.BiMonetaryApi.Rpc"; 6 | 7 | import "google/protobuf/empty.proto"; 8 | 9 | service ExchangeService { 10 | rpc GetTokenInfo(TokenRequest) returns (TokenResponse); 11 | rpc Ping(google.protobuf.Empty) returns (PingResponse); 12 | } 13 | 14 | message TokenRequest { 15 | string Symbol = 1; 16 | } 17 | 18 | message TokenResponse { 19 | int32 Rank = 1; 20 | double PriceUsd = 2; 21 | double PriceBtc = 3; 22 | double Volumn24hUsd = 4; 23 | double MarketCapUsd = 5; 24 | double AvailableSupply = 6; 25 | double TotalSupply = 7; 26 | string PercentChange1h = 8; 27 | string PercentChange24h = 9; 28 | string PercentChange7d = 10; 29 | } 30 | 31 | message PingResponse { 32 | bool Result = 1; 33 | } 34 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.All/Controllers/DbMigrationController.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.AspNetCore.Mvc; 4 | using NetCoreKit.Infrastructure.EfCore.Extensions; 5 | 6 | namespace NetCoreKit.Infrastructure.AspNetCore.All.Controllers 7 | { 8 | [Route("")] 9 | [ApiVersionNeutral] 10 | [ApiExplorerSettings(IgnoreApi = true)] 11 | public class DbMigrationController : Controller 12 | { 13 | private readonly IServiceProvider _svcProvider; 14 | 15 | public DbMigrationController(IServiceProvider svcProvider) 16 | { 17 | _svcProvider = svcProvider; 18 | } 19 | 20 | [HttpGet("/db-migration")] 21 | public Task Index() 22 | { 23 | return Task.Run(() => _svcProvider.MigrateDbContext() != null); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/EventAggregatorExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Reactive.Linq; 3 | using System.Reactive.Threading.Tasks; 4 | using System.Threading; 5 | using MediatR; 6 | 7 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 8 | { 9 | public static class EventAggregatorExtensions 10 | { 11 | public static IObservable SendStream(this IMediator mediator, 12 | TRequest request, Func mapTo = null, 13 | CancellationToken token = default(CancellationToken)) 14 | where TRequest : IRequest 15 | where TResponse : class 16 | { 17 | return mediator.Send(request, token) 18 | .ToObservable() 19 | .Select(x => x.PresentFor(mapTo)); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/TodoApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "iisSettings": { 3 | "windowsAuthentication": false, 4 | "anonymousAuthentication": true, 5 | "iisExpress": { 6 | "applicationUrl": "http://localhost:5001", 7 | "sslPort": 0 8 | } 9 | }, 10 | "profiles": { 11 | "IIS Express": { 12 | "commandName": "IISExpress", 13 | "launchBrowser": true, 14 | "environmentVariables": { 15 | "ASPNETCORE_ENVIRONMENT": "Development" 16 | } 17 | }, 18 | "samples": { 19 | "commandName": "Project", 20 | "launchBrowser": true, 21 | "environmentVariables": { 22 | "ASPNETCORE_ENVIRONMENT": "Development" 23 | }, 24 | "applicationUrl": "http://localhost:5001" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/TxRequestHandlerBase.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MediatR; 4 | using NetCoreKit.Domain; 5 | 6 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 7 | { 8 | public abstract class TxRequestHandlerBase : ITxEventHandler 9 | where TRequest : IRequest 10 | { 11 | protected TxRequestHandlerBase(IUnitOfWorkAsync uow, IQueryRepositoryFactory queryRepositoryFactory) 12 | { 13 | QueryFactory = queryRepositoryFactory; 14 | CommandFactory = uow; 15 | } 16 | 17 | public IQueryRepositoryFactory QueryFactory { get; } 18 | 19 | public IUnitOfWorkAsync CommandFactory { get; } 20 | 21 | public abstract Task Handle(TRequest request, CancellationToken cancellationToken); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/SwaggerExcludeSchemaFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using System.Reflection; 3 | using Swashbuckle.AspNetCore.Swagger; 4 | using Swashbuckle.AspNetCore.SwaggerGen; 5 | 6 | namespace NetCoreKit.Infrastructure.AspNetCore.OpenApi 7 | { 8 | public class SwaggerExcludeSchemaFilter : ISchemaFilter 9 | { 10 | public void Apply(Schema schema, SchemaFilterContext context) 11 | { 12 | if (schema?.Properties == null) return; 13 | 14 | var excludedProperties = context.SystemType.GetProperties() 15 | .Where(t => t.GetCustomAttribute() != null); 16 | foreach (var excludedProperty in excludedProperties) 17 | if (schema.Properties.ContainsKey(excludedProperty.Name)) 18 | schema.Properties.Remove(excludedProperty.Name); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:54408", 8 | "sslPort": 0 9 | } 10 | }, 11 | "profiles": { 12 | "IIS Express": { 13 | "commandName": "IISExpress", 14 | "launchBrowser": true, 15 | "launchUrl": "", 16 | "environmentVariables": { 17 | "ASPNETCORE_ENVIRONMENT": "Development" 18 | } 19 | }, 20 | "NetCoreKit.Samples.BiMonetaryApi": { 21 | "commandName": "Project", 22 | "launchBrowser": true, 23 | "launchUrl": "", 24 | "applicationUrl": "http://localhost:5002", 25 | "environmentVariables": { 26 | "ASPNETCORE_ENVIRONMENT": "Development" 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/NetCoreKit.Domain.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Domain 7 | 0.0.0 8 | NetCoreKit.Domain 9 | NetCoreKit.Domain 10 | The domain library for Cloud Native .NET Core Kit. 11 | Supports DDD style with event approach in the library. 12 | netstandard2.0 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/App_Build/k8s/signalrnotifier-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: signalrnotifier-v1 5 | namespace: netcorekit 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: signalrnotifier 12 | version: v1 13 | spec: 14 | containers: 15 | - name: signalrnotifier 16 | image: vndg/signalrnotifier:latest 17 | imagePullPolicy: IfNotPresent 18 | env: 19 | - name: Hosts__BasePath 20 | value: / 21 | - name: Kafka__FQDN 22 | value: "kafka-cp-kafka.kafka:9092" 23 | - name: Redis__FQDN 24 | value: "redis-master.redis:6379" 25 | - name: Redis__Password 26 | valueFrom: 27 | secretKeyRef: 28 | name: signalrnotifier-secrets 29 | key: RedisPassword 30 | ports: 31 | - containerPort: 80 32 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/v1/Controllers/PingController.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Google.Protobuf.WellKnownTypes; 3 | using Microsoft.AspNetCore.Mvc; 4 | using MyExchangeService = NetCoreKit.Samples.BiMonetaryApi.Rpc.ExchangeService; 5 | 6 | namespace NetCoreKit.Samples.BiMonetaryApi.v1.Controllers 7 | { 8 | [Route("api/ping")] 9 | [ApiController] 10 | public class PingController : ControllerBase 11 | { 12 | private readonly MyExchangeService.ExchangeServiceClient _exchangeServiceClient; 13 | 14 | public PingController(MyExchangeService.ExchangeServiceClient exchangeServiceClient) 15 | { 16 | _exchangeServiceClient = exchangeServiceClient; 17 | } 18 | 19 | [HttpGet] 20 | public async Task Ping() 21 | { 22 | var response = await _exchangeServiceClient.PingAsync(new Empty()); 23 | return Ok(response.Result); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Kafka/ProtoDeserializer.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Confluent.Kafka.Serialization; 3 | using Google.Protobuf; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus.Kafka 6 | { 7 | public class ProtoDeserializer : IDeserializer 8 | where T : IMessage, new() 9 | { 10 | private readonly MessageParser _parser; 11 | 12 | public ProtoDeserializer() 13 | { 14 | _parser = new MessageParser(() => new T()); 15 | } 16 | 17 | public IEnumerable> 18 | Configure(IEnumerable> config, bool isKey) 19 | { 20 | return config; 21 | } 22 | 23 | public void Dispose() 24 | { 25 | } 26 | 27 | public T Deserialize(string topic, byte[] data) 28 | { 29 | return _parser.ParseFrom(data); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/CreateProject/Payloads.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel.DataAnnotations; 2 | using AutoMapper; 3 | using MediatR; 4 | using NetCoreKit.Infrastructure.Mappers; 5 | using NetCoreKit.Samples.TodoAPI.Domain; 6 | using NetCoreKit.Samples.TodoAPI.Dtos; 7 | 8 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.CreateProject 9 | { 10 | public class CreateProjectRequest : IRequest 11 | { 12 | public CreateProjectRequest() 13 | { 14 | Name = "sample project"; 15 | } 16 | 17 | [Required] public string Name { get; set; } 18 | } 19 | 20 | public class CreateProjectResponse 21 | { 22 | public ProjectDto Result { get; set; } 23 | } 24 | 25 | public class CreateProjectProfile : Profile 26 | { 27 | public CreateProjectProfile() 28 | { 29 | this.MapMySelf(); 30 | this.MapMySelf(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /samples/readme.md: -------------------------------------------------------------------------------- 1 | ### Installation 2 | 3 | - MySQL 4 | 5 | ```bash 6 | > helm install --name mysql --namespace netcorekit stable/mysql --set mysqlRootPassword=P@ssw0rd --set mysqlPassword=P@ssw0rd --set mysqlDatabase=maindb 7 | ``` 8 | 9 | - Redis 10 | 11 | ```bash 12 | > helm install --name redis --namespace redis stable/redis --set usePassword=true --set password=letmein 13 | ``` 14 | 15 | - Kafka 16 | 17 | ```bash 18 | > git clone https://github.com/confluentinc/cp-helm-charts.git 19 | > kubectl ns create kafka 20 | > helm install cp-helm-charts --name kafka --namespace kafka 21 | ``` 22 | 23 | - Build all solutions 24 | - Run multiple projects `NetCoreKit.Samples.TodoAPI`, `NetCoreKit.Samples.SignalRNotifier`, and `NetCoreKit.Samples.WebNotifier` 25 | 26 | - Run one-off tasks (e.g. database migration) 27 | 28 | ```bash 29 | > kubectl apply -f samples/TodoApi/k8s/todolist-job.yaml 30 | ``` 31 | 32 | **Notes**: Change configuration in appsettings.Development.json with your configuration on your local machine. 33 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Mongo/QueryRepositoryFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.Mongo 6 | { 7 | public class QueryRepositoryFactory : IQueryRepositoryFactory 8 | { 9 | private readonly IServiceProvider _serviceProvider; 10 | 11 | public QueryRepositoryFactory(IServiceProvider serviceProvider) 12 | { 13 | _serviceProvider = serviceProvider; 14 | } 15 | 16 | public IQueryRepository QueryRepository() where TEntity : class, IAggregateRoot 17 | { 18 | return _serviceProvider.GetService>(); 19 | } 20 | 21 | public IQueryRepositoryWithId QueryRepository() where TEntity : class, IAggregateRootWithId 22 | { 23 | return _serviceProvider.GetService>(); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /samples/ExchangeService/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM microsoft/dotnet:2.2.0-aspnetcore-runtime-alpine AS base 2 | RUN apk update && apk add libc6-compat 3 | RUN GRPC_HEALTH_PROBE_VERSION=v0.2.0 && \ 4 | wget -qO/bin/grpc_health_probe https://github.com/grpc-ecosystem/grpc-health-probe/releases/download/${GRPC_HEALTH_PROBE_VERSION}/grpc_health_probe-linux-amd64 && \ 5 | chmod +x /bin/grpc_health_probe 6 | WORKDIR /app 7 | 8 | ARG service_version 9 | ENV SERVICE_VERSION ${service_version:-0.0.1} 10 | 11 | ARG api_version 12 | ENV API_VERSION ${api_version:-1.0} 13 | 14 | FROM microsoft/dotnet:2.2.100-sdk-alpine AS build 15 | WORKDIR . 16 | COPY . . 17 | 18 | WORKDIR /samples/ExchangeService 19 | 20 | RUN dotnet restore -nowarn:msb3202,nu1503 21 | RUN dotnet build --no-restore -c Release -o /app 22 | 23 | FROM build AS publish 24 | RUN dotnet publish --no-restore -c Release -o /app 25 | 26 | FROM base AS final 27 | WORKDIR /app 28 | COPY --from=publish /app . 29 | ENTRYPOINT ["dotnet", "NetCoreKit.Samples.ExchangeService.dll"] 30 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Services/Mappers/ProjectProfile.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using AutoMapper; 3 | using NetCoreKit.Samples.Contracts.TodoApi; 4 | using NetCoreKit.Samples.SignalRNotifier.Services.Events; 5 | 6 | namespace NetCoreKit.Samples.SignalRNotifier.Services.Mappers 7 | { 8 | public class ProjectProfile : Profile 9 | { 10 | public ProjectProfile() 11 | { 12 | CreateMap() 13 | .ForMember(x => x.Id, conf => conf.MapFrom(cg => new Guid(cg.Id))) 14 | .ForMember(x => x.ProjectId, conf => conf.MapFrom(cg => new Guid(cg.ProjectId))) 15 | .ForMember(x => x.OccurredOn, conf => conf.MapFrom(cg => cg.OccurredOn.ToDateTime())); 16 | 17 | CreateMap() 18 | .ForMember(x => x.Id, conf => conf.MapFrom(cg => new Guid(cg.Id))) 19 | .ForMember(x => x.OccurredOn, conf => conf.MapFrom(cg => cg.OccurredOn.ToDateTime())); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/CreateProject/RequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MediatR; 4 | using NetCoreKit.Domain; 5 | using NetCoreKit.Samples.TodoAPI.Extensions; 6 | 7 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.CreateProject 8 | { 9 | public class RequestHandler : IRequestHandler 10 | { 11 | private readonly IUnitOfWorkAsync _uow; 12 | 13 | public RequestHandler(IUnitOfWorkAsync uow) 14 | { 15 | _uow = uow; 16 | } 17 | 18 | public async Task Handle(CreateProjectRequest request, 19 | CancellationToken cancellationToken) 20 | { 21 | var projectRepository = _uow.RepositoryAsync(); 22 | 23 | var result = await projectRepository.AddAsync(Domain.Project.Load(request.Name)); 24 | 25 | return new CreateProjectResponse {Result = result.ToDto()}; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/AddTask/Payloads.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using MediatR; 4 | using NetCoreKit.Infrastructure.AspNetCore.OpenApi; 5 | using NetCoreKit.Samples.TodoAPI.Dtos; 6 | 7 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.AddTask 8 | { 9 | public class AddTaskRequest : IRequest 10 | { 11 | public AddTaskRequest() 12 | { 13 | Completed = false; 14 | Order = 1; 15 | Title = "sample todo"; 16 | AuthorId = new Guid("E8F0B717-E325-466B-A87C-1AF1AA951599"); // we have it in db 17 | } 18 | 19 | [SwaggerExclude] public Guid ProjectId { get; set; } 20 | 21 | public int? Order { get; set; } 22 | [Required] public string Title { get; set; } 23 | public bool? Completed { get; set; } 24 | public Guid AuthorId { get; } 25 | } 26 | 27 | public class AddTaskResponse 28 | { 29 | public ProjectDto Result { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/Exception.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace NetCoreKit.Domain 4 | { 5 | public class CoreException : Exception 6 | { 7 | public CoreException(string message) 8 | : this(message, null) 9 | { 10 | } 11 | 12 | public CoreException(string message, Exception innerEx) 13 | : base(message, innerEx) 14 | { 15 | } 16 | } 17 | 18 | public class DomainException : CoreException 19 | { 20 | public DomainException(string message) 21 | : base(message, null) 22 | { 23 | } 24 | } 25 | 26 | public class ViolateSecurityException : CoreException 27 | { 28 | public ViolateSecurityException(string message) 29 | : base(message, null) 30 | { 31 | } 32 | } 33 | 34 | public class ValidationException : CoreException 35 | { 36 | public ValidationException(string message) 37 | : base(message, null) 38 | { 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.MySql/NetCoreKit.Infrastructure.EfCore.MySql.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.EfCore.MySql 7 | 0.0.0 8 | The EfCore MySQL library for Cloud Native .NET Core Kit. 9 | The MySQL database default for NetCoreKit.Infrastructure.EfCore 10 | netstandard2.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /appveyor.yml: -------------------------------------------------------------------------------- 1 | image: Visual Studio 2017 2 | 3 | branches: 4 | only: 5 | - master 6 | 7 | init: 8 | - git config --global core.autocrlf true 9 | 10 | pull_requests: 11 | # Do not increment build number for pull requests 12 | do_not_increment_build_number: true 13 | 14 | nuget: 15 | # Do not publish for pull requests 16 | disable_publish_on_pr: true 17 | 18 | environment: 19 | # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages 20 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 21 | # Disable sending usage data to Microsoft 22 | DOTNET_CLI_TELEMETRY_OPTOUT: true 23 | 24 | assembly_info: 25 | patch: false 26 | 27 | configuration: 28 | - Debug 29 | 30 | before_build: 31 | # - ps: choco install dotnetcore-sdk --no-progress --confirm --version 2.2.0 32 | # Display .NET Core version 33 | - cmd: dotnet --version 34 | # Display minimal restore text 35 | - cmd: dotnet restore --verbosity m 36 | 37 | build_script: 38 | - ps: ./build.ps1 39 | 40 | test: off 41 | 42 | skip_tags: true 43 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.SqlServer/NetCoreKit.Infrastructure.EfCore.SqlServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.EfCore.SqlServer 7 | 0.0.0 8 | The EfCore SqlServer library for Cloud Native .NET Core Kit. 9 | The Microsoft Sql Server default for NetCoreKit.Infrastructure.EfCore. 10 | netstandard2.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/_deploys/kafka/kafka-manager.yml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: kafka-manager-v1 5 | namespace: kafka 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kafka-manager 11 | template: 12 | metadata: 13 | labels: 14 | app: kafka-manager 15 | version: v1 16 | spec: 17 | containers: 18 | - name: kafka-manager 19 | image: solsson/kafka-manager@sha256:28b1a0b355f3972a9e3b5ac82abcbfee9a72b66a2bfe86094f6ea2caad9ce3a7 20 | ports: 21 | - containerPort: 80 22 | env: 23 | - name: ZK_HOSTS 24 | value: "kafka-cp-zookeeper.kafka:2181" 25 | command: 26 | - ./bin/kafka-manager 27 | - -Dhttp.port=80 28 | --- 29 | apiVersion: v1 30 | kind: Service 31 | metadata: 32 | name: kafka-manager 33 | namespace: kafka 34 | labels: 35 | app: kafka-manager 36 | spec: 37 | selector: 38 | app: kafka-manager 39 | ports: 40 | - protocol: TCP 41 | port: 9000 42 | targetPort: 80 43 | type: LoadBalancer -------------------------------------------------------------------------------- /samples/BiMonetaryApi/Startup.cs: -------------------------------------------------------------------------------- 1 | using Grpc.Core; 2 | using Microsoft.AspNetCore.Builder; 3 | using Microsoft.Extensions.Configuration; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using NetCoreKit.RestTemplate.MongoDb; 6 | using static NetCoreKit.Samples.BiMonetaryApi.Rpc.ExchangeService; 7 | 8 | namespace NetCoreKit.Samples.BiMonetaryApi 9 | { 10 | public class Startup 11 | { 12 | public void ConfigureServices(IServiceCollection services) 13 | { 14 | services.AddMongoDbTemplate(null, (svc, resolver) => 15 | { 16 | var config = resolver.GetService(); 17 | var channel = new Channel(config["RpcClients:ExchangeService"], ChannelCredentials.Insecure); 18 | var client = new ExchangeServiceClient(channel); 19 | services.AddSingleton(typeof(ExchangeServiceClient), client); 20 | }); 21 | } 22 | 23 | public void Configure(IApplicationBuilder app) 24 | { 25 | app.UseMongoDbTemplate(); 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /netcorekit.sln.DotSettings: -------------------------------------------------------------------------------- 1 | 2 | True 3 | True 4 | True 5 | True 6 | True 7 | True 8 | True 9 | True -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Extensions/AssemblyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Reflection; 5 | using Microsoft.Extensions.DependencyModel; 6 | 7 | namespace NetCoreKit.Utils.Extensions 8 | { 9 | /// 10 | /// https://stackoverflow.com/questions/37895278/how-to-load-assemblies-located-in-a-folder-in-net-core-console-app 11 | /// 12 | public static class AssemblyExtensions 13 | { 14 | public static Assembly FindAssemblyBy(this string assemblyName) 15 | { 16 | var deps = DependencyContext.Default; 17 | var res = deps.CompileLibraries.Where(d => d.Name.Contains(assemblyName)).ToList(); 18 | var assembly = Assembly.Load(new AssemblyName(res.First().Name)); 19 | return assembly; 20 | } 21 | 22 | public static HashSet GetAssembliesByTypes(this IEnumerable types) 23 | { 24 | return new HashSet(types.Select(type => type.GetTypeInfo().Assembly)); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.Tests/NetCoreKit.Infrastructure.EfCore.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | 7.3 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Always 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/UnitOfWork.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | 5 | namespace NetCoreKit.Domain 6 | { 7 | public interface IUnitOfWorkAsync : IRepositoryFactoryAsync, IDisposable 8 | { 9 | int SaveChanges(); 10 | Task SaveChangesAsync(CancellationToken cancellationToken); 11 | } 12 | 13 | public interface IRepositoryFactoryAsync 14 | { 15 | IRepositoryWithIdAsync RepositoryAsync() where TEntity : class, IAggregateRootWithId; 16 | IRepositoryAsync RepositoryAsync() where TEntity : class, IAggregateRoot; 17 | } 18 | 19 | public interface IRepositoryAsync : IRepositoryWithIdAsync where TEntity : IAggregateRoot 20 | { 21 | } 22 | 23 | public interface IRepositoryWithIdAsync where TEntity : IAggregateRootWithId 24 | { 25 | Task AddAsync(TEntity entity); 26 | Task UpdateAsync(TEntity entity); 27 | Task DeleteAsync(TEntity entity); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.SqlServer/DbContextOptionsBuilderFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using NetCoreKit.Infrastructure.EfCore.Db; 4 | 5 | namespace NetCoreKit.Infrastructure.EfCore.SqlServer 6 | { 7 | public sealed class DbContextOptionsBuilderFactory : IExtendDbContextOptionsBuilder 8 | { 9 | public DbContextOptionsBuilder Extend( 10 | DbContextOptionsBuilder optionsBuilder, 11 | IDbConnStringFactory connectionStringFactory, 12 | string assemblyName) 13 | { 14 | return optionsBuilder.UseSqlServer( 15 | connectionStringFactory.Create(), 16 | sqlOptions => 17 | { 18 | sqlOptions.MigrationsAssembly(assemblyName); 19 | sqlOptions.EnableRetryOnFailure( 20 | 15, 21 | TimeSpan.FromSeconds(30), 22 | null); 23 | }) 24 | .EnableSensitiveDataLogging(); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /samples/WebNotifier/Startup.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Reflection; 4 | using Microsoft.AspNetCore.Blazor.Builder; 5 | using Microsoft.Extensions.DependencyInjection; 6 | using Microsoft.JSInterop; 7 | 8 | namespace WebNotifier 9 | { 10 | public class Startup 11 | { 12 | public void ConfigureServices(IServiceCollection services) 13 | { 14 | services.AddSingleton(GetConfiguration()); 15 | } 16 | 17 | public void Configure(IBlazorApplicationBuilder app) 18 | { 19 | app.AddComponent("app"); 20 | } 21 | 22 | public Configuration GetConfiguration() 23 | { 24 | // source: https://github.com/aspnet/Blazor/issues/1152 25 | using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("config.json")) 26 | using (var reader = new StreamReader(stream ?? throw new InvalidOperationException())) 27 | { 28 | return Json.Deserialize(reader.ReadToEnd()); 29 | } 30 | } 31 | } 32 | 33 | public class Configuration 34 | { 35 | public string SignalRBaseUrl { get; set; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/App_Build/k8s/bimonetary-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: bimonetary-api-v1 5 | namespace: netcorekit 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: bimonetary-api 12 | version: v1 13 | spec: 14 | containers: 15 | - name: bimonetary-api 16 | image: vndg/bimonetary-api:latest 17 | imagePullPolicy: IfNotPresent 18 | env: 19 | - name: Hosts__BasePath 20 | value: / 21 | - name: Features__Mongo__ConnString 22 | value: mongodb://mongodb:27017 23 | - name: RpcClients__ExchangeService 24 | value: exchange:5000 25 | resources: 26 | requests: 27 | cpu: 200m 28 | memory: 64Mi 29 | limits: 30 | cpu: 300m 31 | memory: 128Mi 32 | ports: 33 | - containerPort: 80 34 | livenessProbe: 35 | httpGet: 36 | path: /healthz 37 | port: 80 38 | initialDelaySeconds: 15 39 | periodSeconds: 10 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 cloud-native-netcore 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Rest/HttpResponseExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Text; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.WebUtilities; 4 | using Newtonsoft.Json; 5 | 6 | namespace NetCoreKit.Infrastructure.AspNetCore.Rest 7 | { 8 | public static class HttpResponseExtensions 9 | { 10 | private static readonly JsonSerializer Serializer = new JsonSerializer 11 | { 12 | NullValueHandling = NullValueHandling.Ignore 13 | }; 14 | 15 | public static void WriteJson(this HttpResponse response, T obj, string contentType = null) 16 | { 17 | response.ContentType = contentType ?? "application/json"; 18 | using (var writer = new HttpResponseStreamWriter(response.Body, Encoding.UTF8)) 19 | { 20 | using (var jsonWriter = new JsonTextWriter(writer)) 21 | { 22 | jsonWriter.CloseOutput = false; 23 | jsonWriter.AutoCompleteOnClose = false; 24 | 25 | Serializer.Serialize(jsonWriter, obj); 26 | } 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/NetCoreKit.Infrastructure.AspNetCore.CleanArch.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.AspNetCore.CleanArch 7 | 0.0.0 8 | The Clean Architecture library for Cloud Native .NET Core Kit. 9 | Helps to organize a service structure and architecture according to Clean Architecture. 10 | netstandard2.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Redis/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace NetCoreKit.Infrastructure.Bus.Redis 5 | { 6 | public static class ServiceCollectionExtensions 7 | { 8 | public static IServiceCollection AddRedisBus(this IServiceCollection services) 9 | { 10 | var resolver = services.BuildServiceProvider(); 11 | using (var scope = resolver.CreateScope()) 12 | { 13 | var config = scope.ServiceProvider.GetService(); 14 | var redisOptions = config.GetSection("Features:Redis"); 15 | 16 | services.Configure(o => 17 | { 18 | o.Fqdn = redisOptions.GetValue("FQDN"); 19 | o.Password = redisOptions.GetValue("Password"); 20 | }); 21 | 22 | services.AddSingleton(); 23 | services.AddSingleton(); 24 | return services; 25 | } 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/WebNotifier/wwwroot/css/open-iconic/ICON-LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Waybury 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Helpers/CryptoRandomHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using NetCoreKit.Utils.Extensions; 4 | 5 | namespace NetCoreKit.Utils.Helpers 6 | { 7 | public class CryptoRandomHelper 8 | { 9 | private static readonly RandomNumberGenerator _rng = RandomNumberGenerator.Create(); 10 | 11 | public static byte[] CreateRandomBytes(int length) 12 | { 13 | var bytes = new byte[length]; 14 | _rng.GetBytes(bytes); 15 | 16 | return bytes; 17 | } 18 | 19 | public static string CreateRandomKey(int length) 20 | { 21 | var bytes = new byte[length]; 22 | _rng.GetBytes(bytes); 23 | 24 | return Convert.ToBase64String(CreateRandomBytes(length)); 25 | } 26 | 27 | public static string CreateUniqueKey(int length = 8) 28 | { 29 | return CreateRandomBytes(length).ToHexString(); 30 | } 31 | 32 | public static string CreateSeriesNumber(string prefix = "MSK") 33 | { 34 | return $"{prefix}{DateTime.Now.ToString("yyyyMMddHHmmss")}{CreateUniqueKey()}"; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.MySql/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.DependencyInjection.Extensions; 4 | using NetCoreKit.Infrastructure.EfCore.Db; 5 | 6 | namespace NetCoreKit.Infrastructure.EfCore.MySql 7 | { 8 | public static class ServiceCollectionExtensions 9 | { 10 | public static IServiceCollection AddEfCoreMySqlDb(this IServiceCollection services) 11 | { 12 | var svcProvider = services.BuildServiceProvider(); 13 | var config = svcProvider.GetRequiredService(); 14 | 15 | services.Configure(config.GetSection("Features:EfCore:MySqlDb")); 16 | 17 | services.Replace( 18 | ServiceDescriptor.Scoped< 19 | IDbConnStringFactory, 20 | DbConnStringFactory>()); 21 | 22 | services.Replace( 23 | ServiceDescriptor.Scoped< 24 | IExtendDbContextOptionsBuilder, 25 | DbContextOptionsBuilderFactory>()); 26 | 27 | return services; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Redis/RedisStore.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Options; 3 | using StackExchange.Redis; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus.Redis 6 | { 7 | public class RedisStore 8 | { 9 | private static Lazy _lazyConnection; 10 | 11 | public RedisStore(IOptions redisOptions) 12 | { 13 | var configurationOptions = new ConfigurationOptions 14 | { 15 | EndPoints = 16 | { 17 | redisOptions.Value.Fqdn 18 | }, 19 | Password = redisOptions.Value.Password 20 | }; 21 | 22 | _lazyConnection = 23 | new Lazy(() => ConnectionMultiplexer.Connect(configurationOptions)); 24 | } 25 | 26 | public ConnectionMultiplexer Connection => _lazyConnection.Value; 27 | 28 | public IDatabase RedisCache => Connection.GetDatabase(); 29 | } 30 | 31 | public class RedisOptions 32 | { 33 | public string Fqdn { get; set; } = "127.0.0.1:6379"; 34 | public string Password { get; set; } = "letmein"; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Middlewares/LogHandlerMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using Microsoft.AspNetCore.Http; 3 | using Microsoft.AspNetCore.Http.Extensions; 4 | using Microsoft.Extensions.Logging; 5 | using static NetCoreKit.Utils.Helpers.IdHelper; 6 | 7 | namespace NetCoreKit.Infrastructure.AspNetCore.Middlewares 8 | { 9 | public class LogHandlerMiddleware 10 | { 11 | private readonly ILogger _logger; 12 | private readonly RequestDelegate _next; 13 | 14 | public LogHandlerMiddleware(ILoggerFactory loggerFactory, RequestDelegate next) 15 | { 16 | _logger = loggerFactory.CreateLogger(); 17 | _next = next; 18 | } 19 | 20 | public async Task Invoke(HttpContext context) 21 | { 22 | context.Items["CorrelationId"] = GenerateId(); 23 | _logger.LogInformation( 24 | $"About to start {context.Request?.Method} {context.Request?.GetDisplayUrl()} request"); 25 | 26 | await _next(context); 27 | 28 | _logger.LogInformation($"Request completed with status code: {context.Response?.StatusCode} "); 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /samples/ExchangeService/App_Build/k8s/exchange-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1beta2 2 | kind: Deployment 3 | metadata: 4 | name: exchange 5 | namespace: netcorekit 6 | labels: 7 | app: exchange 8 | spec: 9 | replicas: 1 10 | selector: 11 | matchLabels: 12 | app: exchange 13 | template: 14 | metadata: 15 | labels: 16 | app: exchange 17 | spec: 18 | containers: 19 | - name: exchange 20 | image: vndg/exchange-service:latest 21 | imagePullPolicy: IfNotPresent 22 | env: 23 | - name: Hosts__Local__Host 24 | value: "0.0.0.0" 25 | - name: Hosts__Local__Port 26 | value: "5000" 27 | ports: 28 | - containerPort: 5000 29 | resources: 30 | requests: 31 | cpu: 200m 32 | memory: 64Mi 33 | limits: 34 | cpu: 300m 35 | memory: 128Mi 36 | readinessProbe: 37 | initialDelaySeconds: 15 38 | exec: 39 | command: ["/bin/grpc_health_probe", "-addr=:5000"] 40 | livenessProbe: 41 | initialDelaySeconds: 15 42 | periodSeconds: 10 43 | exec: 44 | command: ["/bin/grpc_health_probe", "-addr=:5000"] 45 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Mongo/NetCoreKit.Infrastructure.Mongo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.Mongo 7 | 0.0.1 8 | The Mongo library for Cloud Native .NET Core Kit. 9 | The MySQL database default for NetCoreKit.Infrastructure.Mongo 10 | netstandard2.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/TodoApi/Startup.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using NetCoreKit.Infrastructure.Bus; 4 | using NetCoreKit.Infrastructure.Bus.Redis; 5 | using NetCoreKit.Infrastructure.EfCore.MySql; 6 | using NetCoreKit.RestTemplate.EfCore; 7 | using NetCoreKit.Samples.TodoAPI.Domain; 8 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Db; 9 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Gateways; 10 | 11 | namespace NetCoreKit.Samples.TodoAPI 12 | { 13 | public class Startup 14 | { 15 | public void ConfigureServices(IServiceCollection services) 16 | { 17 | services.AddEfCoreTemplate( 18 | svc => 19 | { 20 | //svc.AddEfSqlLiteDb(); 21 | svc.AddEfCoreMySqlDb(); 22 | }, 23 | (svc, _) => { svc.AddScoped(); } 24 | ); 25 | 26 | services.AddDomainEventBus(); 27 | //services.AddRedisBus(); //todo: enabled it if using a broker 28 | } 29 | 30 | public void Configure(IApplicationBuilder app) 31 | { 32 | app.UseEfCoreTemplate(); 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/NetCoreKit.Utils/Helpers/EnumHelper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace NetCoreKit.Utils.Helpers 6 | { 7 | public class EnumHelper 8 | { 9 | public static IEnumerable> GetEnumKeyValue() 10 | where TKey : class 11 | { 12 | var metas = GetMetadata(); 13 | var results = metas.Item1.Zip(metas.Item2, (key, value) => 14 | new KeyValueObject 15 | ( 16 | key, 17 | value 18 | ) 19 | ); 20 | return results; 21 | } 22 | 23 | public static (IEnumerable, IEnumerable) GetMetadata() 24 | { 25 | var keyArray = (TKey[])Enum.GetValues(typeof(TEnum)); 26 | var nameArray = Enum.GetNames(typeof(TEnum)); 27 | 28 | IList keys = new List(); 29 | foreach (var item in keyArray) keys.Add(item); 30 | 31 | IList names = new List(); 32 | foreach (var item in nameArray) names.Add(item); 33 | 34 | return (keys, names); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Rest/HttpRequestExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace NetCoreKit.Infrastructure.AspNetCore.Rest 6 | { 7 | public static class HttpRequestExtensions 8 | { 9 | /// 10 | /// Follow at http://opentracing.io/documentation/pages/spec 11 | /// 12 | /// 13 | /// 14 | public static IEnumerable> GetOpenTracingInfo(this HttpRequest request) 15 | { 16 | return request.Headers.Where(x => 17 | x.Key == "x-request-id" || 18 | x.Key == "x-b3-traceid" || 19 | x.Key == "x-b3-spanid" || 20 | x.Key == "x-b3-parentspanid" || 21 | x.Key == "x-b3-sampled" || 22 | x.Key == "x-b3-flags" || 23 | x.Key == "x-ot-span-context" /* || x.Key == "Authorization" */ 24 | ).Select(y => 25 | new KeyValuePair( 26 | y.Key, 27 | y.Value.FirstOrDefault())); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.SqlServer/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Configuration; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.DependencyInjection.Extensions; 4 | using NetCoreKit.Infrastructure.EfCore.Db; 5 | using NetCoreKit.Infrastructure.EfCore.SqlServer.Options; 6 | 7 | namespace NetCoreKit.Infrastructure.EfCore.SqlServer 8 | { 9 | public static class ServiceCollectionExtensions 10 | { 11 | public static IServiceCollection AddEfCoreSqlServerDb(this IServiceCollection services) 12 | { 13 | var svcProvider = services.BuildServiceProvider(); 14 | var config = svcProvider.GetRequiredService(); 15 | 16 | services.Configure(config.GetSection("k8s:mssqldb")); 17 | 18 | services.Replace( 19 | ServiceDescriptor.Scoped< 20 | IDbConnStringFactory, 21 | DbConnStringFactory>()); 22 | 23 | services.Replace( 24 | ServiceDescriptor.Scoped< 25 | IExtendDbContextOptionsBuilder, 26 | DbContextOptionsBuilderFactory>()); 27 | 28 | return services; 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus/Envelopes.cs: -------------------------------------------------------------------------------- 1 | using Google.Protobuf; 2 | using MediatR; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus 6 | { 7 | /// 8 | /// This class contains the domain event which published from domain entity. 9 | /// We use DomainEventBus to handle and publish it back to the specific project, 10 | /// then it will handle and use some of popular event brokers like Redis/Kafka to handle it 11 | /// 12 | public class NotificationEnvelope : INotification 13 | { 14 | public NotificationEnvelope(IEvent @event) 15 | { 16 | Event = @event; 17 | } 18 | 19 | public IEvent Event { get; } 20 | } 21 | 22 | /// 23 | /// This class contains the Protobuf message with the idea that we will use Protobuf 24 | /// for inter-communication bus via event broker like Redis/Kafka 25 | /// 26 | /// 27 | public class MessageEnvelope : INotification 28 | where T : IMessage 29 | { 30 | public MessageEnvelope(IMessage message) 31 | { 32 | Message = message; 33 | } 34 | 35 | public IMessage Message { get; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /samples/_deploys/kafka/kafka-server.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: kafka-server-v1 5 | namespace: kafka 6 | spec: 7 | replicas: 1 8 | selector: 9 | matchLabels: 10 | app: kafka-server 11 | template: 12 | metadata: 13 | labels: 14 | app: kafka-server 15 | version: v1 16 | spec: 17 | terminationGracePeriodSeconds: 10 18 | hostNetwork: true 19 | containers: 20 | - name: kafka-server 21 | image: spotify/kafka 22 | ports: 23 | - name: kafka 24 | containerPort: 9092 25 | hostPort: 9092 26 | - name: zookeeper 27 | containerPort: 2181 28 | hostPort: 2181 29 | env: 30 | - name: ADVERTISED_HOST 31 | value: "127.0.0.1" 32 | - name: ADVERTISED_PORT 33 | value: "9092" 34 | --- 35 | apiVersion: v1 36 | kind: Service 37 | metadata: 38 | name: kafka-server 39 | namespace: kafka 40 | labels: 41 | app: kafka-server 42 | spec: 43 | selector: 44 | app: kafka-server 45 | ports: 46 | - name: kafka 47 | protocol: TCP 48 | port: 9092 49 | targetPort: 9092 50 | - name: zookeeper 51 | protocol: TCP 52 | port: 2181 53 | targetPort: 2181 54 | -------------------------------------------------------------------------------- /samples/WebNotifier/NetCoreKit.Samples.WebNotifier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netstandard2.0 5 | dotnet 6 | blazor serve 7 | 7.3 8 | WebNotifier 9 | WebNotifier 10 | true 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | config.json 23 | 24 | 25 | config.json 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/HATEOAS/CriterionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.AspNetCore.HATEOAS 6 | { 7 | public static class CriterionExtensions 8 | { 9 | public static bool HasPrevious(this Criterion criterion) 10 | { 11 | return criterion.CurrentPage > 1; 12 | } 13 | 14 | public static bool HasNext(this Criterion criterion, int totalCount) 15 | { 16 | return criterion.CurrentPage < (int)GetTotalPages(criterion, totalCount); 17 | } 18 | 19 | public static double GetTotalPages(this Criterion criterion, int totalCount) 20 | { 21 | return Math.Ceiling(totalCount / (double)criterion.PageSize); 22 | } 23 | 24 | public static bool HasQuery(this Criterion criterion) 25 | { 26 | return !string.IsNullOrEmpty(criterion.SortBy); 27 | } 28 | 29 | public static bool IsDescending(this Criterion criterion) 30 | { 31 | if (!string.IsNullOrEmpty(criterion.SortOrder)) 32 | return criterion.SortOrder.Split(' ').Last().ToLowerInvariant().StartsWith("desc"); 33 | return false; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /samples/TodoApi/App_Build/k8s/todolist-dep.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: todolist-v1 5 | namespace: netcorekit 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: todolist 12 | version: v1 13 | spec: 14 | containers: 15 | - name: todolist 16 | image: vndg/todo-api:latest 17 | imagePullPolicy: IfNotPresent 18 | env: 19 | - name: Hosts__BasePath 20 | value: / 21 | - name: MySqlDb__FQDN 22 | value: "mysql.netcorekit:3306" 23 | - name: MySqlDb__Password 24 | valueFrom: 25 | secretKeyRef: 26 | name: todolist-secrets 27 | key: MySqlDbPassword 28 | - name: Kafka__FQDN 29 | value: "kafka-cp-kafka.kafka:9092" 30 | - name: Redis__FQDN 31 | value: "redis-master.redis:6379" 32 | - name: Redis__Password 33 | valueFrom: 34 | secretKeyRef: 35 | name: todolist-secrets 36 | key: RedisPassword 37 | ports: 38 | - containerPort: 80 39 | livenessProbe: 40 | httpGet: 41 | path: /healthz 42 | port: 80 43 | initialDelaySeconds: 15 44 | periodSeconds: 10 45 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Redis/NetCoreKit.Infrastructure.Bus.Redis.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.Bus.Redis 7 | 0.0.0 8 | NetCoreKit.Infrastructure.Bus.Redis 9 | NetCoreKit.Infrastructure.Bus.Redis 10 | The redis bus infrastructure library for Cloud Native .NET Core Kit. 11 | Supports Redis Bus for NetCoreKit.Infrastructure.Bus. 12 | netstandard2.0 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.MySql/DbContextOptionsBuilderFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.Options; 4 | using NetCoreKit.Infrastructure.EfCore.Db; 5 | 6 | namespace NetCoreKit.Infrastructure.EfCore.MySql 7 | { 8 | public sealed class DbContextOptionsBuilderFactory : IExtendDbContextOptionsBuilder 9 | { 10 | private readonly DbOptions _options; 11 | 12 | public DbContextOptionsBuilderFactory(IOptions options) 13 | { 14 | _options = options.Value ?? new DbOptions(); 15 | } 16 | 17 | public DbContextOptionsBuilder Extend( 18 | DbContextOptionsBuilder optionsBuilder, 19 | IDbConnStringFactory connStringFactory, 20 | string assemblyName) 21 | { 22 | return optionsBuilder.UseMySql( 23 | connStringFactory.Create(), 24 | sqlOptions => 25 | { 26 | sqlOptions.MigrationsAssembly(assemblyName); 27 | sqlOptions.ServerVersion(_options.DbInfo); 28 | sqlOptions.EnableRetryOnFailure(15, TimeSpan.FromSeconds(30), null); 29 | }) 30 | .EnableSensitiveDataLogging(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.CleanArch/UnitOfWorkBehavior.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MediatR; 4 | using NetCoreKit.Domain; 5 | 6 | namespace NetCoreKit.Infrastructure.AspNetCore.CleanArch 7 | { 8 | /// 9 | /// Source at 10 | /// https://jimmybogard.com/life-beyond-distributed-transactions-an-apostates-implementation-dispatching-example 11 | /// 12 | /// 13 | /// 14 | public class UnitOfWorkBehavior : IPipelineBehavior 15 | { 16 | private readonly IUnitOfWorkAsync _unitOfWork; 17 | 18 | public UnitOfWorkBehavior(IUnitOfWorkAsync unitOfWork) 19 | { 20 | _unitOfWork = unitOfWork; 21 | } 22 | 23 | public async Task Handle( 24 | TRequest request, 25 | CancellationToken cancellationToken, 26 | RequestHandlerDelegate next) 27 | { 28 | using (_unitOfWork) 29 | { 30 | var response = await next(); 31 | 32 | await _unitOfWork.SaveChangesAsync(cancellationToken); 33 | 34 | return response; 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus/NetCoreKit.Infrastructure.Bus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.Bus 7 | 0.0.0 8 | NetCoreKit.Infrastructure.Bus 9 | NetCoreKit.Infrastructure.Bus 10 | The bus infrastructure library for Cloud Native .NET Core Kit. 11 | Supports a very abstraction of the in-memory and utilities for working with the bus. 12 | netstandard2.0 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/Services/HostedService.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Hosting; 4 | 5 | namespace NetCoreKit.Samples.SignalRNotifier.Services 6 | { 7 | /// 8 | /// Source: https://github.com/elucidsoft/aspnetcore-Vue-starter-signalR/blob/master/Services/HostedService.cs 9 | /// 10 | public abstract class HostedService : IHostedService 11 | { 12 | private CancellationTokenSource _cts; 13 | private Task _executingTask; 14 | 15 | public Task StartAsync(CancellationToken cancellationToken) 16 | { 17 | _cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); 18 | 19 | _executingTask = ExecuteAsync(_cts.Token); 20 | 21 | return _executingTask.IsCompleted ? _executingTask : Task.CompletedTask; 22 | } 23 | 24 | public async Task StopAsync(CancellationToken cancellationToken) 25 | { 26 | if (_executingTask == null) return; 27 | 28 | _cts.Cancel(); 29 | 30 | await Task.WhenAny(_executingTask, Task.Delay(-1, cancellationToken)); 31 | 32 | cancellationToken.ThrowIfCancellationRequested(); 33 | } 34 | 35 | protected abstract Task ExecuteAsync(CancellationToken cancellationToken); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/Entity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.ComponentModel.DataAnnotations; 3 | using static NetCoreKit.Utils.Helpers.IdHelper; 4 | using static NetCoreKit.Utils.Helpers.DateTimeHelper; 5 | 6 | namespace NetCoreKit.Domain 7 | { 8 | public interface IEntity : IEntityWithId 9 | { 10 | } 11 | 12 | /// 13 | /// 14 | /// Supertype for all Entity types 15 | /// 16 | public interface IEntityWithId : IIdentityWithId 17 | { 18 | } 19 | 20 | public abstract class EntityBase : EntityWithIdBase 21 | { 22 | protected EntityBase() : base(GenerateId()) 23 | { 24 | } 25 | 26 | protected EntityBase(Guid id) : base(id) 27 | { 28 | } 29 | } 30 | 31 | /// 32 | /// 33 | /// Source: https://github.com/VaughnVernon/IDDD_Samples_NET 34 | /// 35 | public abstract class EntityWithIdBase : IEntityWithId 36 | { 37 | protected EntityWithIdBase(TId id) 38 | { 39 | Id = id; 40 | Created = GenerateDateTime(); 41 | } 42 | 43 | public DateTime Created { get; protected set; } 44 | 45 | public DateTime Updated { get; protected set; } 46 | 47 | [Key] public TId Id { get; protected set; } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.SqlServer/DatabaseConnectionStringFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.Extensions.Configuration; 4 | using NetCoreKit.Infrastructure.EfCore.Db; 5 | 6 | namespace NetCoreKit.Infrastructure.EfCore.SqlServer 7 | { 8 | public sealed class DbConnStringFactory : IDbConnStringFactory 9 | { 10 | private readonly IConfiguration _config; 11 | private readonly IHostingEnvironment _env; 12 | 13 | public DbConnStringFactory( 14 | IConfiguration config, 15 | IHostingEnvironment env) 16 | { 17 | _config = config; 18 | _env = env; 19 | } 20 | 21 | public string Create() 22 | { 23 | if (_env.IsDevelopment()) return _config.GetConnectionString("mssqldb"); 24 | 25 | return string.Format( 26 | _config.GetConnectionString("mssqldb"), 27 | Environment.GetEnvironmentVariable(_config.GetValue("k8s:mssqldb:Host")), 28 | Environment.GetEnvironmentVariable(_config.GetValue("k8s:mssqldb:Port")), 29 | _config.GetValue("k8s:mssqldb:Database"), 30 | _config.GetValue("k8s:mssqldb:UserName"), 31 | _config.GetValue("k8s:mssqldb:Password")); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /samples/SignalRNotifier/NetCoreKit.Samples.SignalRNotifier.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/GetTasks/RequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | using NetCoreKit.Domain; 6 | using NetCoreKit.Infrastructure.AspNetCore.CleanArch; 7 | using NetCoreKit.Infrastructure.EfCore.Extensions; 8 | using NetCoreKit.Samples.TodoAPI.Extensions; 9 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Db; 10 | 11 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.GetTasks 12 | { 13 | public class RequestHandler : RequestHandlerBase 14 | { 15 | public RequestHandler(IQueryRepositoryFactory queryRepositoryFactory) 16 | : base(queryRepositoryFactory) 17 | { 18 | } 19 | 20 | public override async Task Handle(GetTasksRequest request, 21 | CancellationToken cancellationToken) 22 | { 23 | var queryRepository = QueryFactory.QueryRepository(); 24 | 25 | var result = await queryRepository.GetByIdAsync(request.ProjectId, q => q.Include(x => x.Tasks)); 26 | if (result == null) throw new Exception($"Couldn't find project#{request.ProjectId}."); 27 | 28 | return new GetTasksResponse 29 | { 30 | Result = result.ToDto() 31 | }; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/Mappers/AutoMapperProfileExtension.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using MediatR; 3 | using NetCoreKit.Domain; 4 | 5 | namespace NetCoreKit.Infrastructure.Mappers 6 | { 7 | public static class AutoMapperProfileExtension 8 | { 9 | public static Profile MapMySelf(this Profile profile) where TEvent : IEvent 10 | { 11 | profile.CreateMap(typeof(TEvent), typeof(TEvent)).ReverseMap(); 12 | return profile; 13 | } 14 | 15 | public static Profile MapTo(this Profile profile) 16 | { 17 | profile.CreateMap(typeof(TSource), typeof(TDestination)).ReverseMap(); 18 | return profile; 19 | } 20 | 21 | public static Profile MapToNotification(this Profile profile) 22 | { 23 | // Source: https://stackoverflow.com/questions/13075588/configure-automapper-to-map-to-concrete-types-but-allow-interfaces-in-the-defini/13075915 24 | profile.CreateMap(typeof(TSource), typeof(TDestination)); 25 | profile.CreateMap(typeof(TSource), typeof(INotification)).As(typeof(TDestination)); 26 | return profile; 27 | } 28 | 29 | public static TDestination MapTo(this TSource request) 30 | { 31 | return Mapper.Map(request); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/NetCoreKit.Infrastructure.EfCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.EfCore 7 | 0.0.0 8 | The EfCore library for Cloud Native .NET Core Kit. 9 | Helps to add Generic Repository and Unit of Work defaults for a service. 10 | netstandard2.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/WebNotifier/Pages/FetchData.cshtml: -------------------------------------------------------------------------------- 1 | @page "/fetchdata" 2 | @inject HttpClient Http 3 | 4 |

Weather forecast

5 | 6 |

This component demonstrates fetching data from the server.

7 | 8 | @if (forecasts == null) 9 | { 10 |

Loading...

11 | } 12 | else 13 | { 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | @foreach (var forecast in forecasts) 25 | { 26 | 27 | 28 | 29 | 30 | 31 | 32 | } 33 | 34 |
DateTemp. (C)Temp. (F)Summary
@forecast.Date.ToShortDateString()@forecast.TemperatureC@forecast.TemperatureF@forecast.Summary
35 | } 36 | 37 | @functions { 38 | WeatherForecast[] forecasts; 39 | 40 | protected override async Task OnInitAsync() 41 | { 42 | forecasts = await Http.GetJsonAsync("sample-data/weather.json"); 43 | } 44 | 45 | class WeatherForecast 46 | { 47 | public DateTime Date { get; set; } 48 | public int TemperatureC { get; set; } 49 | public int TemperatureF { get; set; } 50 | public string Summary { get; set; } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Rest/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Net.Http; 4 | using Microsoft.Extensions.DependencyInjection; 5 | using Polly; 6 | using Polly.Extensions.Http; 7 | 8 | namespace NetCoreKit.Infrastructure.AspNetCore.Rest 9 | { 10 | public static class ServiceCollectionExtensions 11 | { 12 | public static IServiceCollection AddHttpPolly(this IServiceCollection services) 13 | where TRestClient : class 14 | { 15 | services.AddHttpClient() 16 | .SetHandlerLifetime(TimeSpan.FromMinutes(1)) 17 | .AddPolicyHandler(GetRetryPolicy()) 18 | .AddPolicyHandler(GetCircuitBreakerPolicy()); 19 | 20 | return services; 21 | } 22 | 23 | private static IAsyncPolicy GetRetryPolicy() 24 | { 25 | return HttpPolicyExtensions 26 | .HandleTransientHttpError() 27 | .OrResult(msg => msg.StatusCode == HttpStatusCode.NotFound) 28 | .WaitAndRetryAsync(3, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))); 29 | } 30 | 31 | private static IAsyncPolicy GetCircuitBreakerPolicy() 32 | { 33 | return HttpPolicyExtensions 34 | .HandleTransientHttpError() 35 | .CircuitBreakerAsync(5, TimeSpan.FromSeconds(30)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/Event.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using static NetCoreKit.Utils.Helpers.DateTimeHelper; 5 | 6 | namespace NetCoreKit.Domain 7 | { 8 | /// 9 | /// Supertype for all Event types 10 | /// 11 | public interface IEvent 12 | { 13 | int EventVersion { get; } 14 | DateTime OccurredOn { get; } 15 | } 16 | 17 | public interface IEventHandler 18 | where TEvent : IEvent 19 | { 20 | Task Handle(TEvent request, CancellationToken cancellationToken); 21 | } 22 | 23 | public interface IDomainEventDispatcher : IDisposable 24 | { 25 | Task Dispatch(IEvent @event); 26 | } 27 | 28 | public abstract class EventBase : IEvent 29 | { 30 | public int EventVersion { get; protected set; } = 1; 31 | public DateTime OccurredOn { get; protected set; } = GenerateDateTime(); 32 | } 33 | 34 | public class EventEnvelope : EventBase 35 | { 36 | public EventEnvelope(IEvent @event) 37 | { 38 | Event = @event; 39 | } 40 | 41 | public IEvent Event { get; } 42 | } 43 | 44 | public class MemoryDomainEventDispatcher : IDomainEventDispatcher 45 | { 46 | public void Dispose() 47 | { 48 | } 49 | 50 | public Task Dispatch(IEvent @event) 51 | { 52 | return Task.CompletedTask; 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/NetCoreKit.Infrastructure.AspNetCore.OpenApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.AspNetCore.OpenApi 7 | 0.0.0 8 | The OpenApi library for Cloud Native .NET Core Kit. 9 | Helps to attach the default Swagger and SwaggerUI for a service. 10 | netstandard2.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/Mappers/ProjectProfile.cs: -------------------------------------------------------------------------------- 1 | using AutoMapper; 2 | using Google.Protobuf.WellKnownTypes; 3 | using NetCoreKit.Samples.Contracts.TodoApi.v1.Grpc; 4 | using NetCoreKit.Samples.TodoAPI.Domain; 5 | 6 | namespace NetCoreKit.Samples.TodoApi.v1.Mappers 7 | { 8 | public class ProjectProfile : Profile 9 | { 10 | public ProjectProfile() 11 | { 12 | CreateMap() 13 | .ForMember( 14 | x => x.Key, 15 | conf => conf.MapFrom(cg => cg.GetType().Name)) 16 | .ForMember( 17 | x => x.Id, 18 | conf => conf.MapFrom(cg => cg.Id.ToString())) 19 | .ForMember( 20 | x => x.OccurredOn, 21 | conf => conf.MapFrom(cg => Timestamp.FromDateTime(cg.OccurredOn))); 22 | 23 | CreateMap() 24 | .ForMember( 25 | x => x.Key, 26 | conf => conf.MapFrom(cg => cg.GetType().Name)) 27 | .ForMember( 28 | x => x.Id, 29 | conf => conf.MapFrom(cg => cg.Id.ToString())) 30 | .ForMember( 31 | x => x.ProjectId, 32 | conf => conf.MapFrom(cg => cg.ProjectId.ToString())) 33 | .ForMember( 34 | x => x.OccurredOn, 35 | conf => conf.MapFrom(cg => Timestamp.FromDateTime(cg.OccurredOn))); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/ClearTasks/RequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | using NetCoreKit.Domain; 6 | using NetCoreKit.Infrastructure.AspNetCore.CleanArch; 7 | using NetCoreKit.Infrastructure.EfCore.Extensions; 8 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Db; 9 | 10 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.ClearTasks 11 | { 12 | public class RequestHandler : TxRequestHandlerBase 13 | { 14 | public RequestHandler(IUnitOfWorkAsync uow, IQueryRepositoryFactory queryRepositoryFactory) 15 | : base(uow, queryRepositoryFactory) 16 | { 17 | } 18 | 19 | public override async Task Handle(ClearTasksRequest request, 20 | CancellationToken cancellationToken) 21 | { 22 | var projectRepository = CommandFactory.RepositoryAsync(); 23 | var queryRepository = QueryFactory.QueryRepository(); 24 | 25 | var project = 26 | await queryRepository.GetByIdAsync(request.ProjectId, q => q.Include(x => x.Tasks), false); 27 | if (project == null) 28 | throw new Exception($"Couldn't found the project#{request.ProjectId}."); 29 | 30 | project.ClearTasks(); 31 | await projectRepository.UpdateAsync(project); 32 | 33 | return new ClearTasksResponse(); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/DeleteTask/RequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | using NetCoreKit.Domain; 6 | using NetCoreKit.Infrastructure.AspNetCore.CleanArch; 7 | using NetCoreKit.Infrastructure.EfCore.Extensions; 8 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Db; 9 | 10 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.DeleteTask 11 | { 12 | public class RequestHandler : TxRequestHandlerBase 13 | { 14 | public RequestHandler(IUnitOfWorkAsync uow, IQueryRepositoryFactory queryRepositoryFactory) 15 | : base(uow, queryRepositoryFactory) 16 | { 17 | } 18 | 19 | public override async Task Handle(DeleteTaskRequest request, 20 | CancellationToken cancellationToken) 21 | { 22 | var projectRepository = CommandFactory.RepositoryAsync(); 23 | var queryRepository = QueryFactory.QueryRepository(); 24 | 25 | var project = await queryRepository.GetByIdAsync(request.ProjectId, q => q.Include(x => x.Tasks), false); 26 | if (project == null) throw new Exception($"Couldn't find the project#{request.ProjectId}."); 27 | 28 | project.RemoveTask(request.TaskId); 29 | var result = await projectRepository.UpdateAsync(project); 30 | 31 | return new DeleteTaskResponse {Result = result.Id}; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /samples/WebNotifier/Shared/NavMenu.cshtml: -------------------------------------------------------------------------------- 1 | 7 | 8 |
9 | 31 |
32 | 33 | @functions { 34 | bool collapseNavMenu = true; 35 | 36 | void ToggleNavMenu() 37 | { 38 | collapseNavMenu = !collapseNavMenu; 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/PubSub/KafkaNotifPublisher.cs: -------------------------------------------------------------------------------- 1 | /*using System.Threading; 2 | using MediatR; 3 | using Microsoft.Extensions.Logging; 4 | using NetCoreKit.Infrastructure.Bus; 5 | using NetCoreKit.Infrastructure.Bus.Kafka; 6 | using NetCoreKit.Infrastructure.Mappers; 7 | using NetCoreKit.Samples.TodoAPI.Domain; 8 | using Project.Proto; 9 | using Task = System.Threading.Tasks.Task; 10 | 11 | namespace NetCoreKit.Samples.TodoAPI.v1.Services 12 | { 13 | public class KafkaNotificationPublisher : INotificationHandler 14 | { 15 | private readonly IDispatchedEventBus _eventBus; 16 | private readonly ILogger _logger; 17 | 18 | public KafkaNotificationPublisher(IDispatchedEventBus eventBus, ILoggerFactory loggerFactory) 19 | { 20 | _eventBus = eventBus; 21 | _logger = loggerFactory.CreateLogger(); 22 | } 23 | 24 | public async Task Handle(NotificationEnvelope notify, CancellationToken cancellationToken) 25 | { 26 | if (notify.Event is ProjectCreated created) 27 | { 28 | _logger.LogInformation("[NCK] Start to publish ProjectCreatedMsg."); 29 | await _eventBus.Dispatch(created.MapTo(), "project-created"); 30 | } 31 | else if(notify.Event is TaskCreated taskCreated) 32 | { 33 | _logger.LogInformation("[NCK] Start to publish TaskCreatedMsg."); 34 | await _eventBus.Dispatch(taskCreated.MapTo(), "task-created"); 35 | } 36 | } 37 | } 38 | } */ 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/AuthorizeCheckOperationFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Swashbuckle.AspNetCore.Swagger; 5 | using Swashbuckle.AspNetCore.SwaggerGen; 6 | 7 | namespace NetCoreKit.Infrastructure.AspNetCore.OpenApi 8 | { 9 | public class AuthorizeCheckOperationFilter : IOperationFilter 10 | { 11 | public void Apply(Operation operation, OperationFilterContext context) 12 | { 13 | // Check for authorize attribute 14 | context.ApiDescription.TryGetMethodInfo(out var methodInfo); 15 | var requiredScopes = methodInfo.GetCustomAttributes(true).OfType(); 16 | 17 | /*var hasAuthorize = context.ApiDescription.ControllerAttributes().OfType().Any() || 18 | context.ApiDescription.ActionAttributes().OfType().Any();*/ 19 | 20 | var hasAuthorize = requiredScopes.Any(); 21 | if (!hasAuthorize) return; 22 | 23 | operation.Responses.Add("401", new Response {Description = "Unauthorized"}); 24 | operation.Responses.Add("403", new Response {Description = "Forbidden"}); 25 | 26 | operation.Security = new List>> 27 | { 28 | new Dictionary> 29 | { 30 | ["oauth2"] = new[] {"swagger_id"} 31 | } 32 | }; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Kafka/NetCoreKit.Infrastructure.Bus.Kafka.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure.Bus.Kafka 7 | 0.0.0 8 | NetCoreKit.Infrastructure.Bus.Kafka 9 | NetCoreKit.Infrastructure.Bus.Kafka 10 | The kafka bus infrastructure library for Cloud Native .NET Core Kit. 11 | Supports Kafka Bus for NetCoreKit.Infrastructure.Bus. 12 | netstandard2.0 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/Extensions/UnitOfWorkExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using Microsoft.EntityFrameworkCore; 4 | using NetCoreKit.Domain; 5 | 6 | namespace NetCoreKit.Infrastructure.EfCore.Extensions 7 | { 8 | public static class EfUnitOfWorkExtensions 9 | { 10 | public static int? GetCommandTimeout(this IUnitOfWorkAsync uow, DbContext context) 11 | { 12 | return context.Database.GetCommandTimeout(); 13 | } 14 | 15 | public static IUnitOfWorkAsync SetCommandTimeout(this IUnitOfWorkAsync uow, DbContext context, int? value) 16 | { 17 | context.Database.SetCommandTimeout(value); 18 | return uow; 19 | } 20 | 21 | public static int ExecuteSqlCommand(this IUnitOfWorkAsync uow, DbContext context, string sql, 22 | params object[] parameters) 23 | { 24 | return context.Database.ExecuteSqlCommand(sql, parameters); 25 | } 26 | 27 | public static async Task ExecuteSqlCommandAsync(this IUnitOfWorkAsync uow, DbContext context, string sql, 28 | params object[] parameters) 29 | { 30 | return await context.Database.ExecuteSqlCommandAsync(sql, parameters); 31 | } 32 | 33 | public static async Task ExecuteSqlCommandAsync(this IUnitOfWorkAsync uow, DbContext context, string sql, 34 | CancellationToken cancellationToken, params object[] parameters) 35 | { 36 | return await context.Database.ExecuteSqlCommandAsync(sql, cancellationToken, parameters); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using NetCoreKit.Domain; 4 | using NetCoreKit.Infrastructure.EfCore.Db; 5 | 6 | namespace NetCoreKit.Infrastructure.EfCore 7 | { 8 | public static class ServiceCollectionExtensions 9 | { 10 | public static IServiceCollection AddGenericRepository(this IServiceCollection services) 11 | { 12 | services.AddScoped(); 13 | services.AddScoped(); 14 | return services; 15 | } 16 | 17 | public static IServiceCollection AddInMemoryDb(this IServiceCollection services) 18 | { 19 | services.AddScoped(); 20 | services.AddScoped(); 21 | return services; 22 | } 23 | } 24 | 25 | internal class NoOpDbConnStringFactory : IDbConnStringFactory 26 | { 27 | public string Create() 28 | { 29 | return string.Empty; 30 | } 31 | } 32 | 33 | internal class InMemoryDbContextOptionsBuilderFactory : IExtendDbContextOptionsBuilder 34 | { 35 | public DbContextOptionsBuilder Extend( 36 | DbContextOptionsBuilder optionsBuilder, 37 | IDbConnStringFactory connStringFactory, 38 | string assemblyName) 39 | { 40 | return optionsBuilder.UseInMemoryDatabase("default_db"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.EfCore.MySql/DatabaseConnectionStringFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Microsoft.Extensions.Options; 3 | using NetCoreKit.Infrastructure.EfCore.Db; 4 | 5 | namespace NetCoreKit.Infrastructure.EfCore.MySql 6 | { 7 | public sealed class DbConnStringFactory : IDbConnStringFactory 8 | { 9 | public DbOptions DbOptions { get; } 10 | 11 | public DbConnStringFactory() 12 | { 13 | var config = ConfigurationHelper.GetConfiguration(); 14 | var dbSection = config.GetSection("Features:EfCore:MySqlDb"); 15 | DbOptions = new DbOptions { 16 | ConnString = dbSection["ConnString"], 17 | FQDN = dbSection["FQDN"], 18 | Database = dbSection["Database"], 19 | DbInfo = dbSection["DbInfo"], 20 | UserName = dbSection["UserName"], 21 | Password = dbSection["Password"] 22 | }; 23 | } 24 | 25 | public DbConnStringFactory(IOptions options) 26 | { 27 | DbOptions = options.Value; 28 | } 29 | 30 | public string Create() 31 | { 32 | var connPattern = DbOptions.ConnString; 33 | var connConfigs = DbOptions.FQDN?.Split(':'); 34 | var fqdn = connConfigs?.First(); 35 | var port = connConfigs?.Except(new[] {fqdn}).First(); 36 | 37 | return string.Format( 38 | connPattern, 39 | fqdn, port, 40 | DbOptions.UserName, 41 | DbOptions.Password, 42 | DbOptions.Database); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_VERSION": "1.0", 3 | "SERVICE_VERSION": "0.0.1", 4 | "QualifiedAssemblyPattern": "NetCoreKit.Samples.*", 5 | "Hosts": { 6 | "BasePath": "/", 7 | "Externals": { 8 | "CurrentUri": "http://localhost:54408" 9 | } 10 | }, 11 | "Features": { 12 | "Mongo": { 13 | "ConnString": "mongodb://127.0.0.1:27017", 14 | "Database": "BiMonetaryApi" 15 | }, 16 | "ApiVersion": { "Enabled": true }, 17 | "OpenApi": { 18 | "OpenApiUI": { "Enabled": true }, 19 | "ApiInfo": { 20 | "Title": "BiMonetary API", 21 | "Description": "An application with Swagger, Swashbuckle, and API version.", 22 | "ContactName": "Vietnam Devs", 23 | "ContactEmail": "thangchung.onthenet@gmail.com", 24 | "TermOfService": "Shareware", 25 | "LicenseName": "MIT", 26 | "LicenseUrl": "https://github.com/cloudnative-netcore/netcorekit/blob/master/LICENSE" 27 | } 28 | }, 29 | "AuthN": { 30 | "ClaimToScopeMap": { "access_cart_api": "cart_api_scope" }, 31 | "Scopes": { "cart_api_scope": "Cart APIs" }, 32 | "Audience": "api" 33 | }, 34 | "ResponseCompression": { "Enabled": true } 35 | }, 36 | "RpcClients": { 37 | "ExchangeService": "localhost:5000" 38 | }, 39 | "Logging": { 40 | "IncludeScopes": false, 41 | "Debug": { 42 | "LogLevel": { 43 | "Default": "Information" 44 | } 45 | }, 46 | "Console": { 47 | "LogLevel": { 48 | "Default": "Debug", 49 | "System": "Information", 50 | "Microsoft": "Information" 51 | } 52 | } 53 | }, 54 | "AllowedHosts": "*" 55 | } 56 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/UpdateTask/RequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | using NetCoreKit.Domain; 6 | using NetCoreKit.Infrastructure.AspNetCore.CleanArch; 7 | using NetCoreKit.Infrastructure.EfCore.Extensions; 8 | using NetCoreKit.Samples.TodoAPI.Extensions; 9 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Db; 10 | 11 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.UpdateTask 12 | { 13 | public class RequestHandler : TxRequestHandlerBase 14 | { 15 | public RequestHandler(IUnitOfWorkAsync uow, IQueryRepositoryFactory queryRepositoryFactory) 16 | : base(uow, queryRepositoryFactory) 17 | { 18 | } 19 | 20 | public override async Task Handle(UpdateTaskRequest request, 21 | CancellationToken cancellationToken) 22 | { 23 | var commandRepository = CommandFactory.RepositoryAsync(); 24 | var queryRepository = QueryFactory.QueryRepository(); 25 | 26 | var project = await queryRepository.GetByIdAsync(request.ProjectId, q => q.Include(x => x.Tasks), false); 27 | if (project == null) throw new Exception($"Couldn't find project#{request.ProjectId}."); 28 | 29 | project.UpdateTask(request.TaskId, request.Title, request.Order ?? 1, request.Completed ?? false); 30 | var updated = await commandRepository.UpdateAsync(project); 31 | 32 | return new UpdateTaskResponse {Result = updated.ToDto()}; 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/SecurityRequirementsOperationFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using Microsoft.AspNetCore.Authorization; 4 | using Swashbuckle.AspNetCore.Swagger; 5 | using Swashbuckle.AspNetCore.SwaggerGen; 6 | 7 | namespace NetCoreKit.Infrastructure.AspNetCore.OpenApi 8 | { 9 | public class SecurityRequirementsOperationFilter : IOperationFilter 10 | { 11 | public void Apply(Operation operation, OperationFilterContext context) 12 | { 13 | // Policy names map to scopes 14 | /*var requiredScopes = context.MethodInfo 15 | .GetCustomAttributes(true) 16 | .OfType() 17 | .Select(attr => attr.Policy) 18 | .Distinct();*/ 19 | 20 | var requiredScopes = context.MethodInfo.DeclaringType 21 | ?.GetCustomAttributes(true) 22 | .Union(context.MethodInfo.GetCustomAttributes(true)) 23 | .OfType() 24 | .ToList(); 25 | 26 | if (requiredScopes == null || !requiredScopes.Any()) return; 27 | 28 | operation.Responses.Add("401", new Response {Description = "Unauthorized"}); 29 | operation.Responses.Add("403", new Response {Description = "Forbidden"}); 30 | 31 | operation.Security = new List>> 32 | { 33 | new Dictionary> 34 | { 35 | ["oauth2"] = requiredScopes.Select(attr => attr.Policy).Distinct() 36 | } 37 | }; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /samples/TodoApi/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "API_VERSION": "1.0", 3 | "SERVICE_VERSION": "0.0.1", 4 | "QualifiedAssemblyPattern": "NetCoreKit.Samples.*", 5 | "Hosts": { 6 | "BasePath": "/", 7 | "Externals": { 8 | "CurrentUri": "http://localhost:32501" 9 | } 10 | }, 11 | "Features": { 12 | "EfCore": { 13 | //"SqlServerConnString": "Server=tcp:{0},{1};Database={2};User Id={3};Password={4};" 14 | "MySqlDb": { 15 | "Database": "maindb", 16 | "UserName": "root", 17 | "Password": "letmein", 18 | "DbInfo": "5.7.14-mysql", 19 | "ConnString": "server={0};port={1};uid={2};pwd={3};database={4}" 20 | } 21 | }, 22 | "CleanArch": { "Enabled": true }, 23 | "ApiVersion": { "Enabled": true }, 24 | "OpenApi": { 25 | "OpenApiUI": { "Enabled": true }, 26 | "Profiler": { "Enabled": true }, 27 | "ApiInfo": { 28 | "Title": "Todo APIs", 29 | "Description": "An application with Swagger, Swashbuckle, and API versioning.", 30 | "ContactName": "Vietnam Devs", 31 | "ContactEmail": "thangchung.onthenet@gmail.com", 32 | "TermOfService": "Shareware", 33 | "LicenseName": "MIT", 34 | "LicenseUrl": "https://github.com/cloudnative-netcore/netcorekit/blob/master/LICENSE" 35 | } 36 | } 37 | }, 38 | "Logging": { 39 | "IncludeScopes": false, 40 | "Debug": { 41 | "LogLevel": { 42 | "Default": "Warning" 43 | } 44 | }, 45 | "Console": { 46 | "LogLevel": { 47 | "Default": "Debug", 48 | "System": "Information", 49 | "Microsoft": "Information" 50 | } 51 | } 52 | }, 53 | "AllowedHosts": "*" 54 | } 55 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/ValueObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using NetCoreKit.Utils.Extensions; 4 | 5 | namespace NetCoreKit.Domain 6 | { 7 | /// 8 | /// Source: https://github.com/VaughnVernon/IDDD_Samples_NET 9 | /// 10 | public abstract class ValueObjectBase 11 | { 12 | protected abstract IEnumerable GetEqualityComponents(); 13 | 14 | public override bool Equals(object obj) 15 | { 16 | if (ReferenceEquals(this, obj)) return true; 17 | if (ReferenceEquals(null, obj)) return false; 18 | if (GetType() != obj.GetType()) return false; 19 | var vo = obj as ValueObjectBase; 20 | return GetEqualityComponents().SequenceEqual(vo.GetEqualityComponents()); 21 | } 22 | 23 | public override int GetHashCode() 24 | { 25 | return GetEqualityComponents().CombineHashCodes(); 26 | } 27 | } 28 | 29 | public class PaginatedItem : ValueObjectBase 30 | { 31 | public PaginatedItem(long totalItems, long totalPages, IReadOnlyList items) 32 | { 33 | TotalItems = totalItems; 34 | TotalPages = totalPages; 35 | Items = items; 36 | } 37 | 38 | public long TotalItems { get; } 39 | 40 | public long TotalPages { get; } 41 | 42 | public IReadOnlyList Items { get; } 43 | 44 | protected override IEnumerable GetEqualityComponents() 45 | { 46 | yield return TotalItems; 47 | yield return TotalPages; 48 | yield return Items; 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /samples/BiMonetaryApi/NetCoreKit.Samples.BiMonetaryApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | inprocess 6 | 7 | 8 | 9 | 10 | 11 | 12 | all 13 | runtime; build; native; contentfiles; analyzers 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /samples/_deploys/kafka-topics-ui/kafka-topics-ui.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: extensions/v1beta1 2 | kind: Deployment 3 | metadata: 4 | name: kafka-topics-ui-v1 5 | namespace: kafka 6 | spec: 7 | replicas: 1 8 | template: 9 | metadata: 10 | labels: 11 | app: kafka-topics-ui 12 | version: v1 13 | spec: 14 | containers: 15 | - name: kafka-topics-ui 16 | image: landoop/kafka-topics-ui:0.9.4 17 | imagePullPolicy: IfNotPresent 18 | env: 19 | - name: ACCESS_CONTROL_ALLOW_ORIGIN_DEFAULT 20 | value: "*" 21 | - name: ACCESS_CONTROL_ALLOW_METHODS_DEFAULT 22 | value: "GET,POST,PUT,DELETE,OPTIONS" 23 | - name: ACCESS_CONTROL_ALLOW_ORIGIN 24 | value: "*" 25 | - name: ACCESS_CONTROL_ALLOW_METHODS 26 | value: "GET,POST,PUT,DELETE,OPTIONS" 27 | - name: KAFKA_REST_BOOTSTRAP_SERVERS 28 | value: "PLAINTEXT://kafka-cp-kafka:9092" 29 | - name: KAFKA_REST_PROXY_URL 30 | value: http://kafka-cp-kafka-rest:8082 31 | - name: SCHEMAREGISTRY_UI_URL 32 | value: http://kafka-cp-schema-registry:8081 33 | - name: PROXY 34 | value: "true" 35 | ports: 36 | - containerPort: 8000 37 | resources: 38 | requests: 39 | memory: "64Mi" 40 | cpu: "250m" 41 | limits: 42 | memory: "128Mi" 43 | cpu: "500m" 44 | --- 45 | apiVersion: v1 46 | kind: Service 47 | metadata: 48 | name: kafka-topics-ui 49 | namespace: kafka 50 | labels: 51 | app: kafka-topics-ui 52 | spec: 53 | ports: 54 | - port: 8000 55 | targetPort: redis-commander 56 | protocol: TCP 57 | name: http 58 | type: LoadBalancer 59 | selector: 60 | app: kafka-topics-ui -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Bus.Kafka/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace NetCoreKit.Infrastructure.Bus.Kafka 6 | { 7 | public static class ServiceCollectionExtensions 8 | { 9 | public static IServiceCollection AddKafkaEventBus(this IServiceCollection services) 10 | { 11 | var resolver = services.BuildServiceProvider(); 12 | using (var scope = resolver.CreateScope()) 13 | { 14 | var config = scope.ServiceProvider.GetService(); 15 | var env = scope.ServiceProvider.GetService(); 16 | var kafkaOptions = config.GetSection("Features:Kafka"); 17 | //if (env.IsDevelopment()) 18 | { 19 | services.Configure(o => { o.Fqdn = kafkaOptions.GetValue("FQDN"); }); 20 | } 21 | /*else 22 | { 23 | var serviceName = kafkaOptions 24 | .GetValue("ServiceName", "kafka") 25 | .Replace("-", "_") 26 | .ToUpperInvariant(); 27 | 28 | var ip = Environment.GetEnvironmentVariable($"{serviceName}_SERVICE_HOST"); 29 | var port = Environment.GetEnvironmentVariable($"{serviceName}_SERVICE_PORT"); 30 | 31 | services.Configure(o => { o.Fqdn = $"{ip}:{port}"; }); 32 | }*/ 33 | 34 | services.AddSingleton(); 35 | } 36 | 37 | return services; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/NetCoreKit.Infrastructure.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | NetCoreKit.Infrastructure 7 | 0.0.0 8 | NetCoreKit.Infrastructure 9 | NetCoreKit.Infrastructure 10 | The infrastructure library for Cloud Native .NET Core Kit. 11 | Supports base infrastructure in the library. 12 | netstandard2.0 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/PubSub/RedisNotifPublisher.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using MediatR; 3 | using Microsoft.Extensions.Logging; 4 | using NetCoreKit.Infrastructure.Bus; 5 | using NetCoreKit.Infrastructure.Mappers; 6 | using NetCoreKit.Samples.Contracts.TodoApi.v1.Grpc; 7 | using NetCoreKit.Samples.TodoAPI.Domain; 8 | using Task = System.Threading.Tasks.Task; 9 | 10 | namespace NetCoreKit.Samples.TodoApi.v1.PubSub 11 | { 12 | public class RedisNotifPublisher : INotificationHandler 13 | { 14 | private readonly IDispatchedEventBus _dispatchedEventBus; 15 | private readonly ILogger _logger; 16 | 17 | public RedisNotifPublisher(IDispatchedEventBus dispatchedEventBus, ILoggerFactory loggerFactory) 18 | { 19 | _dispatchedEventBus = dispatchedEventBus; 20 | _logger = loggerFactory.CreateLogger(); 21 | } 22 | 23 | public async Task Handle(NotificationEnvelope notify, CancellationToken cancellationToken) 24 | { 25 | switch (notify.Event) 26 | { 27 | case ProjectCreated projectCreated: 28 | _logger.LogInformation("[NCK] Start to publish ProjectCreatedMsg."); 29 | await _dispatchedEventBus.PublishAsync( 30 | projectCreated.MapTo(), 31 | "project-created"); 32 | break; 33 | case TaskCreated taskCreated: 34 | _logger.LogInformation("[NCK] Start to publish TaskCreatedMsg."); 35 | await _dispatchedEventBus.PublishAsync( 36 | taskCreated.MapTo(), 37 | "task-created"); 38 | break; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore/Middlewares/ErrorHandlerMiddleware.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using System.Threading.Tasks; 4 | using Microsoft.AspNetCore.Http; 5 | using Microsoft.EntityFrameworkCore; 6 | using NetCoreKit.Domain; 7 | using Newtonsoft.Json; 8 | 9 | namespace NetCoreKit.Infrastructure.AspNetCore.Middlewares 10 | { 11 | public class ErrorHandlerMiddleware 12 | { 13 | private readonly RequestDelegate _next; 14 | 15 | public ErrorHandlerMiddleware(RequestDelegate next) 16 | { 17 | _next = next; 18 | } 19 | 20 | public async Task Invoke(HttpContext context) 21 | { 22 | try 23 | { 24 | await _next(context); 25 | } 26 | catch (Exception exception) 27 | { 28 | await HandleErrorAsync(context, exception); 29 | } 30 | } 31 | 32 | private static Task HandleErrorAsync(HttpContext context, Exception exception) 33 | { 34 | const string errorCode = "error"; 35 | const HttpStatusCode statusCode = HttpStatusCode.BadRequest; 36 | var message = exception.Message; 37 | switch (exception) 38 | { 39 | case DbUpdateException e: 40 | message = e.InnerException?.Message; 41 | break; 42 | case CoreException e: 43 | break; 44 | } 45 | 46 | var response = new 47 | { 48 | code = errorCode, 49 | message 50 | }; 51 | 52 | var payload = JsonConvert.SerializeObject(response); 53 | context.Response.ContentType = "application/json"; 54 | context.Response.StatusCode = (int)statusCode; 55 | 56 | return context.Response.WriteAsync(payload); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/Identity.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using static NetCoreKit.Utils.Helpers.IdHelper; 3 | 4 | namespace NetCoreKit.Domain 5 | { 6 | /// 7 | /// Supertype for all Identity types 8 | /// 9 | public interface IIdentity 10 | { 11 | Guid Id { get; } 12 | } 13 | 14 | /// 15 | /// Supertype for all Identity types with generic Id 16 | /// 17 | public interface IIdentityWithId 18 | { 19 | TId Id { get; } 20 | } 21 | 22 | public abstract class IdentityBase : IdentityBase, IEquatable>, IIdentityWithId 23 | { 24 | public IdentityBase() : base(GenerateId()) 25 | { 26 | } 27 | } 28 | 29 | /// 30 | /// Source: https://github.com/VaughnVernon/IDDD_Samples_NET 31 | /// 32 | public abstract class IdentityBase : IEquatable>, IIdentityWithId 33 | { 34 | protected IdentityBase(TId id) 35 | { 36 | Id = id; 37 | } 38 | 39 | public bool Equals(IdentityBase id) 40 | { 41 | if (ReferenceEquals(this, id)) 42 | return true; 43 | return !ReferenceEquals(null, id) && Id.Equals(id.Id); 44 | } 45 | 46 | // currently for Entity Framework, set must be protected, not private. 47 | // will be fixed in EF 6. 48 | public TId Id { get; protected set; } 49 | 50 | public override bool Equals(object anotherObject) 51 | { 52 | return Equals(anotherObject as IdentityBase); 53 | } 54 | 55 | public override int GetHashCode() 56 | { 57 | return GetType().GetHashCode() * 907 + Id.GetHashCode(); 58 | } 59 | 60 | public override string ToString() 61 | { 62 | return $"{GetType().Name} [Id={Id}]"; 63 | } 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.Mongo/UnitOfWorkAsync.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Concurrent; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using NetCoreKit.Domain; 6 | 7 | namespace NetCoreKit.Infrastructure.Mongo 8 | { 9 | public class UnitOfWorkAsync : IUnitOfWorkAsync 10 | { 11 | private readonly DbContext _dbContext; 12 | private readonly IDomainEventDispatcher _domainEventDispatcher; 13 | private ConcurrentDictionary _repositories; 14 | 15 | public UnitOfWorkAsync(DbContext dbContext, IDomainEventDispatcher domainEventDispatcher) 16 | { 17 | _dbContext = dbContext; 18 | _domainEventDispatcher = domainEventDispatcher; 19 | } 20 | 21 | public virtual IRepositoryAsync RepositoryAsync() 22 | where TEntity : class, IAggregateRoot 23 | { 24 | if (_repositories == null) _repositories = new ConcurrentDictionary(); 25 | var type = typeof(TEntity); 26 | if (!_repositories.ContainsKey(type)) _repositories[type] = new Repository(_dbContext, _domainEventDispatcher); 27 | 28 | return (IRepositoryAsync)_repositories[type]; 29 | } 30 | 31 | public virtual IRepositoryWithIdAsync RepositoryAsync() 32 | where TEntity : class, IAggregateRootWithId 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | 37 | public void Dispose() 38 | { 39 | if (_dbContext != null) GC.SuppressFinalize(_dbContext); 40 | } 41 | 42 | public int SaveChanges() 43 | { 44 | // we do nothing 45 | return 1; 46 | } 47 | 48 | public Task SaveChangesAsync(CancellationToken cancellationToken) 49 | { 50 | // we do nothing 51 | return Task.FromResult(1); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /samples/ExchangeService/v1/Services/ExchangeServiceImpl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Google.Protobuf.WellKnownTypes; 4 | using Grpc.Core; 5 | using Microsoft.Extensions.Logging; 6 | using NetCoreKit.Samples.BiMonetaryApi.Rpc; 7 | 8 | namespace NetCoreKit.Samples.ExchangeService.v1.Services 9 | { 10 | public class ExchangeServiceImpl : BiMonetaryApi.Rpc.ExchangeService.ExchangeServiceBase 11 | { 12 | private readonly ILogger _logger; 13 | 14 | public ExchangeServiceImpl(ILoggerFactory loggerFactory) 15 | { 16 | _logger = loggerFactory.CreateLogger(); 17 | } 18 | 19 | public override Task GetTokenInfo(TokenRequest request, ServerCallContext context) 20 | { 21 | _logger.LogInformation($"Start to process get extra info for {request.Symbol}."); 22 | 23 | var rnd = new Random(); 24 | 25 | // TODO: just for demo 26 | var result = new TokenResponse 27 | { 28 | Rank = rnd.Next(1, 1000), 29 | PriceBtc = rnd.NextDouble() * 9999D + 1, 30 | PriceUsd = rnd.NextDouble() * 9999D + 1, 31 | MarketCapUsd = rnd.NextDouble() * 9999D + 1, 32 | AvailableSupply = rnd.NextDouble() * 9999D + 1, 33 | TotalSupply = rnd.NextDouble() * 9999D + 1, 34 | Volumn24HUsd = rnd.NextDouble() * 9999D + 1, 35 | PercentChange1H = rnd.Next(1, 100) + "%", 36 | PercentChange24H = rnd.Next(1, 100) + "%", 37 | PercentChange7D = rnd.Next(1, 100) + "%" 38 | }; 39 | 40 | _logger.LogInformation("Return to caller."); 41 | 42 | return Task.FromResult(result); 43 | } 44 | 45 | public override Task Ping(Empty request, ServerCallContext context) 46 | { 47 | return Task.FromResult(new PingResponse {Result = true}); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/NetCoreKit.Domain/Dto.cs: -------------------------------------------------------------------------------- 1 | namespace NetCoreKit.Domain 2 | { 3 | /// 4 | /// Supertype for all Dto types 5 | /// 6 | public interface IDto 7 | { 8 | } 9 | 10 | public class Criterion : IDto 11 | { 12 | private const int MaxPageSize = 50; 13 | private const int ConfigurablePageSize = 10; 14 | private const string DefaultSortBy = "Id"; 15 | private const string DefaultSortOrder = "desc"; 16 | 17 | private int _pageSize = MaxPageSize; 18 | 19 | private string _sortBy = DefaultSortBy; 20 | 21 | private string _sortOrder = DefaultSortOrder; 22 | 23 | public Criterion() 24 | { 25 | CurrentPage = 1; 26 | PageSize = ConfigurablePageSize; 27 | } 28 | 29 | public int CurrentPage { get; set; } 30 | 31 | public int PageSize 32 | { 33 | get => _pageSize; 34 | set => _pageSize = value > MaxPageSize ? MaxPageSize : value < 1 ? 1 : value; 35 | } 36 | 37 | public string SortBy 38 | { 39 | get => _sortBy; 40 | set => _sortBy = string.IsNullOrEmpty(value) ? DefaultSortBy : value; 41 | } 42 | 43 | public string SortOrder 44 | { 45 | get => _sortOrder; 46 | set => _sortOrder = string.IsNullOrEmpty(value) ? DefaultSortOrder : value; 47 | } 48 | 49 | public Criterion SetPageSize(int pageSize) 50 | { 51 | if (pageSize <= 0) 52 | throw new ValidationException("PageSize could not be less than zero."); 53 | 54 | PageSize = pageSize; 55 | return this; 56 | } 57 | 58 | public Criterion SetCurrentPage(int currentPage) 59 | { 60 | if (currentPage <= 0) 61 | throw new ValidationException("CurrentPage could not be less than zero."); 62 | 63 | CurrentPage = currentPage; 64 | return this; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure.AspNetCore.OpenApi/DefaultValuesOperationFilter.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using Swashbuckle.AspNetCore.Swagger; 3 | using Swashbuckle.AspNetCore.SwaggerGen; 4 | 5 | namespace NetCoreKit.Infrastructure.AspNetCore.OpenApi 6 | { 7 | /// 8 | /// Represents the Swagger/Swashbuckle operation filter used to document the implicit API version parameter. 9 | /// 10 | /// 11 | /// This is only required due to bugs in the . 12 | /// Once they are fixed and published, this class can be removed. 13 | /// 14 | public class DefaultValuesOperationFilter : IOperationFilter 15 | { 16 | /// 17 | /// Applies the filter to the specified operation using the given context. 18 | /// 19 | /// The operation to apply the filter to. 20 | /// The current operation filter context. 21 | public void Apply(Operation operation, OperationFilterContext context) 22 | { 23 | if (operation.Parameters == null) return; 24 | 25 | // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/issues/412 26 | // REF: https://github.com/domaindrivendev/Swashbuckle.AspNetCore/pull/413 27 | foreach (var parameter in operation.Parameters.OfType()) 28 | { 29 | var description = context.ApiDescription.ParameterDescriptions.First(p => p.Name == parameter.Name); 30 | var routeInfo = description.RouteInfo; 31 | 32 | if (parameter.Description == null) parameter.Description = description.ModelMetadata?.Description; 33 | 34 | if (routeInfo == null) continue; 35 | 36 | if (parameter.Default == null) parameter.Default = routeInfo.DefaultValue; 37 | 38 | parameter.Required |= !routeInfo.IsOptional; 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/TodoApi/Domain/Project.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using NetCoreKit.Domain; 5 | 6 | namespace NetCoreKit.Samples.TodoAPI.Domain 7 | { 8 | public class Project : AggregateRootBase 9 | { 10 | private Project() 11 | { 12 | } 13 | 14 | private Project(string name) 15 | { 16 | Name = name; 17 | AddEvent(new ProjectCreated(Id, name)); 18 | } 19 | 20 | public string Name { get; private set; } 21 | public ICollection Tasks { get; private set; } = new List(); 22 | 23 | public static Project Load(string name) 24 | { 25 | return new Project(name); 26 | } 27 | 28 | public Project ChangeName(string name) 29 | { 30 | Name = name; 31 | return this; 32 | } 33 | 34 | public Project AddTask(Task task) 35 | { 36 | Tasks.Add(task.SetProject(this)); 37 | AddEvent(new TaskCreated(task.Id, task.Title, Id)); 38 | return this; 39 | } 40 | 41 | public Project UpdateTask(Guid taskId, string taskName, int order = 1, bool completed = false) 42 | { 43 | var task = Tasks.FirstOrDefault(x => x.Id == taskId); 44 | if (task == null) 45 | throw new DomainException($"Couldn't find any task#{taskId}."); 46 | 47 | task.ChangeTitle(taskName) 48 | .ChangeOrder(order); 49 | 50 | if (completed) task.ChangeToCompleted(); 51 | 52 | AddEvent(new TaskUpdated()); 53 | return this; 54 | } 55 | 56 | public Project RemoveTask(Guid taskId) 57 | { 58 | Tasks = Tasks.Where(x => x.Id != taskId).ToList(); 59 | 60 | AddEvent(new TaskDeleted()); 61 | return this; 62 | } 63 | 64 | public Project ClearTasks() 65 | { 66 | Tasks = new List(); 67 | AddEvent(new TaskDeleted()); 68 | return this; 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/OrderByExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Linq.Expressions; 4 | using NetCoreKit.Domain; 5 | 6 | namespace NetCoreKit.Infrastructure 7 | { 8 | public static class OrderByExtensions 9 | { 10 | public static IQueryable OrderByPropertyName(this IQueryable source, 11 | string propertyName, bool isDescending) where TEntity : IEntityWithId 12 | { 13 | return OrderByPropertyName(source, propertyName, isDescending); 14 | } 15 | 16 | public static IQueryable OrderByPropertyName(this IQueryable source, 17 | string propertyName, bool isDescending) where TEntity : IEntityWithId 18 | { 19 | if (source == null) 20 | throw new ArgumentException("source"); 21 | 22 | if (string.IsNullOrWhiteSpace(propertyName)) 23 | throw new ArgumentException("propertyName"); 24 | 25 | var type = typeof(TEntity); 26 | var arg = Expression.Parameter(type, "x"); 27 | var propertyInfo = type.GetProperty(propertyName); 28 | Expression expression = Expression.Property(arg, propertyInfo); 29 | type = propertyInfo.PropertyType; 30 | 31 | var delegateType = typeof(Func<,>).MakeGenericType(typeof(TEntity), type); 32 | var lambda = Expression.Lambda(delegateType, expression, arg); 33 | 34 | var methodName = isDescending ? "OrderByDescending" : "OrderBy"; 35 | var result = typeof(Queryable).GetMethods().Single( 36 | method => method.Name == methodName 37 | && method.IsGenericMethodDefinition 38 | && method.GetGenericArguments().Length == 2 39 | && method.GetParameters().Length == 2) 40 | .MakeGenericMethod(typeof(TEntity), type) 41 | .Invoke(null, new object[] { source, lambda }); 42 | 43 | return (IQueryable)result; 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /samples/TodoApi/v1/UseCases/AddTask/RequestHandler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.EntityFrameworkCore; 5 | using NetCoreKit.Domain; 6 | using NetCoreKit.Infrastructure.AspNetCore.CleanArch; 7 | using NetCoreKit.Infrastructure.EfCore.Extensions; 8 | using NetCoreKit.Samples.TodoAPI.Domain; 9 | using NetCoreKit.Samples.TodoAPI.Extensions; 10 | using NetCoreKit.Samples.TodoAPI.Infrastructure.Db; 11 | using Task = NetCoreKit.Samples.TodoAPI.Domain.Task; 12 | 13 | namespace NetCoreKit.Samples.TodoAPI.v1.UseCases.AddTask 14 | { 15 | public class RequestHandler : TxRequestHandlerBase 16 | { 17 | private readonly IUserGateway _userGateway; 18 | 19 | public RequestHandler( 20 | IUnitOfWorkAsync uow, 21 | IQueryRepositoryFactory queryRepositoryFactory, 22 | IUserGateway userGateway) 23 | : base(uow, queryRepositoryFactory) 24 | { 25 | _userGateway = userGateway; 26 | } 27 | 28 | public override async Task Handle(AddTaskRequest request, CancellationToken cancellationToken) 29 | { 30 | var commandRepository = CommandFactory.RepositoryAsync(); 31 | var queryRepository = QueryFactory.QueryRepository(); 32 | 33 | var project = 34 | await queryRepository.GetByIdAsync(request.ProjectId, q => q.Include(x => x.Tasks), false); 35 | if (project == null) 36 | throw new Exception($"Couldn't found the project#{request.ProjectId}."); 37 | 38 | var author = await _userGateway.GetAuthorAsync(); 39 | if (author == null) throw new Exception("Couldn't found the default author."); 40 | 41 | var task = Task.Load(request.Title); 42 | task = task.SetAuthor(author.Id, author.GetFullName()); 43 | 44 | project.AddTask(task); 45 | project = await commandRepository.UpdateAsync(project); 46 | 47 | return new AddTaskResponse {Result = project.ToDto()}; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /samples/TodoApi/NetCoreKit.Samples.TodoApi.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | netcoreapp2.2 5 | dccac7b0-2f27-40fb-b062-d13483fefeba 6 | inprocess 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /src/NetCoreKit.Infrastructure/ConfigurationExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using System.Reflection; 6 | using Microsoft.Extensions.Configuration; 7 | using NetCoreKit.Domain; 8 | using NetCoreKit.Utils.Extensions; 9 | 10 | namespace NetCoreKit.Infrastructure 11 | { 12 | public static class ConfigurationExtensions 13 | { 14 | public static IEnumerable LoadFullAssemblies(this IConfiguration config) 15 | { 16 | if (string.IsNullOrEmpty(config.GetValue("QualifiedAssemblyPattern"))) 17 | throw new CoreException( 18 | "Add QualifiedAssemblyPattern key in appsettings.json for automatically loading assembly."); 19 | 20 | return config.GetValue("QualifiedAssemblyPattern").LoadFullAssemblies(); 21 | } 22 | 23 | public static IEnumerable LoadApplicationAssemblies(this IConfiguration config) 24 | { 25 | if (string.IsNullOrEmpty(config.GetValue("QualifiedAssemblyPattern"))) 26 | throw new CoreException( 27 | "Add QualifiedAssemblyPattern key in appsettings.json for automatically loading assembly."); 28 | 29 | var apps = config.GetValue("QualifiedAssemblyPattern").LoadAssemblyWithPattern(); 30 | if (apps == null || !apps.Any()) 31 | throw new Exception("Should have at least one application assembly to load."); 32 | 33 | return apps; 34 | } 35 | } 36 | 37 | public class ConfigurationHelper 38 | { 39 | public static IConfigurationRoot GetConfiguration(string basePath = null) 40 | { 41 | basePath = basePath ?? Directory.GetCurrentDirectory(); 42 | var builder = new ConfigurationBuilder() 43 | .SetBasePath(basePath) 44 | .AddJsonFile("appsettings.json") 45 | .AddJsonFile($"appsettings.{ Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")}.json", true) 46 | .AddEnvironmentVariables(); 47 | 48 | return builder.Build(); 49 | } 50 | } 51 | } 52 | --------------------------------------------------------------------------------