├── .gitattributes ├── .github └── workflows │ ├── Allegro.Extensions.ApplicationInsights.ci.yml │ ├── Allegro.Extensions.ApplicationInsights.publish.yml │ ├── Allegro.Extensions.AspNetCore.ci.yml │ ├── Allegro.Extensions.AspNetCore.publish.yml │ ├── Allegro.Extensions.Cqrs.Abstractions.ci.yml │ ├── Allegro.Extensions.Cqrs.Abstractions.publish.yml │ ├── Allegro.Extensions.Cqrs.FluentValidations.ci.yml │ ├── Allegro.Extensions.Cqrs.FluentValidations.publish.yml │ ├── Allegro.Extensions.Cqrs.ci.yml │ ├── Allegro.Extensions.Cqrs.publish.yml │ ├── Allegro.Extensions.Dapper.Postgres.ci.yml │ ├── Allegro.Extensions.Dapper.Postgres.publish.yml │ ├── Allegro.Extensions.Dapper.ci.yml │ ├── Allegro.Extensions.Dapper.publish.yml │ ├── Allegro.Extensions.DependencyCall.ci.yml │ ├── Allegro.Extensions.DependencyCall.publish.yml │ ├── Allegro.Extensions.Financials.ci.yml │ ├── Allegro.Extensions.Financials.publish.yml │ ├── Allegro.Extensions.Globalization.ci.yml │ ├── Allegro.Extensions.Globalization.publish.yml │ ├── Allegro.Extensions.Identifiers.Abstractions.ci.yml │ ├── Allegro.Extensions.Identifiers.Abstractions.publish.yml │ ├── Allegro.Extensions.Identifiers.AspNetCore.ci.yml │ ├── Allegro.Extensions.Identifiers.AspNetCore.publish.yml │ ├── Allegro.Extensions.NullableReferenceTypes.ci.yml │ ├── Allegro.Extensions.NullableReferenceTypes.publish.yml │ ├── Allegro.Extensions.RateLimiting.ci.yml │ ├── Allegro.Extensions.RateLimiting.publish.yml │ ├── Allegro.Extensions.Serialization.ci.yml │ ├── Allegro.Extensions.Serialization.publish.yml │ ├── Allegro.Extensions.Validators.ci.yml │ ├── Allegro.Extensions.Validators.publish.yml │ └── template.yml ├── .gitignore ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── ap-catalog-info.yaml ├── docs └── index.md ├── global.json ├── mkdocs.yml └── src ├── .editorconfig ├── Allegro.Extensions.ApplicationInsights ├── Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests │ ├── .editorconfig │ ├── AdaptiveSamplingConfigurationTests.cs │ ├── Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests.csproj │ ├── FilterTests.cs │ └── SamplingFilterTests.cs ├── Allegro.Extensions.ApplicationInsights.AspNetCore │ ├── Allegro.Extensions.ApplicationInsights.AspNetCore.csproj │ ├── CloudApplicationInfo │ │ ├── TelemetryCloudApplicationInfo.cs │ │ └── TelemetryCloudApplicationInfoTelemetryInitializer.cs │ ├── FlushAppInsightsHostedService.cs │ ├── InternalsVisibleTo.cs │ ├── SamplingConfig │ │ ├── AdaptiveSamplingConfig.cs │ │ ├── PrintSamplingConfigurationService.cs │ │ ├── SamplingConfig.cs │ │ └── SamplingMode.cs │ ├── SamplingExclusions │ │ ├── DependencyForFilter.cs │ │ ├── ExcludeFromSamplingTelemetryConfig.cs │ │ ├── ExcludeFromSamplingTelemetryInitializer.cs │ │ └── RequestForFilter.cs │ ├── SendConfig.cs │ ├── StartupExtensions.cs │ ├── StartupLogger │ │ └── StartupLogger.cs │ └── TelemetryContext │ │ ├── TelemetryContext.cs │ │ ├── TelemetryContextInitializer.cs │ │ └── TelemetryContextMiddleware.cs ├── Allegro.Extensions.ApplicationInsights.Demo.UnitTests │ ├── .editorconfig │ ├── Allegro.Extensions.ApplicationInsights.Demo.UnitTests.csproj │ ├── ExcludeFromSamplingTelemetryInitializerRulesTests.cs │ └── SamplingFilterTests.cs ├── Allegro.Extensions.ApplicationInsights.Demo │ ├── Allegro.Extensions.ApplicationInsights.Demo.csproj │ ├── Controllers │ │ └── WeatherForecastController.cs │ ├── CustomDependencyForFilter.cs │ ├── CustomTelemetryCloudApplicationInfo.cs │ ├── InternalsVisibleTo.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── appsettings.Development.json │ └── appsettings.json ├── Allegro.Extensions.ApplicationInsights.Prometheus.UnitTests │ ├── .editorconfig │ ├── Allegro.Extensions.ApplicationInsights.Prometheus.UnitTests.csproj │ └── ApplicationInsightsToPrometheusMetricsInitializerTests.cs ├── Allegro.Extensions.ApplicationInsights.Prometheus │ ├── Allegro.Extensions.ApplicationInsights.Prometheus.csproj │ ├── ApplicationInsightsToPrometheusMetricsConfig.cs │ ├── ApplicationInsightsToPrometheusMetricsInitializer.cs │ ├── InternalsVisibleTo.cs │ ├── PrometheusMetrics.cs │ └── StartupExtensions.cs ├── Allegro.Extensions.ApplicationInsights.sln ├── Allegro.Extensions.ApplicationInsights.sln.DotSettings ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.AspNetCore ├── Allegro.Extensions.AspNetCore.Demo │ ├── Allegro.Extensions.AspNetCore.Demo.csproj │ ├── Controllers │ │ ├── ErrorHandlingController.cs │ │ ├── SkipOnProdController.cs │ │ └── TestController.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ └── Startup.cs ├── Allegro.Extensions.AspNetCore.Tests.Unit │ ├── Allegro.Extensions.AspNetCore.Tests.Unit.csproj │ ├── ErrorHandling │ │ ├── ErrorHandlingMiddlewareTests.cs │ │ └── InvalidModelStateResponseFactoryTests.cs │ └── SkipControllerFeatureProviderTests.cs ├── Allegro.Extensions.AspNetCore.sln ├── Allegro.Extensions.AspNetCore │ ├── Allegro.Extensions.AspNetCore.csproj │ ├── Attributes │ │ └── SkipOnProdAttribute.cs │ ├── ErrorHandling │ │ ├── ErrorHandlingConfigurationBuilder.cs │ │ ├── ErrorHandlingMiddlewareExtensions.cs │ │ ├── IErrorSerializer.cs │ │ ├── Internals │ │ │ ├── ErrorHandlingMiddleware.cs │ │ │ ├── ErrorResponse.cs │ │ │ ├── InvalidModelStateResponseFactory.cs │ │ │ └── SystemTextJsonWebErrorSerializer.cs │ │ └── Models.cs │ ├── Extensions │ │ └── MvcBuilderExtensions.cs │ ├── Features │ │ └── SkipControllerFeatureProvider.cs │ └── InternalsVisibleTo.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Cqrs ├── Allegro.Extensions.Cqrs.Abstractions │ ├── Allegro.Extensions.Cqrs.Abstractions.csproj │ ├── Commands │ │ ├── Command.cs │ │ ├── ICommandDispatcher.cs │ │ ├── ICommandHandler.cs │ │ └── ICommandValidator.cs │ ├── DecoratorAttribute.cs │ └── Queries │ │ ├── IQueryDispatcher.cs │ │ ├── IQueryHandler.cs │ │ ├── IQueryValidator.cs │ │ └── Query.cs ├── Allegro.Extensions.Cqrs.Demo │ ├── Allegro.Extensions.Cqrs.Demo.csproj │ ├── Commands │ │ └── BarCommand.cs │ ├── Controllers │ │ ├── CommandController.cs │ │ └── QueryController.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ ├── Queries │ │ └── BarQuery.cs │ └── Startup.cs ├── Allegro.Extensions.Cqrs.FluentValidations │ ├── Allegro.Extensions.Cqrs.FluentValidations.csproj │ ├── FluentCommandValidator.cs │ ├── FluentQueryValidator.cs │ └── StartupExtensions.cs ├── Allegro.Extensions.Cqrs.Tests.Unit │ ├── Allegro.Extensions.Cqrs.Tests.Unit.csproj │ ├── CommandsSpec.cs │ └── QueriesSpec.cs ├── Allegro.Extensions.Cqrs.sln ├── Allegro.Extensions.Cqrs │ ├── Allegro.Extensions.Cqrs.csproj │ ├── Commands │ │ ├── CommandDispatcher.cs │ │ └── StartupExtensions.cs │ ├── InternalsVisibleTo.cs │ └── Queries │ │ ├── QueryDispatcher.cs │ │ └── StartupExtensions.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Dapper ├── Allegro.Extensions.Dapper.Postgres.Tests.Integration │ ├── Allegro.Extensions.Dapper.Postgres.Tests.Integration.csproj │ ├── DapperPostgresBinaryCopyClient.cs │ ├── Helpers │ │ ├── CustomWebApplicationFactory.cs │ │ ├── FakeStartup.cs │ │ └── SqlQueries.cs │ ├── Models │ │ └── TestModel.cs │ ├── PostgresDapperClient.cs │ └── appsettings.Test.json ├── Allegro.Extensions.Dapper.Postgres │ ├── Abstractions │ │ ├── DbType.cs │ │ └── IDapperPostgresBinaryCopyClient.cs │ ├── Allegro.Extensions.Dapper.Postgres.csproj │ ├── DapperPostgresBinaryCopyClient.cs │ ├── Exceptions │ │ └── InvalidDbConnectionTypeException.cs │ ├── Extensions │ │ └── ServiceCollectionExtensions.cs │ └── Factories │ │ └── PostgresDatabaseConnectionFactory.cs ├── Allegro.Extensions.Dapper.sln ├── Allegro.Extensions.Dapper │ ├── Abstractions │ │ ├── IDapperClient.cs │ │ └── IDatabaseConnectionFactory.cs │ ├── Allegro.Extensions.Dapper.csproj │ ├── Configurations │ │ └── DatabaseConfiguration.cs │ ├── DapperClient.cs │ └── Extensions │ │ └── ServiceCollectionExtensions.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.DependencyCall ├── Allegro.Extensions.DependencyCall.Abstractions │ ├── Allegro.Extensions.DependencyCall.Abstractions.csproj │ ├── IDependencyCallDispatcher.cs │ ├── IDependencyCallMetrics.cs │ └── IRequest.cs ├── Allegro.Extensions.DependencyCall.Metrics.Prometheus │ ├── Allegro.Extensions.DependencyCall.Metrics.Prometheus.csproj │ ├── DependencyCallBuilderExtensions.cs │ └── PrometheusDependencyCallMetrics.cs ├── Allegro.Extensions.DependencyCall.Tests.Unit │ ├── Allegro.Extensions.DependencyCall.Tests.Unit.csproj │ ├── DependencyCallDispatcherSpec.cs │ └── Fixture.cs ├── Allegro.Extensions.DependencyCall.sln ├── Allegro.Extensions.DependencyCall │ ├── Allegro.Extensions.DependencyCall.csproj │ ├── DependencyCall.cs │ ├── DependencyCallDispatcher.cs │ ├── NoOperationDependencyCallMetrics.cs │ └── StartupExtensions.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Financials ├── Allegro.Extensions.Financials.Tests.Unit │ ├── Allegro.Extensions.Financials.Tests.Unit.csproj │ ├── Extensions │ │ └── MoneyExtensionsTests.cs │ └── ValueObjects │ │ └── MoneyTests.cs ├── Allegro.Extensions.Financials.sln ├── Allegro.Extensions.Financials │ ├── Allegro.Extensions.Financials.csproj │ ├── Extensions │ │ └── MoneyExtensions.cs │ └── ValueObjects │ │ ├── Currency.cs │ │ ├── Money.Operators.cs │ │ └── Money.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Globalization ├── Allegro.Extensions.Globalization.Tests │ ├── Allegro.Extensions.Globalization.Tests.csproj │ └── PolishPluralizerTests.cs ├── Allegro.Extensions.Globalization.sln ├── Allegro.Extensions.Globalization │ ├── Allegro.Extensions.Globalization.csproj │ └── Extensions │ │ └── PolishPluralizer.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Identifiers ├── Allegro.Extensions.Identifiers.Abstractions │ ├── Allegro.Extensions.Identifiers.Abstractions.csproj │ ├── IStronglyTypedEntity.cs │ └── IStronglyTypedId.cs ├── Allegro.Extensions.Identifiers.AspNetCore │ ├── Allegro.Extensions.Identifiers.AspNetCore.csproj │ └── Swagger │ │ └── StronglyTypedIdsSwaggerExtensions.cs ├── Allegro.Extensions.Identifiers.Demo │ ├── Allegro.Extensions.Identifiers.Demo.csproj │ ├── Controllers │ │ └── TestController.cs │ ├── Identifiers │ │ ├── OrderId.cs │ │ ├── PaymentId.cs │ │ └── UserId.cs │ ├── Program.cs │ ├── Properties │ │ └── launchSettings.json │ └── Startup.cs ├── Allegro.Extensions.Identifiers.sln ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.NullableReferenceTypes ├── Allegro.Extensions.NullableReferenceTypes.Tests.Unit │ ├── Allegro.Extensions.NullableReferenceTypes.Tests.Unit.csproj │ └── Validators │ │ └── ObjectValidatorTests.cs ├── Allegro.Extensions.NullableReferenceTypes.sln ├── Allegro.Extensions.NullableReferenceTypes │ ├── Allegro.Extensions.NullableReferenceTypes.csproj │ └── Validators │ │ └── ObjectValidator.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.RateLimiting ├── Allegro.Extensions.RateLimiting.Tests.Unit │ ├── Allegro.Extensions.RateLimiting.Tests.Unit.csproj │ └── RateLimiterTests.cs ├── Allegro.Extensions.RateLimiting.sln ├── Allegro.Extensions.RateLimiting │ ├── Allegro.Extensions.RateLimiting.csproj │ ├── Events │ │ ├── AvgRateCalculated.cs │ │ ├── MaxRateChanged.cs │ │ └── MaxRateExceeded.cs │ ├── IRateLimiter.cs │ ├── IRateLimiterWithVariableRate.cs │ └── RateLimiter.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Serialization ├── Allegro.Extensions.Serialization.Tests.Unit │ ├── Allegro.Extensions.Serialization.Tests.Unit.csproj │ └── EnumHelperTests.cs ├── Allegro.Extensions.Serialization.sln ├── Allegro.Extensions.Serialization │ ├── Allegro.Extensions.Serialization.csproj │ └── Extensions │ │ └── EnumHelper.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Allegro.Extensions.Validators ├── Allegro.Extensions.Validators.Tests.Unit │ ├── Allegro.Extensions.Validators.Tests.Unit.csproj │ └── InputValidatorTests.cs ├── Allegro.Extensions.Validators.sln ├── Allegro.Extensions.Validators │ ├── Allegro.Extensions.Validators.csproj │ ├── FluentValidationOptions.cs │ ├── InputValidator.cs │ ├── OptionsBuilderFluentValidationExtensions.cs │ └── StartupExtensions.cs ├── CHANGELOG.md ├── README.md └── version.xml ├── Directory.Build.props ├── Directory.Build.targets └── Package.Build.props /.gitattributes: -------------------------------------------------------------------------------- 1 | *.sh text eol=lf -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.ApplicationInsights.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.ApplicationInsights 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.ApplicationInsights/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.ApplicationInsights/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci1: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.ApplicationInsights.AspNetCore 20 | solutionName: Allegro.Extensions.ApplicationInsights 21 | ci2: 22 | uses: ./.github/workflows/template.yml 23 | with: 24 | projectName: Allegro.Extensions.ApplicationInsights.Prometheus 25 | solutionName: Allegro.Extensions.ApplicationInsights 26 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.ApplicationInsights.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.ApplicationInsights 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.ApplicationInsights_*' 7 | 8 | jobs: 9 | publish1: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.ApplicationInsights.AspNetCore 13 | solutionName: Allegro.Extensions.ApplicationInsights 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | publish2: 24 | uses: ./.github/workflows/template.yml 25 | with: 26 | projectName: Allegro.Extensions.ApplicationInsights.Prometheus 27 | solutionName: Allegro.Extensions.ApplicationInsights 28 | publish: true 29 | tagName: ${{ github.ref_name }} 30 | secrets: 31 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 32 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 33 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 34 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 35 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 36 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 37 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.AspNetCore.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.AspNetCore 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.AspNetCore/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.AspNetCore/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.AspNetCore 20 | solutionName: Allegro.Extensions.AspNetCore 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.AspNetCore.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.AspNetCore 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.AspNetCore_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.AspNetCore 13 | solutionName: Allegro.Extensions.AspNetCore 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Cqrs.Abstractions.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Cqrs.Abstractions 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Cqrs/*' 8 | - 'src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Cqrs/*' 14 | - 'src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Cqrs.Abstractions 22 | solutionName: Allegro.Extensions.Cqrs 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Cqrs.Abstractions.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Cqrs.Abstractions 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Cqrs.Abstractions_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Cqrs.Abstractions 13 | solutionName: Allegro.Extensions.Cqrs 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Cqrs.FluentValidations.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Cqrs.FluentValidations 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Cqrs/*' 8 | - 'src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.FluentValidations/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Cqrs/*' 14 | - 'src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.FluentValidations/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Cqrs.FluentValidations 22 | solutionName: Allegro.Extensions.Cqrs 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Cqrs.FluentValidations.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Cqrs.FluentValidations 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Cqrs.FluentValidations_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Cqrs.FluentValidations 13 | solutionName: Allegro.Extensions.Cqrs 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Cqrs.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Cqrs 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Cqrs/*' 8 | - 'src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Cqrs/*' 14 | - 'src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Cqrs 22 | solutionName: Allegro.Extensions.Cqrs 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Cqrs.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Cqrs 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Cqrs_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Cqrs 13 | solutionName: Allegro.Extensions.Cqrs 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Dapper.Postgres.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Dapper.Postgres 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Dapper/*' 8 | - 'src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Dapper/*' 14 | - 'src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Dapper.Postgres 22 | solutionName: Allegro.Extensions.Dapper 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Dapper.Postgres.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Dapper.Postgres 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Dapper.Postgres_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Dapper.Postgres 13 | solutionName: Allegro.Extensions.Dapper 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Dapper.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Dapper 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Dapper/*' 8 | - 'src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Dapper/*' 14 | - 'src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Dapper 22 | solutionName: Allegro.Extensions.Dapper 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Dapper.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Dapper 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Dapper_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Dapper 13 | solutionName: Allegro.Extensions.Dapper 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.DependencyCall.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.DependencyCall 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.DependencyCall/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.DependencyCall/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.DependencyCall 20 | solutionName: Allegro.Extensions.DependencyCall 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.DependencyCall.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.DependencyCall 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.DependencyCall_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.DependencyCall 13 | solutionName: Allegro.Extensions.DependencyCall 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Financials.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Financials 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Financials/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.Financials/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.Financials 20 | solutionName: Allegro.Extensions.Financials 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Financials.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Financials 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Financials_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Financials 13 | solutionName: Allegro.Extensions.Financials 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Globalization.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Globalization 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Globalization/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.Globalization/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.Globalization 20 | solutionName: Allegro.Extensions.Globalization 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Globalization.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Globalization 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Globalization_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Globalization 13 | solutionName: Allegro.Extensions.Globalization 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Identifiers.Abstractions.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Identifiers.Abstractions 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Identifiers/*' 8 | - 'src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Abstractions/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Identifiers/*' 14 | - 'src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Abstractions/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Identifiers.Abstractions 22 | solutionName: Allegro.Extensions.Identifiers 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Identifiers.Abstractions.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Identifiers.Abstractions 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Identifiers.Abstractions_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Identifiers.Abstractions 13 | solutionName: Allegro.Extensions.Identifiers 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Identifiers.AspNetCore.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Identifiers.AspNetCore 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Identifiers/*' 8 | - 'src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.AspNetCore/**' 9 | - 'src/*' 10 | pull_request: 11 | branches: [ main ] 12 | paths: 13 | - 'src/Allegro.Extensions.Identifiers/*' 14 | - 'src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.AspNetCore/**' 15 | - 'src/*' 16 | 17 | jobs: 18 | ci: 19 | uses: ./.github/workflows/template.yml 20 | with: 21 | projectName: Allegro.Extensions.Identifiers.AspNetCore 22 | solutionName: Allegro.Extensions.Identifiers 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Identifiers.AspNetCore.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Identifiers.AspNetCore 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Identifiers.AspNetCore_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Identifiers.AspNetCore 13 | solutionName: Allegro.Extensions.Identifiers 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.NullableReferenceTypes.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.NullableReferenceTypes 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.NullableReferenceTypes/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.NullableReferenceTypes/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.NullableReferenceTypes 20 | solutionName: Allegro.Extensions.NullableReferenceTypes 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.NullableReferenceTypes.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.NullableReferenceTypes 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.NullableReferenceTypes_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.NullableReferenceTypes 13 | solutionName: Allegro.Extensions.NullableReferenceTypes 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.RateLimiting.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.RateLimiting 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.RateLimiting/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.RateLimiting/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.RateLimiting 20 | solutionName: Allegro.Extensions.RateLimiting 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.RateLimiting.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.RateLimiting 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.RateLimiting_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.RateLimiting 13 | solutionName: Allegro.Extensions.RateLimiting 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Serialization.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Serialization 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Serialization/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.Serialization/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.Serialization 20 | solutionName: Allegro.Extensions.Serialization 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Serialization.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Serialization 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Serialization_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Serialization 13 | solutionName: Allegro.Extensions.Serialization 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Validators.ci.yml: -------------------------------------------------------------------------------- 1 | name: Build Allegro.Extensions.Validators 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | paths: 7 | - 'src/Allegro.Extensions.Validators/**' 8 | - 'src/*' 9 | pull_request: 10 | branches: [ main ] 11 | paths: 12 | - 'src/Allegro.Extensions.Validators/**' 13 | - 'src/*' 14 | 15 | jobs: 16 | ci: 17 | uses: ./.github/workflows/template.yml 18 | with: 19 | projectName: Allegro.Extensions.Validators 20 | solutionName: Allegro.Extensions.Validators 21 | -------------------------------------------------------------------------------- /.github/workflows/Allegro.Extensions.Validators.publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Allegro.Extensions.Validators 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'Allegro.Extensions.Validators_*' 7 | 8 | jobs: 9 | publish: 10 | uses: ./.github/workflows/template.yml 11 | with: 12 | projectName: Allegro.Extensions.Validators 13 | solutionName: Allegro.Extensions.Validators 14 | publish: true 15 | tagName: ${{ github.ref_name }} 16 | secrets: 17 | SM_CLIENT_CERT_PASSWORD: ${{ secrets.DIGICERT_SM_CLIENT_CERT_PASSWORD }} 18 | SM_CLIENT_CERT_FILE_B64: ${{ secrets.DIGICERT_SM_CLIENT_CERT_FILE_B64 }} 19 | SM_HOST: ${{ secrets.DIGICERT_SM_HOST }} 20 | SM_API_KEY: ${{ secrets.DIGICERT_SM_API_KEY }} 21 | SM_CODE_SIGNING_CERT_SHA1_HASH: ${{ secrets.DIGICERT_SM_CODE_SIGNING_CERT_SHA1_HASH }} 22 | nugetApiKey: ${{ secrets.NUGET_API_KEY }} 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .fake/ 2 | .idea/ 3 | .ionide/ 4 | .paket/ 5 | .vscode/ 6 | App_Data/ 7 | packages/ 8 | obj/ 9 | bin/ 10 | build/ 11 | deploy/ 12 | TestResults/ 13 | *.bak 14 | *.user 15 | *.suo 16 | *.ncrunchsolution 17 | *.ncrunchproject 18 | *.nupkg 19 | *.snupkg 20 | .vs/ 21 | **/frontend/node_modules/ 22 | **/frontend/coverage/ 23 | DeploymentScripts/temp/ 24 | BenchmarkDotNet.Artifacts 25 | paket-files/ 26 | .DS_Store 27 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Pull requests 4 | 5 | * for small changes, no need to add separate issue, defining problem in pull request is enough 6 | * if issue exists, reference it from PR title or description using GitHub magic words like *resolves #issue-number* 7 | * before making significant changes, please contact us via issues to discuss your plans and decrease number of changes after Pull Request is created 8 | * create pull requests to **main** branch 9 | * when updating a package, make sure to: 10 | * update its README.md 11 | * update its CHANGELOG.md 12 | * update its version 13 | * consider presenting usage in Demo app (`/samples`) 14 | * add tests 15 | * when creating a new package, make sure to: 16 | * maintain the repo structure (see existing packages) 17 | * add code analyzers 18 | * create the package's README.md 19 | * initialize the package's CHANGELOG.md 20 | * add tests 21 | * consider presenting usage in Demo app (`/samples`) 22 | * reference the package from README.md in repo's root 23 | 24 | ## Coding style 25 | 26 | The coding style is guarded by the analyzers (such as stylecop) and .editorconfig. 27 | Make sure to follow the defined standards. -------------------------------------------------------------------------------- /ap-catalog-info.yaml: -------------------------------------------------------------------------------- 1 | # https://backstage.io/docs/features/software-catalog/descriptor-format#kind-component 2 | apiVersion: backstage.io/v1alpha1 3 | kind: Component 4 | metadata: 5 | name: AllegroExtensions 6 | description: "This repo contains utility packages that can be shared between Allegro services, but are not required. " 7 | title: Allegro Extensions 8 | annotations: 9 | backstage.io/techdocs-ref: dir:. 10 | allegropay/entity-updated-at: '2023-11-03T08:15' 11 | github.com/project-slug: allegro/dotnet-utils 12 | links: [] 13 | spec: 14 | type: library 15 | owner: aard 16 | lifecycle: production 17 | system: application-platform 18 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | {% 2 | include-markdown "../README.md" 3 | start="" 4 | end="" 5 | rewrite-relative-urls=true 6 | %} 7 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "8.0.100", 4 | "rollForward": "latestFeature" 5 | }, 6 | "msbuild-sdks": { 7 | "Allegro.DotnetSdk": "2.1.0" 8 | } 9 | } -------------------------------------------------------------------------------- /mkdocs.yml: -------------------------------------------------------------------------------- 1 | site_name: Allegro Pay Backstage docs 2 | 3 | plugins: 4 | - techdocs-core 5 | - include-markdown 6 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{cs,fs}] 2 | dotnet_diagnostic.CS1591.severity = none -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests/Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers 25 | 26 | 27 | all 28 | runtime; compile; build; native; contentfiles; analyzers 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests/FilterTests.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.DataContracts; 2 | using Microsoft.Extensions.Logging.Abstractions; 3 | 4 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 5 | 6 | public class FilterTests 7 | where TDependencyForFilter : DependencyForFilter 8 | where TRequestForFilter : RequestForFilter 9 | { 10 | public void ApplyDependencyRules( 11 | DependencyTelemetry dependencyTelemetry, 12 | string filter, 13 | Func dependencyMap) 14 | { 15 | var predicates = 16 | ExcludeFromSamplingTelemetryInitializer 17 | .CreatePredicates( 18 | NullLogger.Instance, 19 | new Dictionary() { { "any", filter } }); 20 | 21 | ExcludeFromSamplingTelemetryInitializer.ApplyDependencyRules( 22 | dependencyTelemetry, 23 | predicates, 24 | dependencyMap); 25 | } 26 | 27 | public void ApplyRequestRules( 28 | RequestTelemetry requestTelemetry, string filter, Func requestMap) 29 | { 30 | var predicates = 31 | ExcludeFromSamplingTelemetryInitializer 32 | .CreatePredicates( 33 | NullLogger.Instance, 34 | new Dictionary() { { "any", filter } }); 35 | 36 | ExcludeFromSamplingTelemetryInitializer.ApplyRequestRules( 37 | requestTelemetry, 38 | predicates, 39 | requestMap); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/Allegro.Extensions.ApplicationInsights.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | all 22 | runtime; build; native; contentfiles; analyzers 23 | 24 | 25 | all 26 | runtime; compile; build; native; contentfiles; analyzers 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/CloudApplicationInfo/TelemetryCloudApplicationInfo.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | 3 | /// 4 | /// Information about cloud environment of the app 5 | /// 6 | public class TelemetryCloudApplicationInfo : Dictionary 7 | { 8 | /// 9 | /// Default value when no value provided 10 | /// 11 | public const string EmptyPlaceholder = "empty"; 12 | 13 | /// 14 | /// ApplicationName Key 15 | /// 16 | public const string ApplicationNameKey = "ApplicationName"; 17 | 18 | /// 19 | /// Application name (i.e. name of the k8s service) 20 | /// 21 | public string? ApplicationName 22 | { 23 | get => this.GetValueOrDefault(nameof(ApplicationName)); 24 | set 25 | { 26 | if (value != null) 27 | this[nameof(ApplicationName)] = value; 28 | } 29 | } 30 | 31 | /// 32 | /// Load cloud application info from environment variables 33 | /// 34 | public virtual void LoadFromEnv() 35 | { 36 | var applicationName = 37 | Environment.GetEnvironmentVariable(ApplicationNameKey) 38 | ?? EmptyPlaceholder; 39 | 40 | Add(ApplicationNameKey, applicationName); 41 | } 42 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/CloudApplicationInfo/TelemetryCloudApplicationInfoTelemetryInitializer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.Channel; 2 | using Microsoft.ApplicationInsights.DataContracts; 3 | using Microsoft.ApplicationInsights.Extensibility; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 7 | 8 | internal class TelemetryCloudApplicationInfoTelemetryInitializer : ITelemetryInitializer 9 | { 10 | private readonly IOptions _cloudApplicationInfo; 11 | 12 | public TelemetryCloudApplicationInfoTelemetryInitializer(IOptions cloudApplicationInfo) 13 | { 14 | _cloudApplicationInfo = cloudApplicationInfo; 15 | } 16 | 17 | public void Initialize(ITelemetry telemetry) 18 | { 19 | telemetry.Context.Cloud.RoleName = _cloudApplicationInfo.Value.ApplicationName; 20 | 21 | foreach (var metadata in _cloudApplicationInfo.Value) 22 | { 23 | if (metadata.Key != TelemetryCloudApplicationInfo.ApplicationNameKey) 24 | { 25 | SetTelemetryProperty(telemetry, metadata.Key, metadata.Value); 26 | } 27 | } 28 | } 29 | 30 | private static void SetTelemetryProperty(ITelemetry telemetry, string key, string value) 31 | { 32 | if (telemetry is ISupportProperties propTelemetry && 33 | !string.IsNullOrEmpty(value) && 34 | !propTelemetry.Properties.ContainsKey(key)) 35 | { 36 | propTelemetry.Properties.Add(key, value); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/FlushAppInsightsHostedService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights; 2 | using Microsoft.Extensions.Hosting; 3 | 4 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 5 | 6 | internal class FlushAppInsightsHostedService : IHostedService 7 | { 8 | private readonly TelemetryClient _telemetryClient; 9 | private readonly IHostApplicationLifetime _hostLifetime; 10 | 11 | public FlushAppInsightsHostedService(TelemetryClient telemetryClient, IHostApplicationLifetime hostLifetime) 12 | { 13 | _telemetryClient = telemetryClient; 14 | _hostLifetime = hostLifetime; 15 | } 16 | 17 | public Task StartAsync(CancellationToken cancellationToken) 18 | { 19 | // flushes right after graceful shutdown of hosted services finished 20 | _hostLifetime.ApplicationStopped.Register(() => _telemetryClient.Flush()); 21 | 22 | return Task.CompletedTask; 23 | } 24 | 25 | public Task StopAsync(CancellationToken cancellationToken) 26 | { 27 | // flushes right after graceful shutdown of hosted services started 28 | _telemetryClient.Flush(); 29 | 30 | return Task.CompletedTask; 31 | } 32 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo( 4 | "Allegro.Extensions.ApplicationInsights.AspNetCore.UnitTests")] 5 | [assembly: InternalsVisibleTo( 6 | "Allegro.Extensions.ApplicationInsights.Demo.UnitTests")] -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SamplingConfig/PrintSamplingConfigurationService.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Hosting; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | 5 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 6 | 7 | internal class PrintSamplingConfigurationService : IHostedService 8 | { 9 | private readonly SamplingConfig _samplingConfig; 10 | private readonly ILogger _logger; 11 | 12 | public PrintSamplingConfigurationService( 13 | IOptions samplingConfig, 14 | ILogger logger) 15 | { 16 | _samplingConfig = samplingConfig.Value; 17 | _logger = logger; 18 | } 19 | 20 | public Task StartAsync(CancellationToken cancellationToken) 21 | { 22 | #pragma warning disable CA1848 23 | _logger.LogInformation("SamplingConfig: {@config}", _samplingConfig); 24 | #pragma warning restore CA1848 25 | return Task.CompletedTask; 26 | } 27 | 28 | public Task StopAsync(CancellationToken cancellationToken) 29 | { 30 | return Task.CompletedTask; 31 | } 32 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SamplingConfig/SamplingConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | 3 | /// 4 | /// Configuration for sampling 5 | /// 6 | public record SamplingConfig 7 | { 8 | /// 9 | /// Allow to set sampling mode 10 | /// 11 | public SamplingMode SamplingMode { get; init; } 12 | 13 | /// 14 | /// Sampling percentage for fixed mode 15 | /// 16 | public double? FixedSamplingPercentage { get; init; } 17 | 18 | /// 19 | /// A semi-colon delimited list of types that you don't want to be subject to sampling. 20 | /// Recognized types are: Dependency, Event, Exception, PageView, Request, Trace. All telemetry of the specified types is transmitted; the types that aren't specified will be sampled. 21 | /// 22 | public string SamplingExcludedTypes { get; init; } = "Event;Exception;Trace;PageView"; 23 | 24 | /// 25 | /// Advanced configuration for adaptive sampling 26 | /// 27 | public AdaptiveSamplingConfig AdaptiveSamplingConfig { get; init; } = new AdaptiveSamplingConfig(); 28 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SamplingConfig/SamplingMode.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | 3 | /// 4 | /// Sampling modes 5 | /// AdaptiveWithRules or FixedWithRules enable sampling ODATA exclusions rules 6 | /// 7 | public enum SamplingMode 8 | { 9 | /// 10 | /// Adaptive sampling with enabled ODATA exclusion rules 11 | /// 12 | AdaptiveWithRules, 13 | 14 | /// 15 | /// Adaptive sampling without rules 16 | /// 17 | Adaptive, 18 | 19 | /// 20 | /// Fixed sampling with enabled ODATA exclusion rules 21 | /// 22 | FixedWithRules, 23 | 24 | /// 25 | /// Fixed sampling without rules 26 | /// 27 | Fixed, 28 | 29 | /// 30 | /// No sampling at all 31 | /// 32 | Disabled 33 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SamplingExclusions/DependencyForFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.DataContracts; 2 | 3 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 4 | 5 | /// 6 | /// Default dependency filter types for ODATA exclusion rules 7 | /// 8 | [Serializable] 9 | public record DependencyForFilter 10 | { 11 | /// 12 | /// CloudRoleName of dependency 13 | /// 14 | public string CloudRoleName { get; } 15 | 16 | /// 17 | /// Type of dependency 18 | /// 19 | public string Type { get; } 20 | 21 | /// 22 | /// Target of dependency 23 | /// 24 | public string Target { get; } 25 | 26 | /// 27 | /// Name of dependency 28 | /// 29 | public string Name { get; } 30 | 31 | /// 32 | /// Duration of dependency 33 | /// 34 | public double Duration { get; } 35 | 36 | /// 37 | /// Success of dependency 38 | /// 39 | public bool? Success { get; } 40 | 41 | /// 42 | /// ResultCode of dependency 43 | /// 44 | public string ResultCode { get; } 45 | 46 | /// 47 | /// Maps dependencyTelemetry to filter understand by ODATA engine 48 | /// 49 | /// 50 | public DependencyForFilter(DependencyTelemetry dependencyTelemetry) 51 | { 52 | Type = dependencyTelemetry.Type ?? string.Empty; 53 | Target = dependencyTelemetry.Target ?? string.Empty; 54 | Name = dependencyTelemetry.Name ?? string.Empty; 55 | Duration = dependencyTelemetry.Duration.TotalMilliseconds; 56 | Success = dependencyTelemetry.Success; 57 | CloudRoleName = dependencyTelemetry.Context?.Cloud?.RoleName ?? string.Empty; 58 | ResultCode = dependencyTelemetry.ResultCode ?? string.Empty; 59 | } 60 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SamplingExclusions/ExcludeFromSamplingTelemetryConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | 3 | /// 4 | /// Configuration for sampling exclusion ODATA rules 5 | /// 6 | public record ExcludeFromSamplingTelemetryConfig 7 | { 8 | /// 9 | /// Sampling dependency exclusion ODATA rules 10 | /// 11 | public Dictionary? DependencyRules { get; init; } 12 | 13 | /// 14 | /// Sampling request exclusion ODATA rules 15 | /// 16 | public Dictionary? RequestRules { get; init; } 17 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SamplingExclusions/RequestForFilter.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.DataContracts; 2 | 3 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 4 | 5 | /// 6 | /// Default request filter types for ODATA exclusion rules 7 | /// 8 | [Serializable] 9 | public record RequestForFilter 10 | { 11 | /// 12 | /// Maps requestTelemetry to filter understand by ODATA engine 13 | /// 14 | /// 15 | public RequestForFilter(RequestTelemetry requestTelemetry) 16 | { 17 | Name = requestTelemetry.Name ?? string.Empty; 18 | Duration = requestTelemetry.Duration.TotalMilliseconds; 19 | Success = requestTelemetry.Success; 20 | CloudRoleName = requestTelemetry.Context?.Cloud?.RoleName ?? string.Empty; 21 | ResponseCode = requestTelemetry.ResponseCode ?? string.Empty; 22 | Url = requestTelemetry.Url?.ToString() ?? string.Empty; 23 | } 24 | 25 | /// 26 | /// CloudRoleName of request 27 | /// 28 | public string CloudRoleName { get; } 29 | 30 | /// 31 | /// Name of request 32 | /// 33 | public string Name { get; } 34 | 35 | /// 36 | /// Duration of request 37 | /// 38 | public double Duration { get; } 39 | 40 | /// 41 | /// Success of request 42 | /// 43 | public bool? Success { get; } 44 | 45 | /// 46 | /// ResponseCode of request 47 | /// 48 | public string ResponseCode { get; } 49 | 50 | /// 51 | /// Url of request 52 | /// 53 | public string Url { get; } 54 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/SendConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | 3 | /// 4 | /// Configuration for disabling/enabling sending telemetry from local machine 5 | /// 6 | public record SendConfig 7 | { 8 | /// 9 | /// Disable/enable sending telemetry from local machine 10 | /// 11 | public bool DisableLocally { get; init; } = true; 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/StartupLogger/StartupLogger.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 4 | 5 | /// 6 | /// Separate instance of logger for logging purposes in TelemetryInitializers 7 | /// 8 | public interface ITelemetryInitializerLogger : ILogger 9 | { } 10 | 11 | internal class TelemetryInitializerLogger : Logger, ITelemetryInitializerLogger 12 | { 13 | public TelemetryInitializerLogger(ILoggerFactory factory) : base(factory) 14 | { 15 | } 16 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/TelemetryContext/TelemetryContext.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Concurrent; 2 | 3 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 4 | 5 | /// 6 | /// Scoped to async local telemetry context which provide additional medata for each telemetry within scope 7 | /// 8 | public class TelemetryContext : ConcurrentDictionary 9 | { 10 | internal static readonly AsyncLocal _context = new AsyncLocal(); 11 | 12 | /// 13 | /// Scoped to async local telemetry context which provide additional medata for each telemetry within scope 14 | /// 15 | public static TelemetryContext Current 16 | { 17 | get => _context.Value ??= new TelemetryContext(); 18 | private set => _context.Value = value; 19 | } 20 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/TelemetryContext/TelemetryContextInitializer.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.Channel; 2 | using Microsoft.ApplicationInsights.DataContracts; 3 | using Microsoft.ApplicationInsights.Extensibility; 4 | using Microsoft.AspNetCore.Http; 5 | 6 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 7 | 8 | internal class TelemetryContextInitializer : ITelemetryInitializer 9 | { 10 | private readonly IHttpContextAccessor _contextAccessor; 11 | 12 | public TelemetryContextInitializer(IHttpContextAccessor contextAccessor) 13 | { 14 | _contextAccessor = contextAccessor; 15 | } 16 | 17 | public void Initialize(ITelemetry telemetry) 18 | { 19 | TelemetryContext context; 20 | 21 | if (TelemetryContext._context?.Value == null) 22 | { 23 | if (_contextAccessor.HttpContext?.Items != null && _contextAccessor.HttpContext.Items.ContainsKey(nameof(TelemetryContext))) 24 | { 25 | context = (TelemetryContext)_contextAccessor.HttpContext.Items[nameof(TelemetryContext)]; 26 | } 27 | else 28 | { 29 | return; 30 | } 31 | } 32 | else 33 | { 34 | context = TelemetryContext.Current; 35 | } 36 | 37 | var propTelemetry = (ISupportProperties)telemetry; 38 | 39 | foreach (var keyValue in context) 40 | SetProperty(propTelemetry, keyValue.Key, keyValue.Value); 41 | } 42 | 43 | private static void SetProperty(ISupportProperties propTelemetry, string key, string value) 44 | { 45 | if (!string.IsNullOrEmpty(value) && 46 | !propTelemetry.Properties.ContainsKey(key)) 47 | propTelemetry.Properties.Add(key, value); 48 | } 49 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.AspNetCore/TelemetryContext/TelemetryContextMiddleware.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Builder; 2 | using Microsoft.AspNetCore.Hosting; 3 | using Microsoft.AspNetCore.Http; 4 | 5 | namespace Allegro.Extensions.ApplicationInsights.AspNetCore; 6 | 7 | internal class TelemetryContextMiddleware 8 | { 9 | private readonly RequestDelegate _next; 10 | 11 | public TelemetryContextMiddleware(RequestDelegate next) 12 | { 13 | _next = next; 14 | } 15 | 16 | public async Task InvokeAsync(HttpContext context) 17 | { 18 | var current = TelemetryContext.Current; 19 | context.Items.Add(nameof(TelemetryContext), current); 20 | await _next(context); 21 | } 22 | } 23 | 24 | internal static class TelemetryContextMiddlewareExtensions 25 | { 26 | public static IApplicationBuilder UseTelemetryContextMiddleware(this IApplicationBuilder builder) 27 | { 28 | return builder.UseMiddleware(); 29 | } 30 | } 31 | 32 | internal class TelemetryContextMiddlewareStartupFilter : IStartupFilter 33 | { 34 | public Action Configure(Action next) 35 | { 36 | return app => 37 | { 38 | app.UseTelemetryContextMiddleware(); 39 | next(app); 40 | }; 41 | } 42 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo.UnitTests/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{cs,fs}] 2 | dotnet_diagnostic.CS1591.severity = none -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo.UnitTests/Allegro.Extensions.ApplicationInsights.Demo.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | runtime; build; native; contentfiles; analyzers; buildtransitive 16 | all 17 | 18 | 19 | runtime; build; native; contentfiles; analyzers; buildtransitive 20 | all 21 | 22 | 23 | all 24 | runtime; build; native; contentfiles; analyzers 25 | 26 | 27 | all 28 | runtime; compile; build; native; contentfiles; analyzers 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo.UnitTests/SamplingFilterTests.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | using AutoFixture; 3 | using FluentAssertions; 4 | using Microsoft.ApplicationInsights.DataContracts; 5 | 6 | namespace Allegro.Extensions.ApplicationInsights.Demo.UnitTests; 7 | 8 | public class SamplingFilterTests : FilterTests 9 | { 10 | [Theory] 11 | [InlineData("GET Method", "skyfall", "Team eq 'skyfall'", true)] 12 | [InlineData("GET Method", "skyfall", "OperationName eq 'GET Method'", true)] 13 | public void Dependencies_Rules(string operationName, string team, string filter, bool shouldExclude) 14 | { 15 | var fixture = new Fixture(); 16 | var dependency = new DependencyTelemetry( 17 | fixture.Create(), 18 | fixture.Create(), 19 | fixture.Create(), 20 | null); 21 | dependency.Context.Operation.Name = operationName; 22 | dependency.Properties[nameof(CustomTelemetryCloudApplicationInfo.TeamName)] = team; 23 | 24 | CustomDependencyForFilter DependencyMap(DependencyTelemetry d) => new(d); 25 | 26 | ApplyDependencyRules(dependency, filter, DependencyMap); 27 | 28 | ((ISupportSampling)dependency).SamplingPercentage.Should().Be(shouldExclude ? 100 : null); 29 | } 30 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/Allegro.Extensions.ApplicationInsights.Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | all 19 | runtime; compile; build; native; contentfiles; analyzers 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/Controllers/WeatherForecastController.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Http; 2 | using Allegro.Extensions.ApplicationInsights.AspNetCore; 3 | using Microsoft.AspNetCore.Mvc; 4 | using Microsoft.Extensions.Logging; 5 | 6 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 7 | 8 | namespace Allegro.Extensions.ApplicationInsights.Demo.Controllers; 9 | 10 | public record WeatherForecast(DateTime Date, int TemperatureC, string Summary); 11 | 12 | [ApiController] 13 | [Route("[controller]")] 14 | public class WeatherForecastController : ControllerBase 15 | { 16 | private static readonly string[] Summaries = new[] 17 | { 18 | "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" 19 | }; 20 | 21 | private readonly ILogger _logger; 22 | private readonly IHttpClientFactory _httpClientFactory; 23 | 24 | public WeatherForecastController(ILogger logger, IHttpClientFactory httpClientFactory) 25 | { 26 | _logger = logger; 27 | _httpClientFactory = httpClientFactory; 28 | } 29 | 30 | [HttpGet(Name = "GetWeatherForecast")] 31 | public async Task> Get() 32 | { 33 | TelemetryContext.Current["TraceIdentifier"] = HttpContext.TraceIdentifier; 34 | var client = _httpClientFactory.CreateClient(); 35 | await client.GetAsync("https://asd/asd/12331/3321"); 36 | // return Task.FromResult>( 37 | // Enumerable.Range(1, 5).Select( 38 | // index => new WeatherForecast( 39 | // DateTime.Now.AddDays(index), 40 | // Random.Shared.Next(-20, 55), 41 | // Summaries[Random.Shared.Next(Summaries.Length)])) 42 | // .ToArray()); 43 | return 44 | Enumerable.Range(1, 5).Select( 45 | index => new WeatherForecast( 46 | DateTime.Now.AddDays(index), 47 | Random.Shared.Next(-20, 55), 48 | Summaries[Random.Shared.Next(Summaries.Length)])) 49 | .ToArray(); 50 | } 51 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/CustomDependencyForFilter.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | using Microsoft.ApplicationInsights.DataContracts; 3 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 4 | 5 | namespace Allegro.Extensions.ApplicationInsights.Demo; 6 | 7 | public record CustomRequestForFilter : RequestForFilter 8 | { 9 | public string Team { get; } 10 | 11 | public CustomRequestForFilter(RequestTelemetry requestTelemetry) : base(requestTelemetry) 12 | { 13 | Team = requestTelemetry.Properties[nameof(CustomTelemetryCloudApplicationInfo.TeamName)]; 14 | } 15 | } 16 | 17 | public record CustomDependencyForFilter : DependencyForFilter 18 | { 19 | public string OperationName { get; } 20 | public string Team { get; } 21 | 22 | public CustomDependencyForFilter(DependencyTelemetry dependencyTelemetry) : base(dependencyTelemetry) 23 | { 24 | OperationName = dependencyTelemetry.Context.Operation.Name; 25 | Team = dependencyTelemetry.Properties[nameof(CustomTelemetryCloudApplicationInfo.TeamName)]; 26 | } 27 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/CustomTelemetryCloudApplicationInfo.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | 3 | namespace Allegro.Extensions.ApplicationInsights.Demo; 4 | 5 | internal class CustomTelemetryCloudApplicationInfo : TelemetryCloudApplicationInfo 6 | { 7 | /// 8 | /// Name of the team assigned to the service 9 | /// 10 | public string? TeamName 11 | { 12 | get => this.GetValueOrDefault(nameof(TeamName)); 13 | set 14 | { 15 | if (value != null) 16 | { 17 | this[nameof(TeamName)] = value; 18 | } 19 | } 20 | } 21 | 22 | public override void LoadFromEnv() 23 | { 24 | base.LoadFromEnv(); 25 | Add(nameof(TeamName), Environment.GetEnvironmentVariable(nameof(TeamName)) ?? EmptyPlaceholder); 26 | } 27 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo( 4 | "Allegro.Extensions.ApplicationInsights.Demo.UnitTests")] -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.ApplicationInsights.AspNetCore; 2 | using Allegro.Extensions.ApplicationInsights.Demo; 3 | using Allegro.Extensions.ApplicationInsights.Prometheus; 4 | using Microsoft.Extensions.Logging; 5 | using Prometheus; 6 | 7 | var builder = WebApplication.CreateBuilder(args); 8 | 9 | builder.Services.AddControllers(); 10 | builder.Services.AddHttpClient(); 11 | builder.Services.AddEndpointsApiExplorer(); 12 | builder.Services.AddSwaggerGen(); 13 | builder.Services.AddApplicationInsightsTelemetry(); 14 | builder.Services.AddApplicationInsightsExtensions(builder.Configuration, builder.Environment, b => 15 | { 16 | void ConfigureCloudInfo(CustomTelemetryCloudApplicationInfo p) 17 | { 18 | p.TeamName = "skyfall"; 19 | p.ApplicationName = "demos-app-insights"; 20 | } 21 | 22 | b.ConfigureTelemetryInitializerLogger(p => p.AddConsole()); 23 | b.AddApplicationInsightsCloudApplicationInfo(ConfigureCloudInfo); 24 | b.AddApplicationInsightsSamplingConfig(); 25 | b.AddApplicationInsightsTelemetryContext(); 26 | b.AddApplicationInsightsFlush(); 27 | b.AddApplicationInsightsSendConfig(); 28 | b.AddApplicationInsightsSamplingExclusions(p => new CustomDependencyForFilter(p), p => new CustomRequestForFilter(p)); 29 | }); // customization 30 | builder.Services.AddApplicationInsightsToPrometheus(builder.Configuration); // prometheus 31 | 32 | var app = builder.Build(); 33 | 34 | if (app.Environment.IsDevelopment()) 35 | { 36 | app.UseSwagger(); 37 | app.UseSwaggerUI(); 38 | } 39 | 40 | app.UseMetricServer(); 41 | app.UseHttpsRedirection(); 42 | app.UseAuthorization(); 43 | app.MapControllers(); 44 | app.Run(); -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://json.schemastore.org/launchsettings.json", 3 | "iisSettings": { 4 | "windowsAuthentication": false, 5 | "anonymousAuthentication": true, 6 | "iisExpress": { 7 | "applicationUrl": "http://localhost:2790", 8 | "sslPort": 44348 9 | } 10 | }, 11 | "profiles": { 12 | "Allegro.Extensions.ApplicationInsights.Demo": { 13 | "commandName": "Project", 14 | "dotnetRunMessages": true, 15 | "launchBrowser": true, 16 | "launchUrl": "swagger", 17 | "applicationUrl": "https://localhost:7123;http://localhost:5202", 18 | "environmentVariables": { 19 | "ASPNETCORE_ENVIRONMENT": "Development" 20 | } 21 | }, 22 | "IIS Express": { 23 | "commandName": "IISExpress", 24 | "launchBrowser": true, 25 | "launchUrl": "swagger", 26 | "environmentVariables": { 27 | "ASPNETCORE_ENVIRONMENT": "Development" 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/appsettings.Development.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "LogLevel": { 4 | "Default": "Information", 5 | "Microsoft.AspNetCore": "Warning" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Demo/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "ApplicationInsights": { 3 | "DisableLocally": true, 4 | "SamplingMode": "AdaptiveWithRules", 5 | "FixedSamplingPercentage": 0.01, 6 | "ExcludeFromSamplingTelemetryConfig": { 7 | "DependencyRules": { 8 | "AzureServiceBus": "Type eq 'Azure Service Bus' and (duration ge 5000 or success eq false)" 9 | }, 10 | "RequestRules": { 11 | "MyService": "Team eq 'skyfall'" 12 | } 13 | }, 14 | "ApplicationInsightsToPrometheusMetrics": { 15 | "DependenciesTypesIncluded": [ 16 | "HTTP" 17 | ], 18 | "IncludeBusRequests": false, 19 | "ShouldGeneralizeHttpDependencyOperationName": false, 20 | "ShouldGeneralizeHttpDependencyTargetUrl": false, 21 | "MaxUrisPerHost": 100 22 | }, 23 | "ConnectionString": "InstrumentationKey=11955cd8-5cd1-4fde-803b-cb31b8b320e4;IngestionEndpoint=https://westeurope-3.in.applicationinsights.azure.com/;LiveEndpoint=https://westeurope.livediagnostics.monitor.azure.com/" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus.UnitTests/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{cs,fs}] 2 | dotnet_diagnostic.CS1591.severity = none -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus.UnitTests/Allegro.Extensions.ApplicationInsights.Prometheus.UnitTests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | runtime; build; native; contentfiles; analyzers; buildtransitive 15 | all 16 | 17 | 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | all 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers 24 | 25 | 26 | all 27 | runtime; compile; build; native; contentfiles; analyzers 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus/Allegro.Extensions.ApplicationInsights.Prometheus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net6.0 5 | enable 6 | true 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | all 15 | runtime; build; native; contentfiles; analyzers 16 | 17 | 18 | all 19 | runtime; compile; build; native; contentfiles; analyzers 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus/ApplicationInsightsToPrometheusMetricsConfig.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.ApplicationInsights.Prometheus; 2 | 3 | /// 4 | /// Configuration class for ApplicationInsightsToPrometheusMetrics mechanism 5 | /// 6 | public class ApplicationInsightsToPrometheusMetricsConfig 7 | { 8 | /// 9 | /// Section path for this configuration class 10 | /// 11 | public const string SectionName = "ApplicationInsights:ApplicationInsightsToPrometheusMetrics"; 12 | 13 | /// 14 | /// Which dependency types should be exported 15 | /// 16 | public List DependenciesTypesIncluded { get; set; } = new(); 17 | 18 | /// 19 | /// Should include Azure Bus requests 20 | /// 21 | public bool IncludeBusRequests { get; set; } 22 | 23 | /// 24 | /// Should generalize http dependency operation name 25 | /// 26 | public bool ShouldGeneralizeHttpDependencyOperationName { get; set; } 27 | 28 | /// 29 | /// Should generalize http dependency target url 30 | /// 31 | public bool ShouldGeneralizeHttpDependencyTargetUrl { get; set; } 32 | 33 | /// 34 | /// How many uris per host can be exported before circuit break 35 | /// 36 | public int MaxUrisPerHost { get; set; } = 100; 37 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Allegro.Extensions.ApplicationInsights.Prometheus.UnitTests")] -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus/PrometheusMetrics.cs: -------------------------------------------------------------------------------- 1 | using Prometheus; 2 | 3 | namespace Allegro.Extensions.ApplicationInsights.Prometheus; 4 | 5 | internal class PrometheusMetrics 6 | { 7 | public Histogram ApplicationInsightsDependencyDuration { get; } 8 | public Histogram ApplicationInsightsRequestDuration { get; } 9 | 10 | public PrometheusMetrics(IMetricFactory? metrics = null) 11 | { 12 | metrics ??= Metrics.WithCustomRegistry(Metrics.DefaultRegistry); 13 | ApplicationInsightsDependencyDuration = DependencyHistogramFactory(metrics); 14 | ApplicationInsightsRequestDuration = RequestHistogramFactory(metrics); 15 | } 16 | 17 | private static Histogram DependencyHistogramFactory(IMetricFactory metrics) 18 | { 19 | return metrics.CreateHistogram( 20 | "ai_dependency_duration_seconds", 21 | "The duration of dependency call", 22 | new HistogramConfiguration 23 | { 24 | LabelNames = new[] 25 | { 26 | "service", "type", "target", "name", "operation_name", "success", "resultCode" 27 | }, 28 | Buckets = new[] { 0.008, 0.016, 0.032, 0.064, 0.128, 0.512, 1, 4, 16 } 29 | }); 30 | } 31 | 32 | private static Histogram RequestHistogramFactory(IMetricFactory metrics) 33 | { 34 | return metrics.CreateHistogram( 35 | "ai_request_duration_seconds", 36 | "The duration of request", 37 | new HistogramConfiguration 38 | { 39 | LabelNames = new[] { "service", "name", "success", "resultCode" }, 40 | Buckets = new[] { 0.008, 0.016, 0.032, 0.064, 0.128, 0.512, 1, 4, 16 } 41 | }); 42 | } 43 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.Prometheus/StartupExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.ApplicationInsights.Extensibility; 2 | using Microsoft.Extensions.Configuration; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace Allegro.Extensions.ApplicationInsights.Prometheus; 6 | 7 | /// 8 | /// IServiceCollection extensions 9 | /// 10 | public static class StartupExtensions 11 | { 12 | /// 13 | /// Add export of application insights telemetry to prometheus metrics 14 | /// 15 | public static IServiceCollection AddApplicationInsightsToPrometheus( 16 | this IServiceCollection services, 17 | IConfiguration configuration) 18 | { 19 | services.AddSingleton(); 20 | services.Configure( 21 | configuration.GetSection(ApplicationInsightsToPrometheusMetricsConfig.SectionName)); 22 | services.AddSingleton(); 23 | return services; 24 | } 25 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/Allegro.Extensions.ApplicationInsights.sln.DotSettings: -------------------------------------------------------------------------------- 1 |  2 | True 3 | True 4 | True 5 | True -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.0] - 2023-09-27 9 | ### Allegro.Extensions.ApplicationInsights.AspNetCore 10 | 11 | * Initiated Allegro.Extensions.ApplicationInsights.AspNetCore, check readme for features 12 | 13 | ### Allegro.Extensions.ApplicationInsights.Prometheus 14 | 15 | * Initiated Allegro.Extensions.ApplicationInsights.Prometheus, check readme for features 16 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.ApplicationInsights/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Demo/Allegro.Extensions.AspNetCore.Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Demo/Controllers/SkipOnProdController.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.AspNetCore.Attributes; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace Allegro.Extensions.AspNetCore.Demo.Controllers 5 | { 6 | [ApiController] 7 | [Route("api/skip-on-prod")] 8 | [SkipOnProd] 9 | public class SkipOnProdController : ControllerBase 10 | { 11 | [HttpGet("hello")] 12 | public IActionResult Hello() 13 | { 14 | return Ok("Welcome to test environment! If you see this on production, something went wrong :("); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Demo/Controllers/TestController.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Mvc; 2 | 3 | namespace Allegro.Extensions.AspNetCore.Demo.Controllers 4 | { 5 | [ApiController] 6 | [Route("api/test")] 7 | public class TestController : ControllerBase 8 | { 9 | [HttpGet("hello")] 10 | public IActionResult Hello() 11 | { 12 | return Ok("Welcome to production!"); 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.AspNetCore.Demo 2 | { 3 | public static class Program 4 | { 5 | public static void Main(string[] args) 6 | { 7 | Host.CreateDefaultBuilder(args) 8 | .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()) 9 | .Build() 10 | .Run(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Demo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Allegro.Extensions.AspNetCore.Demo": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Production", 9 | "Environment": "xyz" 10 | }, 11 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Demo/Startup.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.AspNetCore.Demo.Controllers; 2 | using Allegro.Extensions.AspNetCore.ErrorHandling; 3 | using Allegro.Extensions.AspNetCore.Extensions; 4 | 5 | namespace Allegro.Extensions.AspNetCore.Demo 6 | { 7 | public class Startup 8 | { 9 | private readonly IWebHostEnvironment _env; 10 | 11 | public Startup(IWebHostEnvironment env) 12 | { 13 | _env = env; 14 | } 15 | 16 | public void Configure(IApplicationBuilder app) 17 | { 18 | app 19 | .UseFluentErrorHandlingMiddleware() 20 | .UseRouting() 21 | .UseSwagger() 22 | .UseSwaggerUI() 23 | .UseEndpoints(endpoints => { endpoints.MapControllers(); }); 24 | } 25 | 26 | public void ConfigureServices(IServiceCollection services) 27 | { 28 | services 29 | .AddFluentErrorHandlingMiddleware( 30 | logError: error => Console.WriteLine($"Error: {error.Message}"), 31 | logWarning: warning => Console.WriteLine($"Warning: {warning.Message}"), 32 | builder => builder.WithCustomAllegroErrorHandling() 33 | ) 34 | .AddControllers() 35 | .AddSkipOnProd(_env) 36 | .AddFluentModelStateValidationHandling(builder => builder.WithCustomAllegroErrorHandling()); 37 | 38 | services.AddSwaggerGen(); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.Tests.Unit/Allegro.Extensions.AspNetCore.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1A5C6678-1714-4D2A-A0B5-DF08B4796E92}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.AspNetCore", "Allegro.Extensions.AspNetCore\Allegro.Extensions.AspNetCore.csproj", "{2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.AspNetCore.Demo", "Allegro.Extensions.AspNetCore.Demo\Allegro.Extensions.AspNetCore.Demo.csproj", "{B1903BE3-CB8E-44C6-9E68-5D7DFC1C3EE6}" 8 | EndProject 9 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.AspNetCore.Tests.Unit", "Allegro.Extensions.AspNetCore.Tests.Unit\Allegro.Extensions.AspNetCore.Tests.Unit.csproj", "{BBB95FD3-301B-47E9-9F21-4818E55DFFAF}" 10 | EndProject 11 | Global 12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 13 | Debug|Any CPU = Debug|Any CPU 14 | Release|Any CPU = Release|Any CPU 15 | EndGlobalSection 16 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 17 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Release|Any CPU.Build.0 = Release|Any CPU 21 | {B1903BE3-CB8E-44C6-9E68-5D7DFC1C3EE6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 22 | {B1903BE3-CB8E-44C6-9E68-5D7DFC1C3EE6}.Debug|Any CPU.Build.0 = Debug|Any CPU 23 | {B1903BE3-CB8E-44C6-9E68-5D7DFC1C3EE6}.Release|Any CPU.ActiveCfg = Release|Any CPU 24 | {B1903BE3-CB8E-44C6-9E68-5D7DFC1C3EE6}.Release|Any CPU.Build.0 = Release|Any CPU 25 | {BBB95FD3-301B-47E9-9F21-4818E55DFFAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {BBB95FD3-301B-47E9-9F21-4818E55DFFAF}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {BBB95FD3-301B-47E9-9F21-4818E55DFFAF}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {BBB95FD3-301B-47E9-9F21-4818E55DFFAF}.Release|Any CPU.Build.0 = Release|Any CPU 29 | EndGlobalSection 30 | EndGlobal 31 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.AspNetCore 5 | ... 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/Attributes/SkipOnProdAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.AspNetCore.Attributes 2 | { 3 | /// 4 | /// Disables the controller on environments other than test (Environment=dev|uat), unless HostEnvironment is Development. 5 | /// 6 | [AttributeUsage(AttributeTargets.Class)] 7 | public class SkipOnProdAttribute : Attribute 8 | { 9 | } 10 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/ErrorHandling/IErrorSerializer.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.AspNetCore.ErrorHandling; 2 | 3 | /// 4 | /// Defines used by error handling middleware serializer 5 | /// 6 | public interface IErrorSerializer 7 | { 8 | /// 9 | /// Serialize error response 10 | /// 11 | string Serialize(object errorResponse); 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/ErrorHandling/Internals/ErrorResponse.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.AspNetCore.ErrorHandling.Internals; 2 | 3 | internal record ErrorResponse( 4 | string Code, 5 | string Message, 6 | string? UserMessage = default, 7 | string? Path = default, 8 | string? Details = default); 9 | 10 | internal record ErrorResponsesHolder( 11 | IEnumerable Errors); -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/ErrorHandling/Internals/InvalidModelStateResponseFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Http; 2 | using Microsoft.AspNetCore.Mvc; 3 | using Microsoft.AspNetCore.Mvc.ModelBinding; 4 | 5 | namespace Allegro.Extensions.AspNetCore.ErrorHandling.Internals 6 | { 7 | internal class InvalidModelStateResponseFactory 8 | { 9 | private readonly Func? _customModelStateValidationHandler; 10 | 11 | public InvalidModelStateResponseFactory(Func? customModelStateValidationHandler = null) 12 | { 13 | _customModelStateValidationHandler = customModelStateValidationHandler; 14 | } 15 | 16 | public IActionResult BuildResponse(ActionContext context) 17 | { 18 | var errorResponse = _customModelStateValidationHandler is not null 19 | ? HandleCustomResponse(context) 20 | : DefaultResponse(context); 21 | 22 | return new ObjectResult(errorResponse.Response) { StatusCode = errorResponse.StatusCode }; 23 | } 24 | 25 | private static (int StatusCode, object Response) DefaultResponse(ActionContext context) 26 | { 27 | var errorResponseHolder = new ErrorResponsesHolder( 28 | Errors: context.ModelState.Values.Select( 29 | modelStateEntry => new ErrorResponse( 30 | modelStateEntry.ValidationState.ToString(), 31 | GetErrorMessageFrom(modelStateEntry) 32 | ))); 33 | return (StatusCodes.Status400BadRequest, errorResponseHolder); 34 | } 35 | 36 | private (int StatusCode, object Response) HandleCustomResponse(ActionContext context) 37 | { 38 | var error = _customModelStateValidationHandler!(context); 39 | return error is not null 40 | ? (error.ResponseCode, error.BuildErrorResponse()) 41 | : DefaultResponse(context); 42 | } 43 | 44 | private static string GetErrorMessageFrom(ModelStateEntry value) 45 | { 46 | return string.Join(", ", value.Errors.Select(e => e.ErrorMessage)); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/ErrorHandling/Internals/SystemTextJsonWebErrorSerializer.cs: -------------------------------------------------------------------------------- 1 | using System.Text.Json; 2 | 3 | namespace Allegro.Extensions.AspNetCore.ErrorHandling.Internals; 4 | 5 | internal class SystemTextJsonWebErrorSerializer : IErrorSerializer 6 | { 7 | public string Serialize(object errorResponse) => 8 | JsonSerializer.Serialize(errorResponse, new JsonSerializerOptions(JsonSerializerDefaults.Web)); 9 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/Extensions/MvcBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.AspNetCore.Attributes; 2 | using Allegro.Extensions.AspNetCore.Features; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Hosting; 5 | 6 | namespace Allegro.Extensions.AspNetCore.Extensions 7 | { 8 | /// 9 | /// Asp Mvc Builder Extensions 10 | /// 11 | public static class MvcBuilderExtensions 12 | { 13 | /// 14 | /// Configures the based on `Environment` env variable and ASP.NET hosting environment. 15 | /// Assumes that `IsTestEnv = Environment == dev|uat || HostEnvironment.IsDevelopment()`. 16 | /// 17 | /// IMvcBuilder - target of extension method 18 | /// Hosting environment 19 | /// Allows to override default test environments (dev|uat) 20 | public static IMvcBuilder AddSkipOnProd( 21 | this IMvcBuilder mvcBuilder, 22 | IHostEnvironment aspNetEnvironment, 23 | string[]? overrideTestEnvironments = null) 24 | { 25 | return mvcBuilder 26 | .ConfigureApplicationPartManager(mgr => 27 | { 28 | mgr.FeatureProviders.Add( 29 | new SkipControllerFeatureProvider( 30 | aspNetEnvironment, 31 | overrideTestEnvironments)); 32 | }); 33 | } 34 | 35 | /// 36 | /// Configures the . 37 | /// 38 | /// IMvcBuilder - target of extension method 39 | /// Is currently running on test environment 40 | public static IMvcBuilder AddSkipOnProd(this IMvcBuilder mvcBuilder, bool isTestEnv) 41 | { 42 | return mvcBuilder 43 | .ConfigureApplicationPartManager(mgr => 44 | { 45 | mgr.FeatureProviders.Add(new SkipControllerFeatureProvider(isTestEnv)); 46 | }); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/Allegro.Extensions.AspNetCore/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.CompilerServices; 2 | 3 | [assembly: InternalsVisibleTo("Allegro.Extensions.AspNetCore.Tests.Unit")] -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.4.0] - 2024-01-11 9 | 10 | ### Added 11 | 12 | * New `AddFluentErrorHandlingMiddleware` overload that allows to pass factories for logging methods. 13 | 14 | ## [1.3.0] - 2022-06-03 15 | 16 | ### Added 17 | 18 | * Default exception handling in controllers with custom error mapping end response provider 19 | 20 | ## [1.2.0] - 2022-05-06 21 | 22 | ### Removed 23 | 24 | * Removed targeting net5.0 25 | 26 | ## [1.1.0] - 2022-03-28 27 | 28 | ### Changed 29 | 30 | * Multitargeting net5.0;net6.0 31 | 32 | ## [1.0.1] - 2022-03-15 33 | 34 | ### Changed 35 | 36 | * Minor code & tests refactor 37 | 38 | ## [1.0.0] - 2022-03-10 39 | 40 | ### Added 41 | 42 | * Initiated Allegro.Extensions.AspNetCore project 43 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.AspNetCore/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.4.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Allegro.Extensions.Cqrs.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Allegro.Extensions.Cqrs.Abstractions 4 | Contains Cqrs basic abstractions used in Allegro services 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Commands/Command.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | 3 | /// 4 | /// Cqrs base representation of command. 5 | /// 6 | public abstract record Command 7 | { 8 | /// 9 | /// Command identifier 10 | /// 11 | public string Id { get; } = Guid.NewGuid().ToString(); 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Commands/ICommandDispatcher.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | 3 | /// 4 | /// Cqrs command dispatcher interface 5 | /// 6 | public interface ICommandDispatcher 7 | { 8 | /// 9 | /// Sends command to dispatcher 10 | /// 11 | Task Send(TCommand command) where TCommand : Command; 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Commands/ICommandHandler.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | 3 | /// 4 | /// Marker interface to add handler for command. In most cases changes state. 5 | /// 6 | public interface ICommandHandler where TCommand : Command 7 | { 8 | /// 9 | /// Handles command request 10 | /// 11 | Task Handle(TCommand command); 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Commands/ICommandValidator.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | 3 | /// 4 | /// Marker interface that allows to execute more complicated validations before action execution. 5 | /// 6 | /// Supported command type 7 | public interface ICommandValidator where T : Command 8 | { 9 | /// 10 | /// Validates command before execution. Should throw ValidationException or other exception. 11 | /// 12 | Task Validate(T command); 13 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/DecoratorAttribute.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions; 2 | 3 | /// 4 | /// Marker attribute - allows to mark ICommandHandler, IQueryHandler as decorator (pattern) of main handler. 5 | /// 6 | [AttributeUsage(AttributeTargets.Class)] 7 | public class DecoratorAttribute : Attribute 8 | { 9 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Queries/IQueryDispatcher.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Queries; 2 | 3 | /// 4 | /// Cqrs query dispatcher interface 5 | /// 6 | public interface IQueryDispatcher 7 | { 8 | /// 9 | /// Sends query to dispatcher 10 | /// 11 | /// Type of data returned by query 12 | /// Query data 13 | Task Query(Query query, CancellationToken cancellationToken); 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Queries/IQueryHandler.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Queries; 2 | 3 | /// 4 | /// Cqrs query handler interface 5 | /// 6 | /// Type of supported query 7 | /// Type of data returned by query 8 | public interface IQueryHandler where TQuery : Query 9 | { 10 | /// 11 | /// Handles query execution. In most cases reading data from read-model directly. 12 | /// 13 | Task Handle(TQuery query, CancellationToken cancellationToken); 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Queries/IQueryValidator.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Queries; 2 | 3 | /// 4 | /// Marker interface that allows to execute more complicated validations before action execution. 5 | /// 6 | /// Supported query type 7 | public interface IQueryValidator where T : Query 8 | { 9 | /// 10 | /// Validates query before execution. Should throw ValidationException or other exception. 11 | /// 12 | Task Validate(T query, CancellationToken cancellationToken); 13 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Abstractions/Queries/Query.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Abstractions.Queries; 2 | 3 | /// 4 | /// Cqrs base representation of query. 5 | /// 6 | public abstract record Query 7 | { 8 | /// 9 | /// Query identifier 10 | /// 11 | public string Id { get; } = Guid.NewGuid().ToString(); 12 | } 13 | 14 | /// 15 | /// Cqrs base representation of query. 16 | /// 17 | /// Type of data returned by query 18 | public abstract record Query : Query; -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Allegro.Extensions.Cqrs.Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Commands/BarCommand.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions; 2 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 3 | using FluentValidation; 4 | using Microsoft.Extensions.Logging; 5 | 6 | namespace Allegro.Extensions.Cqrs.Demo.Commands; 7 | 8 | public record BarCommand(string Name) : Command; 9 | 10 | internal sealed class BarCommandFluentValidator : AbstractValidator 11 | { 12 | public BarCommandFluentValidator() 13 | { 14 | RuleFor(p => p.Name).NotEmpty(); 15 | } 16 | } 17 | 18 | internal sealed class BarCommandValidator : ICommandValidator 19 | { 20 | public Task Validate(BarCommand command) 21 | { 22 | if (string.IsNullOrEmpty(command.Name)) 23 | { 24 | throw new ValidationException("Missing name!"); 25 | } 26 | 27 | return Task.CompletedTask; 28 | } 29 | } 30 | 31 | internal sealed class BarCommandHandler : ICommandHandler 32 | { 33 | private readonly ILogger _logger; 34 | 35 | public BarCommandHandler(ILogger logger) 36 | { 37 | _logger = logger; 38 | } 39 | 40 | public Task Handle(BarCommand command) 41 | { 42 | #pragma warning disable CA1848 43 | _logger.LogInformation("Handle Bar"); 44 | #pragma warning restore CA1848 45 | return Task.CompletedTask; 46 | } 47 | } 48 | 49 | [Decorator] 50 | internal sealed class BarCommandHandlerDecorator : ICommandHandler 51 | { 52 | private readonly ICommandHandler _decorated; 53 | private readonly ILogger _logger; 54 | 55 | public BarCommandHandlerDecorator(ICommandHandler decorated, ILogger logger) 56 | { 57 | _decorated = decorated; 58 | _logger = logger; 59 | } 60 | 61 | public async Task Handle(BarCommand command) 62 | { 63 | #pragma warning disable CA1848 64 | _logger.LogInformation("Before handle"); 65 | await _decorated.Handle(command); 66 | _logger.LogInformation("After handle"); 67 | #pragma warning restore CA1848 68 | } 69 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Controllers/CommandController.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | using Allegro.Extensions.Cqrs.Demo.Commands; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace Allegro.Extensions.Cqrs.Demo.Controllers; 6 | 7 | [ApiController] 8 | [Route("commands")] 9 | public class CommandController : ControllerBase 10 | { 11 | private readonly ICommandDispatcher _commandDispatcher; 12 | 13 | public CommandController(ICommandDispatcher commandDispatcher) 14 | { 15 | _commandDispatcher = commandDispatcher; 16 | } 17 | 18 | [HttpPost("bar")] 19 | public async Task Bar(BarCommand command) 20 | { 21 | await _commandDispatcher.Send(command); 22 | return Ok(command.Id); 23 | } 24 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Controllers/QueryController.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions.Queries; 2 | using Allegro.Extensions.Cqrs.Demo.Queries; 3 | using Microsoft.AspNetCore.Mvc; 4 | 5 | namespace Allegro.Extensions.Cqrs.Demo.Controllers; 6 | 7 | [ApiController] 8 | [Route("queries")] 9 | public class QueryController : ControllerBase 10 | { 11 | private readonly IQueryDispatcher _queryDispatcher; 12 | 13 | public QueryController(IQueryDispatcher queryDispatcher) 14 | { 15 | _queryDispatcher = queryDispatcher; 16 | } 17 | 18 | [HttpGet("bar")] 19 | public async Task Bar([FromQuery] string? id, CancellationToken cancellationToken) 20 | { 21 | var result = await _queryDispatcher.Query(new BarQuery(id), cancellationToken); 22 | return Ok(result); 23 | } 24 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Cqrs.Demo; 2 | 3 | public static class Program 4 | { 5 | public static void Main(string[] args) 6 | { 7 | Host.CreateDefaultBuilder(args) 8 | .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()) 9 | .Build() 10 | .Run(); 11 | } 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Allegro.Extensions.Cqrs.Demo": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Production" 9 | }, 10 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Queries/BarQuery.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions; 2 | using Allegro.Extensions.Cqrs.Abstractions.Queries; 3 | using Allegro.Extensions.Cqrs.Demo.Commands; 4 | using FluentValidation; 5 | using Microsoft.Extensions.Logging; 6 | 7 | namespace Allegro.Extensions.Cqrs.Demo.Queries; 8 | 9 | public record BarData(string SomeData); 10 | internal sealed record BarQuery(string? SomeId) : Query; 11 | 12 | internal sealed class BarQueryFluentValidator : AbstractValidator 13 | { 14 | public BarQueryFluentValidator() 15 | { 16 | RuleFor(p => p.SomeId).NotEmpty(); 17 | } 18 | } 19 | 20 | internal sealed class BarQueryValidator : IQueryValidator 21 | { 22 | public Task Validate(BarQuery query, CancellationToken cancellationToken) 23 | { 24 | if (string.IsNullOrEmpty(query.SomeId)) 25 | { 26 | throw new ValidationException("Missing some id!"); 27 | } 28 | 29 | return Task.CompletedTask; 30 | } 31 | } 32 | 33 | internal sealed class BarQueryHandler : IQueryHandler 34 | { 35 | public Task Handle(BarQuery query, CancellationToken cancellationToken) 36 | { 37 | // should take data directly from read model on dedicates sql query to view of some data 38 | return Task.FromResult(new BarData("Some data 1")); 39 | } 40 | } 41 | 42 | [Decorator] 43 | internal sealed class BarQueryHandlerDecorator : IQueryHandler 44 | { 45 | private readonly IQueryHandler _decorated; 46 | private readonly ILogger _logger; 47 | 48 | public BarQueryHandlerDecorator(IQueryHandler decorated, ILogger logger) 49 | { 50 | _decorated = decorated; 51 | _logger = logger; 52 | } 53 | 54 | public async Task Handle(BarQuery query, CancellationToken cancellationToken) 55 | { 56 | #pragma warning disable CA1848 57 | _logger.LogInformation("Before handle"); 58 | var result = await _decorated.Handle(query, cancellationToken); 59 | _logger.LogInformation("After handle"); 60 | #pragma warning restore CA1848 61 | return result; 62 | } 63 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Demo/Startup.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | using Allegro.Extensions.Cqrs.Abstractions.Queries; 3 | using Allegro.Extensions.Cqrs.Commands; 4 | using Allegro.Extensions.Cqrs.Demo.Commands; 5 | using Allegro.Extensions.Cqrs.Demo.Queries; 6 | using Allegro.Extensions.Cqrs.FluentValidations; 7 | using Allegro.Extensions.Cqrs.Queries; 8 | 9 | namespace Allegro.Extensions.Cqrs.Demo; 10 | 11 | public class Startup 12 | { 13 | private readonly IWebHostEnvironment _env; 14 | 15 | public Startup(IWebHostEnvironment env) 16 | { 17 | _env = env; 18 | } 19 | 20 | public void Configure(IApplicationBuilder app) 21 | { 22 | app 23 | .UseRouting() 24 | .UseSwagger() 25 | .UseSwaggerUI() 26 | .UseEndpoints(endpoints => { endpoints.MapControllers(); }); 27 | } 28 | 29 | public void ConfigureServices(IServiceCollection services) 30 | { 31 | var cqrsAssemblies = new[] { typeof(Startup).Assembly }; 32 | services 33 | .AddCommands(cqrsAssemblies) 34 | .AddQueries(cqrsAssemblies) 35 | .AddCqrsFluentValidations(cqrsAssemblies) 36 | .AddControllers(); 37 | services.TryDecorate, BarCommandHandlerDecorator>(); 38 | services.TryDecorate, BarQueryHandlerDecorator>(); 39 | services.AddSwaggerGen(); 40 | } 41 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.FluentValidations/Allegro.Extensions.Cqrs.FluentValidations.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Allegro.Extensions.Cqrs.FluentValidations 4 | Contains FluentVlidations extension for Allegro.Extensions.Cqrs 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.FluentValidations/FluentCommandValidator.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | using FluentValidation; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace Allegro.Extensions.Cqrs.FluentValidations; 6 | 7 | internal sealed class FluentCommandValidator : ICommandValidator 8 | where T : Command 9 | { 10 | private readonly IServiceProvider _serviceProvider; 11 | 12 | public FluentCommandValidator(IServiceProvider serviceProvider) 13 | { 14 | _serviceProvider = serviceProvider; 15 | } 16 | 17 | public async Task Validate(T command) 18 | { 19 | var requestValidators = _serviceProvider.GetServices>(); 20 | 21 | var failures = (await Task.WhenAll(requestValidators.Select(v => v.ValidateAsync(command)))) 22 | .SelectMany(result => result.Errors) 23 | .Where(f => f != null) 24 | .ToList(); 25 | 26 | if (failures.Count != 0) 27 | { 28 | throw new ValidationException(failures); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.FluentValidations/FluentQueryValidator.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions.Queries; 2 | using FluentValidation; 3 | using Microsoft.Extensions.DependencyInjection; 4 | 5 | namespace Allegro.Extensions.Cqrs.FluentValidations; 6 | 7 | internal sealed class FluentQueryValidator : IQueryValidator 8 | where T : Query 9 | { 10 | private readonly IServiceProvider _serviceProvider; 11 | 12 | public FluentQueryValidator(IServiceProvider serviceProvider) 13 | { 14 | _serviceProvider = serviceProvider; 15 | } 16 | 17 | public async Task Validate(T query, CancellationToken cancellationToken) 18 | { 19 | var requestValidators = _serviceProvider.GetServices>(); 20 | 21 | var failures = (await Task.WhenAll(requestValidators.Select(v => v.ValidateAsync(query, cancellationToken)))) 22 | .SelectMany(result => result.Errors) 23 | .Where(f => f != null) 24 | .ToList(); 25 | 26 | if (failures.Count != 0) 27 | { 28 | throw new ValidationException(failures); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.FluentValidations/StartupExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 3 | using Allegro.Extensions.Cqrs.Abstractions.Queries; 4 | using FluentValidation; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace Allegro.Extensions.Cqrs.FluentValidations; 8 | 9 | /// 10 | /// Startup Extensions - expose registration of Fluent Validations for CQRS in application. 11 | /// 12 | public static class StartupExtensions 13 | { 14 | /// 15 | /// Add fluent validations for CQRS and register all IValidator from given assemblies 16 | /// 17 | /// 18 | /// Assembly collection in which IValidators should be looked for. 19 | /// Determines whether only public classes should be registered 20 | public static IServiceCollection AddCqrsFluentValidations( 21 | this IServiceCollection services, 22 | IEnumerable assemblies, 23 | bool publicOnly = false) 24 | { 25 | services.Scan(s => s.FromAssemblies(assemblies) 26 | .AddClasses(c => c.AssignableTo(typeof(IValidator<>)), publicOnly) 27 | .AsImplementedInterfaces() 28 | .WithScopedLifetime()); 29 | 30 | services 31 | .Scan(s => s.FromCallingAssembly() 32 | .AddClasses( 33 | c => c.AssignableToAny(typeof(ICommandValidator<>), typeof(IQueryValidator<>)), 34 | publicOnly) 35 | .AsImplementedInterfaces() 36 | .WithScopedLifetime()); 37 | 38 | return services; 39 | } 40 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.Tests.Unit/Allegro.Extensions.Cqrs.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | false 4 | true 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Allegro.Extensions.Cqrs 4 | Contains Cqrs defualt implementation of automatic registration, default dispatchers and command actions support used in Allegro services 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/Commands/CommandDispatcher.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Allegro.Extensions.Cqrs.Commands; 5 | 6 | // TODO: can we extract common logic for command and query? Should we? 7 | internal sealed class CommandDispatcher : ICommandDispatcher 8 | { 9 | private readonly IServiceProvider _serviceProvider; 10 | 11 | public CommandDispatcher(IServiceProvider serviceProvider) 12 | => _serviceProvider = serviceProvider; 13 | 14 | public async Task Send(TCommand command) where TCommand : Command 15 | { 16 | // TODO: maybe some configuration to reuse outer scope instead of creating new one 17 | using var scope = _serviceProvider.CreateScope(); 18 | 19 | var commandValidators = scope.ServiceProvider.GetServices>(); 20 | 21 | await Task.WhenAll(commandValidators.Select(p => p.Validate(command))); 22 | 23 | var handlers = scope.ServiceProvider.GetServices>().ToList(); 24 | 25 | // TODO: throw this on startup 26 | if (handlers.Count == 0) 27 | throw new MissingCommandHandlerException(command); 28 | 29 | if (handlers.Count > 1) 30 | throw new MultipleCommandHandlerException(command); 31 | 32 | var handler = handlers.Single(); 33 | 34 | await handler.Handle(command); 35 | } 36 | } 37 | 38 | internal class MissingCommandHandlerException : Exception 39 | { 40 | public MissingCommandHandlerException(Command command) : base($"Missing handler for command {command.GetType().FullName}") 41 | { 42 | } 43 | } 44 | 45 | internal class MultipleCommandHandlerException : Exception 46 | { 47 | public MultipleCommandHandlerException(Command command) : base($"Multiple handler registration for command {command.GetType().FullName}") 48 | { 49 | } 50 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/Commands/StartupExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Allegro.Extensions.Cqrs.Abstractions; 3 | using Allegro.Extensions.Cqrs.Abstractions.Commands; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace Allegro.Extensions.Cqrs.Commands; 7 | 8 | /// 9 | /// Startup Extensions - expose registration of commands in application. 10 | /// 11 | public static class StartupExtensions 12 | { 13 | /// 14 | /// Register all commands/handlers implemented in application and common tools (dispatchers, actions, validators) 15 | /// 16 | /// 17 | /// Assembly collection in which Command related types should be looked for. 18 | /// Determines whether only public classes should be registered 19 | public static IServiceCollection AddCommands( 20 | this IServiceCollection services, 21 | IEnumerable assemblies, 22 | bool publicOnly = false) 23 | { 24 | services 25 | .AddSingleton(); 26 | services 27 | .Scan(s => s.FromAssemblies(assemblies) // TODO: should we remove Scrutor in future? 28 | .AddClasses( 29 | c => c.AssignableTo(typeof(ICommandHandler<>)) 30 | .WithoutAttribute(), 31 | publicOnly) 32 | .AsImplementedInterfaces() 33 | .WithScopedLifetime()); 34 | 35 | services 36 | .Scan(s => s.FromAssemblies(assemblies) 37 | .AddClasses(c => c.AssignableTo(typeof(ICommandValidator<>)), publicOnly) 38 | .AsImplementedInterfaces() 39 | .WithScopedLifetime()); 40 | return services; 41 | } 42 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/InternalsVisibleTo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) PlaceholderCompany. All rights reserved. 2 | 3 | using System.Runtime.CompilerServices; 4 | 5 | [assembly: InternalsVisibleTo("Allegro.Extensions.Cqrs.Tests.Unit")] -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/Allegro.Extensions.Cqrs/Queries/StartupExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using Allegro.Extensions.Cqrs.Abstractions; 3 | using Allegro.Extensions.Cqrs.Abstractions.Queries; 4 | using Microsoft.Extensions.DependencyInjection; 5 | 6 | namespace Allegro.Extensions.Cqrs.Queries; 7 | 8 | /// 9 | /// Startup Extensions - expose registration of queries in application. 10 | /// 11 | public static class StartupExtensions 12 | { 13 | /// 14 | /// Register all queries/handlers implemented in application and common tools (dispatchers) 15 | /// 16 | /// 17 | /// Assembly collection in which Command related types should be looked for. 18 | /// Determines whether only public classes should be registered 19 | public static IServiceCollection AddQueries(this IServiceCollection services, IEnumerable assemblies, bool publicOnly = false) 20 | { 21 | services.AddSingleton(); 22 | services.Scan(s => s.FromAssemblies(assemblies) // TODO: remove scrutor and register by own util 23 | .AddClasses( 24 | c => c.AssignableTo(typeof(IQueryHandler<,>)) 25 | .WithoutAttribute(), 26 | publicOnly) 27 | .AsImplementedInterfaces() 28 | .WithScopedLifetime()); 29 | 30 | services 31 | .Scan(s => s.FromAssemblies(assemblies) 32 | .AddClasses(c => c.AssignableTo(typeof(IQueryValidator<>)), publicOnly) 33 | .AsImplementedInterfaces() 34 | .WithScopedLifetime()); 35 | return services; 36 | } 37 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [2.2.0] - 2025-01-14 9 | ### Allegro.Extensions.Cqrs 10 | - Added publicOnly parameter to AddQueries and AddCommands methods 11 | - Unified commands/queries registration behavior across different Scrutor versions 12 | ### Allegro.Extensions.Cqrs.FluentValidations 13 | - Added publicOnly parameter to AddCqrsFluentValidations method 14 | - Unified validators registration behavior across different Scrutor versions 15 | 16 | ## [2.1.0] - 2023-01-26 17 | 18 | ### Allegro.Extensions.Cqrs 19 | 20 | Command and Query dispatchers will explicitly fail when multiple handler registrations are registered. 21 | 22 | ## [2.0.0] - 2023-01-26 23 | 24 | ### Allegro.Extensions.Cqrs.Abstractions 25 | 26 | Replace ICommand and IQuery with Command and Query (based on the approach 27 | from [CQRS.Mediatr.Lite](https://github.com/microsoft/CQRS.Mediatr.Lite/blob/a6f63cf62a5e2b1b48a55b7917ba036c8ae6f3b9/src/sdk/Command/Command.cs)) 28 | 29 | ## [1.1.0] - 2022-11-17 30 | 31 | ### Allegro.Extensions.Cqrs 32 | 33 | * Adjust implementation to Allegro.Extensions.Cqrs.Abstractions 1.1.0 34 | * Some code cleanup 35 | 36 | ### Allegro.Extensions.Cqrs.Abstractions 37 | 38 | * Remove ICommandExecutionActions - as we already have possibility to decorate 39 | * Add IQueryValidator 40 | * Change query result not nullable 41 | 42 | ### Allegro.Extensions.Cqrs.FluentValidations 43 | 44 | * Add `AddCqrsFluentValidations` extension to enable fluent validations 45 | 46 | ## [1.0.0] - 2022-11-09 47 | ### Allegro.Extensions.Cqrs 48 | 49 | * Initiated Allegro.Extensions.Cqrs with default implementation of dispatchers and command actions support 50 | 51 | ### Allegro.Extensions.Cqrs.Abstractions 52 | 53 | * Initiated Allegro.Extensions.Cqrs.Abstractions with basic abstraction for cqrs. 54 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Cqrs/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 2.2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres.Tests.Integration/Allegro.Extensions.Dapper.Postgres.Tests.Integration.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | PreserveNewest 25 | 26 | 27 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres.Tests.Integration/Helpers/CustomWebApplicationFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.AspNetCore.Hosting; 2 | using Microsoft.AspNetCore.Mvc.Testing; 3 | using Microsoft.AspNetCore.TestHost; 4 | using Microsoft.Extensions.Configuration; 5 | using Microsoft.Extensions.Hosting; 6 | 7 | namespace Allegro.Extensions.Dapper.Postgres.Tests.Integration.Helpers; 8 | 9 | public class CustomWebApplicationFactory : WebApplicationFactory 10 | { 11 | protected override IHostBuilder CreateHostBuilder() 12 | { 13 | return base.CreateHostBuilder()! 14 | .ConfigureAppConfiguration((_, builder) => 15 | { 16 | builder 17 | .SetBasePath(Directory.GetCurrentDirectory()) 18 | .AddJsonFile("appsettings.Test.json"); 19 | }) 20 | .ConfigureWebHostDefaults( 21 | webBuilder => 22 | { 23 | webBuilder 24 | .UseTestServer() 25 | .UseStartup(); 26 | }) 27 | .UseEnvironment(Environments.Development); 28 | } 29 | 30 | protected override IHost CreateHost(IHostBuilder builder) 31 | { 32 | builder.UseContentRoot(Directory.GetCurrentDirectory()); 33 | return base.CreateHost(builder); 34 | } 35 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres.Tests.Integration/Helpers/FakeStartup.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Dapper.Extensions; 2 | using Allegro.Extensions.Dapper.Postgres.Extensions; 3 | using Microsoft.AspNetCore.Builder; 4 | using Microsoft.AspNetCore.Hosting; 5 | using Microsoft.Extensions.Configuration; 6 | using Microsoft.Extensions.DependencyInjection; 7 | 8 | namespace Allegro.Extensions.Dapper.Postgres.Tests.Integration.Helpers; 9 | 10 | public class FakeStartup 11 | { 12 | private readonly IConfiguration _configuration; 13 | 14 | public FakeStartup(IConfiguration configuration) 15 | { 16 | _configuration = configuration; 17 | } 18 | 19 | public void ConfigureServices(IServiceCollection services) 20 | { 21 | var connectionString = _configuration["PostgresSDK:ConnectionString"]; 22 | 23 | services 24 | .AddDapperClient() 25 | .AddDapperPostgres(connectionString); 26 | } 27 | 28 | public static void Configure(IApplicationBuilder app, IWebHostEnvironment env) 29 | { 30 | } 31 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres.Tests.Integration/Helpers/SqlQueries.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Dapper.Postgres.Tests.Integration.Helpers; 2 | 3 | public static class SqlQueries 4 | { 5 | public const string TableName = "TestTable"; 6 | 7 | public static string CreateTableIfNotExists => 8 | @" 9 | CREATE TABLE IF NOT EXISTS TestTable 10 | ( 11 | Id SERIAL primary key, 12 | Username VARCHAR(40) UNIQUE 13 | ); 14 | "; 15 | 16 | public static string InsertRowWithReturning => 17 | $@" 18 | INSERT INTO {TableName} 19 | ( 20 | Username 21 | ) 22 | VALUES 23 | ( 24 | @Username 25 | ) 26 | RETURNING 27 | id AS Id, 28 | username AS Username; 29 | "; 30 | 31 | public static string DropTableIfExists => 32 | $@"DROP TABLE IF EXISTS {TableName}"; 33 | 34 | public static string SelectAllFromTable => 35 | $@"SELECT 36 | Id, 37 | Username 38 | FROM {TableName}"; 39 | 40 | public static string SelectFirstFromTable => 41 | SelectAllFromTable + " LIMIT 1"; 42 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres.Tests.Integration/Models/TestModel.cs: -------------------------------------------------------------------------------- 1 | #nullable enable 2 | namespace Vabank.Storage.Postgres.Sdk.Tests.Integration.Models; 3 | 4 | public class TestModel 5 | { 6 | public TestModel(int id, string? username) 7 | { 8 | Id = id; 9 | Username = username; 10 | } 11 | 12 | public int Id { get; set; } 13 | public string? Username { get; set; } 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres.Tests.Integration/appsettings.Test.json: -------------------------------------------------------------------------------- 1 | { 2 | "PostgresSDK": { 3 | "ConnectionString" : "TODO" 4 | } 5 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/Abstractions/DbType.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | 3 | #pragma warning disable CS1591 4 | namespace Allegro.Extensions.Dapper.Postgres.Abstractions; 5 | 6 | /// 7 | /// Dto database type. 8 | /// 9 | [SuppressMessage("Naming", "CA1720:Identifier contains type name", Justification = "Purpose of that enum")] 10 | public enum DbType 11 | { 12 | Int, 13 | BigInt, 14 | Text, 15 | Date, 16 | Decimal, 17 | Guid, 18 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/Abstractions/IDapperPostgresBinaryCopyClient.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Dapper.Postgres.Exceptions; 2 | 3 | namespace Allegro.Extensions.Dapper.Postgres.Abstractions; 4 | 5 | /// 6 | /// Binary copy operation using built-in Postgres mechanism. 7 | /// 8 | public interface IDapperPostgresBinaryCopyClient 9 | { 10 | /// 11 | /// Binary COPY FROM operation which is data import mechanism to a Postgres table. 12 | /// 13 | /// Table name to which data will be copied 14 | /// Dictionary of name and type of columns 15 | /// Selector of properties to copy from source data type 16 | /// Source data 17 | /// Source data type 18 | /// Number of affected rows 19 | /// Thrown if there is a DbConnection type mismatch 20 | /// from IDatabaseConnectionFactory 21 | public Task BinaryCopyAsync( 22 | string tableName, 23 | IDictionary columns, 24 | Func selector, 25 | IAsyncEnumerable source); 26 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/Allegro.Extensions.Dapper.Postgres.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Dapper.Postgres 5 | Postgres Dapper clients 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/Exceptions/InvalidDbConnectionTypeException.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | namespace Allegro.Extensions.Dapper.Postgres.Exceptions; 4 | 5 | /// 6 | /// Exception which indicates invalid underlying DbConnection type. 7 | /// 8 | public class InvalidDbConnectionTypeException : Exception 9 | { 10 | public InvalidDbConnectionTypeException(string expectedType) 11 | : base($"Invalid DbConnectionType, expected type: {expectedType}") 12 | { 13 | } 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Dapper.Abstractions; 2 | using Allegro.Extensions.Dapper.Configurations; 3 | using Allegro.Extensions.Dapper.Postgres.Abstractions; 4 | using Allegro.Extensions.Dapper.Postgres.Factories; 5 | using Microsoft.Extensions.DependencyInjection; 6 | 7 | namespace Allegro.Extensions.Dapper.Postgres.Extensions; 8 | 9 | /// 10 | /// Service Collection Extensions to register dapper postgress services 11 | /// 12 | public static class ServiceCollectionExtensions 13 | { 14 | /// 15 | /// Register Dapper Postgres utilities with passed connection string as a parameter. 16 | /// 17 | /// Target of an extension method 18 | /// Postgres database connection string 19 | public static IServiceCollection AddDapperPostgres( 20 | this IServiceCollection services, 21 | string connectionString) 22 | { 23 | if (string.IsNullOrWhiteSpace(connectionString)) 24 | { 25 | throw new ArgumentNullException(nameof(connectionString), "Empty connection string"); 26 | } 27 | 28 | return services 29 | .AddSingleton(new DatabaseConfiguration 30 | { 31 | ConnectionString = connectionString 32 | }) 33 | .AddSingleton() 34 | .AddSingleton() 35 | .AddSingleton(); 36 | } 37 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.Postgres/Factories/PostgresDatabaseConnectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | using Allegro.Extensions.Dapper.Abstractions; 3 | using Allegro.Extensions.Dapper.Configurations; 4 | using Npgsql; 5 | 6 | namespace Allegro.Extensions.Dapper.Postgres.Factories; 7 | 8 | /// 9 | /// Database connection factory for Postgres database. 10 | /// 11 | internal class PostgresDatabaseConnectionFactory : IDatabaseConnectionFactory 12 | { 13 | private readonly DatabaseConfiguration _databaseConfiguration; 14 | 15 | public PostgresDatabaseConnectionFactory( 16 | DatabaseConfiguration databaseConfiguration) 17 | { 18 | _databaseConfiguration = databaseConfiguration; 19 | } 20 | 21 | /// 22 | /// Initialize new NpgsqlConnection with registered as configuration connection string. 23 | /// 24 | public DbConnection Create() => 25 | new NpgsqlConnection(_databaseConfiguration.ConnectionString); 26 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.sln: -------------------------------------------------------------------------------- 1 | Microsoft Visual Studio Solution File, Format Version 12.00 2 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1A5C6678-1714-4D2A-A0B5-DF08B4796E92}" 3 | EndProject 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Dapper", "Allegro.Extensions.Dapper\Allegro.Extensions.Dapper.csproj", "{2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Dapper.Postgres", "Allegro.Extensions.Dapper.Postgres\Allegro.Extensions.Dapper.Postgres.csproj", "{C4EBC25F-22C8-4F15-AA21-53567F3269BF}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Dapper.Postgres.Tests.Integration", "Allegro.Extensions.Dapper.Postgres.Tests.Integration\Allegro.Extensions.Dapper.Postgres.Tests.Integration.csproj", "{B1B1FADB-D3DF-4FD6-A2A2-EE3821C6ED79}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Release|Any CPU = Release|Any CPU 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 17 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Debug|Any CPU.Build.0 = Debug|Any CPU 18 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Release|Any CPU.ActiveCfg = Release|Any CPU 19 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Release|Any CPU.Build.0 = Release|Any CPU 20 | {C4EBC25F-22C8-4F15-AA21-53567F3269BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {C4EBC25F-22C8-4F15-AA21-53567F3269BF}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {C4EBC25F-22C8-4F15-AA21-53567F3269BF}.Release|Any CPU.ActiveCfg = Release|Any CPU 23 | {C4EBC25F-22C8-4F15-AA21-53567F3269BF}.Release|Any CPU.Build.0 = Release|Any CPU 24 | {B1B1FADB-D3DF-4FD6-A2A2-EE3821C6ED79}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 25 | {B1B1FADB-D3DF-4FD6-A2A2-EE3821C6ED79}.Debug|Any CPU.Build.0 = Debug|Any CPU 26 | {B1B1FADB-D3DF-4FD6-A2A2-EE3821C6ED79}.Release|Any CPU.ActiveCfg = Release|Any CPU 27 | {B1B1FADB-D3DF-4FD6-A2A2-EE3821C6ED79}.Release|Any CPU.Build.0 = Release|Any CPU 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper/Abstractions/IDatabaseConnectionFactory.cs: -------------------------------------------------------------------------------- 1 | using System.Data.Common; 2 | 3 | namespace Allegro.Extensions.Dapper.Abstractions; 4 | 5 | /// 6 | /// Factory to create specific DbConnection (e. g. Postgres, MySQL DbConnection). 7 | /// 8 | public interface IDatabaseConnectionFactory 9 | { 10 | /// 11 | /// Initialize database connection with registered as configuration connection string. 12 | /// 13 | DbConnection Create(); 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Dapper 5 | Dapper utilities 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper/Configurations/DatabaseConfiguration.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Dapper.Configurations; 2 | 3 | /// 4 | /// Database configuration options. 5 | /// 6 | public class DatabaseConfiguration 7 | { 8 | /// 9 | /// Connection string to a database. 10 | /// 11 | public string ConnectionString { get; init; } = null!; 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/Allegro.Extensions.Dapper/Extensions/ServiceCollectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Dapper.Abstractions; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Allegro.Extensions.Dapper.Extensions; 5 | 6 | /// 7 | /// Service Collection Extensions 8 | /// 9 | public static class ServiceCollectionExtensions 10 | { 11 | /// 12 | /// Register Dapper Client. 13 | /// 14 | /// Target of an extension method 15 | public static IServiceCollection AddDapperClient( 16 | this IServiceCollection services) 17 | { 18 | return services 19 | .AddSingleton(); 20 | } 21 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.2.0] - 2022-10-26 9 | 10 | ### Added 11 | 12 | * Add support for uuid type in binary copy client. 13 | 14 | ## [1.1.0] - 2022-05-06 15 | 16 | ### Removed 17 | 18 | * Removed targeting net5.0 19 | 20 | ## [1.0.0] - 2022-05-06 21 | 22 | ### Added 23 | 24 | * Initiated Allegro.Extensions.Dapper project 25 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Dapper/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Abstractions/Allegro.Extensions.DependencyCall.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Allegro.Extensions.DependencyCall.Abstractions 4 | Contains DependencyCall package abstractions 5 | ${NoWarn},CS8618,SA1636 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Abstractions/IDependencyCallDispatcher.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.DependencyCall.Abstractions; 2 | 3 | /// 4 | /// Allows to dispatch any dependency call with default pipeline. 5 | /// 6 | public interface IDependencyCallDispatcher 7 | { 8 | /// 9 | /// Dispatches IRequest with default pipeline and support for metrics, fallbacks, retry policies. 10 | /// 11 | /// Request data 12 | /// Optional cancellation token. If null default cancellation policy will be used 13 | /// Type of response data 14 | Task Dispatch(IRequest request, CancellationToken cancellationToken = default); 15 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Abstractions/IDependencyCallMetrics.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.DependencyCall.Abstractions; 2 | 3 | /// 4 | /// Expose metrics collected by dispatcher. Allow to support own implementation of metrics 5 | /// 6 | public interface IDependencyCallMetrics 7 | { 8 | /// 9 | /// Triggered when new dependency call was executed successfully 10 | /// 11 | public void Succeeded(IRequest request, TimeSpan duration); 12 | 13 | /// 14 | /// Triggered when new dependency call failed with error 15 | /// 16 | public void Failed(IRequest request, Exception exception, TimeSpan duration); 17 | 18 | /// 19 | /// Triggered when new dependency call used fallback 20 | /// 21 | public void Fallback(IRequest request, TimeSpan duration); 22 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Abstractions/IRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.DependencyCall.Abstractions; 2 | 3 | /// 4 | /// Marker interface. Used to recognize Dependency Call request data 5 | /// 6 | /// Type of dependency call response data 7 | public interface IRequest : IRequest 8 | { 9 | } 10 | 11 | /// 12 | /// Marker interface. Used to recognize Dependency Call request data 13 | /// 14 | public interface IRequest { } -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Metrics.Prometheus/Allegro.Extensions.DependencyCall.Metrics.Prometheus.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Allegro.Extensions.DependencyCall.Metrics.Prometheus 4 | Contains prometheus based metrics for dependency call 5 | ${NoWarn},CS8618,SA1636 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Metrics.Prometheus/DependencyCallBuilderExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | 3 | namespace Allegro.Extensions.DependencyCall.Metrics.Prometheus; 4 | 5 | /// 6 | /// Register Prometheus metrics extensions 7 | /// 8 | public static class DependencyCallBuilderExtensions 9 | { 10 | /// 11 | /// Registers PrometheusDependencyCallMetrics into DependencyCall pipeline 12 | /// 13 | public static DependencyCallBuilder RegisterPrometheusDependencyCallMetrics( 14 | this DependencyCallBuilder builder, 15 | string applicationName) 16 | { 17 | builder.Services.AddSingleton(sp => new ApplicationNameProvider(applicationName)); 18 | return builder.WithDependencyCallMetrics(); 19 | } 20 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Metrics.Prometheus/PrometheusDependencyCallMetrics.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.DependencyCall.Abstractions; 2 | using Prometheus; 3 | 4 | namespace Allegro.Extensions.DependencyCall.Metrics.Prometheus; 5 | 6 | internal class PrometheusDependencyCallMetrics : IDependencyCallMetrics 7 | { 8 | private readonly Histogram _dependencyCallDuration; 9 | 10 | public PrometheusDependencyCallMetrics(IMetricFactory metrics, ApplicationNameProvider applicationNameProvider) 11 | { 12 | _dependencyCallDuration = DependencyCallDurationFactory(metrics, applicationNameProvider.ApplicationName); 13 | } 14 | 15 | private static Histogram DependencyCallDurationFactory(IMetricFactory metrics, string applicationName) => 16 | metrics.CreateHistogram( 17 | $"{applicationName}_dependency_call_duration_metrics", 18 | "Duration of dependency call", 19 | new HistogramConfiguration() 20 | { 21 | // CA1861 : Prefer 'static readonly' fields over constant array arguments if the called method is called repeatedly and is not mutating the passed array 22 | #pragma warning disable CA1861 23 | LabelNames = new[] { "dependencyCallName", "type" }, 24 | #pragma warning restore CA1861 25 | Buckets = new[] { 0.008, 0.016, 0.032, 0.064, 0.128, 0.512, 1, 4, 16 }, 26 | }); 27 | 28 | public void Succeeded(IRequest request, TimeSpan duration) 29 | { 30 | _dependencyCallDuration.WithLabels(request.GetType().FullName!, "succeeded") 31 | .Observe(duration.TotalSeconds); 32 | } 33 | 34 | public void Failed(IRequest request, Exception exception, TimeSpan duration) 35 | { 36 | _dependencyCallDuration.WithLabels(request.GetType().FullName!, "failed").Observe(duration.TotalSeconds); 37 | } 38 | 39 | public void Fallback(IRequest request, TimeSpan duration) 40 | { 41 | _dependencyCallDuration.WithLabels(request.GetType().FullName!, "fallback") 42 | .Observe(duration.TotalSeconds); 43 | } 44 | } 45 | 46 | internal record ApplicationNameProvider(string ApplicationName); -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.Tests.Unit/Allegro.Extensions.DependencyCall.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | ${NoWarn},CS8618,CS1591 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.DependencyCall 5 | Contains DependencyCall tool 6 | ${NoWarn},CS8618,SA1636 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/Allegro.Extensions.DependencyCall/NoOperationDependencyCallMetrics.cs: -------------------------------------------------------------------------------- 1 | using System.Diagnostics.CodeAnalysis; 2 | using Allegro.Extensions.DependencyCall.Abstractions; 3 | 4 | namespace Allegro.Extensions.DependencyCall; 5 | 6 | [SuppressMessage("Performance", "CA1822:Mark members as static", Justification = "Interface implementation")] 7 | internal class NoOperationDependencyCallMetrics : IDependencyCallMetrics 8 | { 9 | public void Succeeded(IRequest request, TimeSpan duration) 10 | { 11 | } 12 | 13 | public void Failed(IRequest request, Exception exception, TimeSpan duration) 14 | { 15 | } 16 | 17 | public void Fallback(IRequest request, TimeSpan duration) 18 | { 19 | } 20 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.2.0] - 2025-01-14 9 | 10 | ### Added 11 | * Added publicOnly parameter to AddDependencyCall method 12 | * Unified DependencyCall registration behavior across different Scrutor versions 13 | 14 | ## [1.1.0] - 2024-01-31 15 | 16 | ### Added 17 | 18 | * Filtered out Microsoft packages from assembly loading due to a bug in Microsoft.Data.SqlClient and .net 8 19 | 20 | ## [1.0.0] - 2023-06-27 21 | 22 | ### Added 23 | 24 | * Initiated Allegro.Extensions.DependencyCall project with DependencyCall abstractions -------------------------------------------------------------------------------- /src/Allegro.Extensions.DependencyCall/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials.Tests.Unit/Allegro.Extensions.Financials.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials.Tests.Unit/Extensions/MoneyExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Financials.Extensions; 2 | using Allegro.Extensions.Financials.ValueObjects; 3 | using FluentAssertions; 4 | using Xunit; 5 | 6 | namespace Allegro.Extensions.Financials.Tests.Unit.Extensions; 7 | 8 | public class MoneyExtensionsTests 9 | { 10 | [Fact] 11 | public void Sum_Money_Items() 12 | { 13 | var moneys = new List 14 | { 15 | new(10), 16 | new(5), 17 | new(0), 18 | }; 19 | 20 | var sum = moneys.Sum(); 21 | sum.Should().NotBeNull(); 22 | sum.Amount.Should().Be(15); 23 | } 24 | 25 | [Fact] 26 | public void Sum_Money_Items_with_null() 27 | { 28 | var moneys = new List 29 | { 30 | new(5), 31 | new(2), 32 | }; 33 | 34 | var sum = moneys.Sum(); 35 | sum.Should().NotBeNull(); 36 | sum.Amount.Should().Be(7); 37 | } 38 | 39 | [Fact] 40 | public void Sum_Struct_with_money() 41 | { 42 | var moneys = new List 43 | { 44 | new(5.10m), 45 | new(4.20m), 46 | new(-2), 47 | }; 48 | 49 | var sum = moneys.Sum(x => x.Money); 50 | sum.Should().NotBeNull(); 51 | sum.Amount.Should().Be(7.30m); 52 | } 53 | 54 | [Fact] 55 | public void Sum_Class_with_money() 56 | { 57 | var moneys = new List 58 | { 59 | new(5.10m), 60 | new(4.20m), 61 | new(-2), 62 | }; 63 | 64 | var sum = moneys.Sum(x => x.Money); 65 | sum.Should().NotBeNull(); 66 | sum.Amount.Should().Be(7.30m); 67 | } 68 | 69 | private readonly struct StructWithMoney 70 | { 71 | public Money Money { get; } 72 | 73 | public StructWithMoney(decimal money) 74 | { 75 | Money = new Money(money); 76 | } 77 | } 78 | 79 | private class ClassWithMoney 80 | { 81 | public Money Money { get; } 82 | 83 | public ClassWithMoney(decimal money) 84 | { 85 | Money = new Money(money); 86 | } 87 | } 88 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Financials", "Allegro.Extensions.Financials\Allegro.Extensions.Financials.csproj", "{E1C61F6A-FEAA-4252-87DF-C0EBD17AEDF0}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Financials.Tests.Unit", "Allegro.Extensions.Financials.Tests.Unit\Allegro.Extensions.Financials.Tests.Unit.csproj", "{272A2598-7520-402B-A07D-22C4FE518B82}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {E1C61F6A-FEAA-4252-87DF-C0EBD17AEDF0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {E1C61F6A-FEAA-4252-87DF-C0EBD17AEDF0}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {E1C61F6A-FEAA-4252-87DF-C0EBD17AEDF0}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {E1C61F6A-FEAA-4252-87DF-C0EBD17AEDF0}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {272A2598-7520-402B-A07D-22C4FE518B82}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {272A2598-7520-402B-A07D-22C4FE518B82}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {272A2598-7520-402B-A07D-22C4FE518B82}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {272A2598-7520-402B-A07D-22C4FE518B82}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials/Allegro.Extensions.Financials.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Financials 5 | Contains money value object and currency. 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials/Extensions/MoneyExtensions.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Financials.ValueObjects; 2 | 3 | namespace Allegro.Extensions.Financials.Extensions; 4 | 5 | /// 6 | /// Money related extensions 7 | /// 8 | public static class MoneyExtensions 9 | { 10 | /// 11 | /// Sum money in collection of objects that contains money 12 | /// 13 | public static Money Sum(this IEnumerable source, Func selector) 14 | { 15 | ArgumentNullException.ThrowIfNull(source); 16 | ArgumentNullException.ThrowIfNull(selector); 17 | 18 | var sum = Money.Zero; 19 | return source.Aggregate(sum, (current, item) => current + selector(item)); 20 | } 21 | 22 | /// 23 | /// Sum money in collection of money objects 24 | /// 25 | public static Money Sum(this IEnumerable source) 26 | { 27 | ArgumentNullException.ThrowIfNull(source); 28 | 29 | var sum = Money.Zero; 30 | return source.Aggregate(sum, (current, item) => current + item); 31 | } 32 | 33 | /// 34 | /// Allows to round money value with Math.Round api 35 | /// 36 | public static Money? Round(this Money? money, int decimals, MidpointRounding midpointRounding) 37 | { 38 | if (money == null) 39 | { 40 | return null; 41 | } 42 | 43 | return new Money( 44 | Amount: Math.Round(money.Amount, decimals, midpointRounding), 45 | Currency: money.Currency); 46 | } 47 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials/ValueObjects/Currency.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.Serialization; 2 | #pragma warning disable CS1591 3 | 4 | namespace Allegro.Extensions.Financials.ValueObjects; 5 | 6 | /// 7 | /// Country currency codes (ISO 4217). 8 | /// https://www.iban.com/currency-codes 9 | /// 10 | public enum Currency 11 | { 12 | [EnumMember(Value = "PLN")] 13 | PLN = 985, 14 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/Allegro.Extensions.Financials/ValueObjects/Money.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Financials.ValueObjects; 2 | 3 | /// 4 | /// Value object to store money related data in standardize way 5 | /// 6 | public partial record Money( 7 | decimal Amount, 8 | Currency Currency = Currency.PLN) 9 | { 10 | /// 11 | /// Creates money with value 0 and default currency (PLN) 12 | /// 13 | public static Money Zero => new(0); 14 | 15 | /// 16 | /// Defualt string representation of money 17 | /// 18 | public override string ToString() => $"{Amount} {Currency}"; 19 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.0] - 2022-05-25 9 | 10 | ### Added 11 | 12 | * Initiated Allegro.Extensions.Financials project with money value object. 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/README.md: -------------------------------------------------------------------------------- 1 | # Allegro.Extensions.Financials 2 | 3 | Contains money value object and currency. -------------------------------------------------------------------------------- /src/Allegro.Extensions.Financials/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Globalization/Allegro.Extensions.Globalization.Tests/Allegro.Extensions.Globalization.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | AnyCPU;x64 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Globalization/Allegro.Extensions.Globalization/Allegro.Extensions.Globalization.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Allegro.Extensions.Globalization 5 | Contains classes that define culture-related information, including language, country/region, calendars in use, format patterns for dates, currency, and numbers, and sort order for strings. These classes are useful for writing globalized (internationalized) applications. 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Globalization/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.0] - 2022-05-18 9 | 10 | ### Added 11 | 12 | * Initiated Allegro.Extensions.Globalization project and PolishPluralizer added 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Globalization/README.md: -------------------------------------------------------------------------------- 1 | # Allegro.Extensions.Globalization 2 | 3 | Contains classes that define culture-related information, including language, country/region, calendars in use, format patterns for dates, currency, and numbers, and sort order for strings. These classes are useful for writing globalized (internationalized) applications. -------------------------------------------------------------------------------- /src/Allegro.Extensions.Globalization/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Abstractions/Allegro.Extensions.Identifiers.Abstractions.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Identifiers.Abstractions 5 | Contains strongly typed identifiers abstractions. 6 | CS1574 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Abstractions/IStronglyTypedEntity.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Identifiers.Abstractions; 2 | 3 | /// 4 | /// Marker interface for strongly typed entities 5 | /// 6 | public interface IStronglyTypedEntity 7 | where T : IStronglyTypedId 8 | { 9 | /// 10 | /// Strongly typed entity id 11 | /// 12 | public T Id { get; } 13 | } 14 | 15 | /// 16 | /// Marker interface for strongly typed identifiers 17 | /// 18 | public interface IStronglyTypedEntity : IStronglyTypedEntity 19 | where T : IStronglyTypedId 20 | { 21 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Abstractions/IStronglyTypedId.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Identifiers.Abstractions; 2 | 3 | /// 4 | /// Marker interface. Indicates if type should be treated as a strongly typed identifier. 5 | /// Meziantou.Framework.StronglyTypedId that is recommended as a code generator implements this interface by default and provides common JSON serializers. 6 | /// 7 | public interface IStronglyTypedId 8 | { 9 | /// 10 | /// Value of identifier 11 | /// 12 | public T Value { get; } 13 | 14 | /// 15 | /// String value of identifier 16 | /// 17 | public string ValueAsString { get; } 18 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.AspNetCore/Allegro.Extensions.Identifiers.AspNetCore.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Identifiers.AspNetCore 5 | Contains strongly typed identifiers extensions for swagger. 6 | CS1574 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Allegro.Extensions.Identifiers.Demo.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Controllers/TestController.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Identifiers.Demo.Identifiers; 2 | using Microsoft.AspNetCore.Mvc; 3 | 4 | namespace Allegro.Extensions.Identifiers.Demo.Controllers 5 | { 6 | [ApiController] 7 | [Route("strongly-typed")] 8 | public class StronglyTypedExamples : ControllerBase 9 | { 10 | [HttpGet] 11 | public IActionResult Get() 12 | { 13 | return Ok(new { UserId = UserId.Generate(), PaymentId = PaymentId.Parse("123"), OrderId = OrderId.FromGuid(Guid.NewGuid()) }); 14 | } 15 | 16 | [HttpPost] 17 | public IActionResult Post([FromQuery] UserId userId, [FromQuery] PaymentId paymentId, [FromQuery] OrderId orderId) 18 | { 19 | return Ok(new { UserId = userId, PaymentId = paymentId, OrderId = orderId }); 20 | } 21 | 22 | [HttpGet("{userId}")] 23 | public IActionResult Post([FromRoute] UserId userId) 24 | { 25 | return Ok(new { UserId = userId }); 26 | } 27 | 28 | [HttpPost("body")] 29 | public IActionResult Post([FromBody] Dto dto) 30 | { 31 | return Ok(dto); 32 | } 33 | 34 | public record Dto(UserId UserId, PaymentId PaymentId, OrderId OrderId); 35 | } 36 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Identifiers/OrderId.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) PlaceholderCompany. All rights reserved. 2 | #pragma warning disable 1591 3 | 4 | using Allegro.Extensions.Identifiers.Abstractions; 5 | using Meziantou.Framework.Annotations; 6 | 7 | namespace Allegro.Extensions.Identifiers.Demo.Identifiers; 8 | 9 | [StronglyTypedId(typeof(Guid))] 10 | public partial class OrderId : IStronglyTypedId 11 | { 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Identifiers/PaymentId.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) PlaceholderCompany. All rights reserved. 2 | 3 | using Allegro.Extensions.Identifiers.Abstractions; 4 | using Meziantou.Framework.Annotations; 5 | 6 | namespace Allegro.Extensions.Identifiers.Demo.Identifiers; 7 | 8 | [StronglyTypedId(typeof(int))] 9 | public partial class PaymentId : IStronglyTypedId 10 | { 11 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Identifiers/UserId.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) PlaceholderCompany. All rights reserved. 2 | 3 | using Allegro.Extensions.Identifiers.Abstractions; 4 | using Meziantou.Framework.Annotations; 5 | 6 | namespace Allegro.Extensions.Identifiers.Demo.Identifiers; 7 | 8 | [StronglyTypedId(typeof(string))] 9 | public partial class UserId : IStronglyTypedId 10 | { 11 | public static UserId Generate() => FromString(Guid.NewGuid().ToString()); 12 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Program.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.Identifiers.Demo 2 | { 3 | public static class Program 4 | { 5 | public static void Main(string[] args) 6 | { 7 | Host.CreateDefaultBuilder(args) 8 | .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()) 9 | .Build() 10 | .Run(); 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "Allegro.Extensions.AspNetCore.Demo": { 4 | "commandName": "Project", 5 | "launchBrowser": true, 6 | "launchUrl": "swagger", 7 | "environmentVariables": { 8 | "ASPNETCORE_ENVIRONMENT": "Development" 9 | }, 10 | "applicationUrl": "https://localhost:5001;http://localhost:5000" 11 | } 12 | } 13 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.Demo/Startup.cs: -------------------------------------------------------------------------------- 1 | using Allegro.Extensions.Identifiers.AspNetCore.Swagger; 2 | 3 | namespace Allegro.Extensions.Identifiers.Demo 4 | { 5 | public class Startup 6 | { 7 | private readonly IWebHostEnvironment _env; 8 | 9 | public Startup(IWebHostEnvironment env) 10 | { 11 | _env = env; 12 | } 13 | 14 | public void Configure(IApplicationBuilder app) 15 | { 16 | app 17 | .UseRouting() 18 | .UseSwagger() 19 | .UseSwaggerUI() 20 | .UseEndpoints(endpoints => { endpoints.MapControllers(); }); 21 | } 22 | 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services 26 | .AddControllers(); 27 | 28 | services 29 | .AddStronglyTypedIds() 30 | .AddSwaggerGen(); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/Allegro.Extensions.Identifiers.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Identifiers.Abstractions", "Allegro.Extensions.Identifiers.Abstractions\Allegro.Extensions.Identifiers.Abstractions.csproj", "{1196D276-39C2-4EA1-966D-6775D17B0DC5}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Identifiers.AspNetCore", "Allegro.Extensions.Identifiers.AspNetCore\Allegro.Extensions.Identifiers.AspNetCore.csproj", "{964DDB21-8B3A-43B7-A4F3-69A35875EF84}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Identifiers.Demo", "Allegro.Extensions.Identifiers.Demo\Allegro.Extensions.Identifiers.Demo.csproj", "{22E35C09-957D-4A5A-8D0C-CA316093DED1}" 8 | EndProject 9 | Global 10 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 11 | Debug|Any CPU = Debug|Any CPU 12 | Release|Any CPU = Release|Any CPU 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {1196D276-39C2-4EA1-966D-6775D17B0DC5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 16 | {1196D276-39C2-4EA1-966D-6775D17B0DC5}.Debug|Any CPU.Build.0 = Debug|Any CPU 17 | {1196D276-39C2-4EA1-966D-6775D17B0DC5}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {1196D276-39C2-4EA1-966D-6775D17B0DC5}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {964DDB21-8B3A-43B7-A4F3-69A35875EF84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {964DDB21-8B3A-43B7-A4F3-69A35875EF84}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {964DDB21-8B3A-43B7-A4F3-69A35875EF84}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {964DDB21-8B3A-43B7-A4F3-69A35875EF84}.Release|Any CPU.Build.0 = Release|Any CPU 23 | {22E35C09-957D-4A5A-8D0C-CA316093DED1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {22E35C09-957D-4A5A-8D0C-CA316093DED1}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {22E35C09-957D-4A5A-8D0C-CA316093DED1}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {22E35C09-957D-4A5A-8D0C-CA316093DED1}.Release|Any CPU.Build.0 = Release|Any CPU 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.3.0] - 2024-01-26 9 | * Updated to version 2.1.0 of Meziantou.Framework.StronglyTypedId and Microsoft.CodeAnalysis to 4.8.0 10 | * Fixed AddStronglyTypedIds failing becouse of https://github.com/dotnet/SqlClient/issues/1930 11 | ### Fix 12 | 13 | * Updated to version 1.0.34 of Meziantou.Framework.StronglyTypedId and Microsoft.CodeAnalysis to 4.7.0 14 | 15 | ## [1.2.0] - 2023-01-03 16 | 17 | ### Fix 18 | 19 | * Update toe 1.0.28 version of Meziantou.Framework.StronglyTypedId with need to install .net sdk v6.0.404 to make it work properly 20 | 21 | ## [1.1.1] - 2023-01-03 22 | 23 | ### Fix 24 | 25 | * Stick to version 1.0.22 of Meziantou.Framework.StronglyTypedId as higher versions introduces some errors: https://github.com/meziantou/Meziantou.Framework/issues/507 26 | 27 | ## [1.1.0] - 2022-11-15 28 | 29 | ### Changed 30 | 31 | * Updated AddStronglyTypedIds to remove assembly naming convention used for Swagger mapping configuration. 32 | 33 | ## [1.0.0] - 2022-05-26 34 | 35 | ### Added 36 | 37 | * Initiated Allegro.Extensions.Identifiers.Abstractions with basic entity and id. 38 | 39 | ## [1.0.0] - 2022-05-26 40 | 41 | ### Added 42 | 43 | * Initiated Allegro.Extensions.Identifiers.AspNetCore with swagger extensions. 44 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Identifiers/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.4.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.NullableReferenceTypes/Allegro.Extensions.NullableReferenceTypes.Tests.Unit/Allegro.Extensions.NullableReferenceTypes.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | ${NoWarn},CS8618 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.NullableReferenceTypes/Allegro.Extensions.NullableReferenceTypes.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.NullableReferenceTypes", "Allegro.Extensions.NullableReferenceTypes\Allegro.Extensions.NullableReferenceTypes.csproj", "{FE489585-F1F4-4D01-9EFB-7380CC61EE53}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.NullableReferenceTypes.Tests.Unit", "Allegro.Extensions.NullableReferenceTypes.Tests.Unit\Allegro.Extensions.NullableReferenceTypes.Tests.Unit.csproj", "{1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.NullableReferenceTypes/Allegro.Extensions.NullableReferenceTypes/Allegro.Extensions.NullableReferenceTypes.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.NullableReferenceTypes 5 | Contains useful classes and extensions for projects which use NRT. 6 | ${NoWarn},CS8618 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.NullableReferenceTypes/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.0] - 2022-05-26 9 | 10 | ### Added 11 | 12 | * Initiated Allegro.Extensions.NullableReferenceTypes project with ObjectValidator 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.NullableReferenceTypes/README.md: -------------------------------------------------------------------------------- 1 | # Allegro.Extensions.NullableReferenceTypes 2 | 3 | Contains useful classes and extensions for projects which use NRT. -------------------------------------------------------------------------------- /src/Allegro.Extensions.NullableReferenceTypes/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting.Tests.Unit/Allegro.Extensions.RateLimiting.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | false 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | all 17 | runtime; build; native; contentfiles; analyzers; buildtransitive 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1A5C6678-1714-4D2A-A0B5-DF08B4796E92}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.RateLimiting", "Allegro.Extensions.RateLimiting\Allegro.Extensions.RateLimiting.csproj", "{2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}" 6 | EndProject 7 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.RateLimiting.Tests.Unit", "Allegro.Extensions.RateLimiting.Tests.Unit\Allegro.Extensions.RateLimiting.Tests.Unit.csproj", "{FAC8446F-E898-4265-84FC-291AC35F6195}" 8 | EndProject 9 | Global 10 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 11 | Debug|Any CPU = Debug|Any CPU 12 | Release|Any CPU = Release|Any CPU 13 | EndGlobalSection 14 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 15 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 16 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Debug|Any CPU.Build.0 = Debug|Any CPU 17 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Release|Any CPU.ActiveCfg = Release|Any CPU 18 | {2E3FAF13-980B-40D2-9FFC-8D9CDB06F641}.Release|Any CPU.Build.0 = Release|Any CPU 19 | {FAC8446F-E898-4265-84FC-291AC35F6195}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 20 | {FAC8446F-E898-4265-84FC-291AC35F6195}.Debug|Any CPU.Build.0 = Debug|Any CPU 21 | {FAC8446F-E898-4265-84FC-291AC35F6195}.Release|Any CPU.ActiveCfg = Release|Any CPU 22 | {FAC8446F-E898-4265-84FC-291AC35F6195}.Release|Any CPU.Build.0 = Release|Any CPU 23 | EndGlobalSection 24 | EndGlobal 25 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.RateLimiting 5 | ... 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting/Events/AvgRateCalculated.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.RateLimiting.Events 2 | { 3 | /// 4 | /// Event handler delegate for the event of periodic average rate of rate limiter being calculated. 5 | /// 6 | #pragma warning disable CA1711 7 | public delegate void AvgRateCalculatedEventHandler(object sender, AvgRateCalculatedEventArgs e); 8 | #pragma warning restore CA1711 9 | 10 | /// 11 | /// Event arguments for the event of periodic average rate of rate limiter being calculated. 12 | /// 13 | public class AvgRateCalculatedEventArgs : EventArgs 14 | { 15 | internal AvgRateCalculatedEventArgs( 16 | double avgRate, 17 | TimeSpan period) 18 | { 19 | AvgRate = avgRate; 20 | Period = period; 21 | } 22 | 23 | /// 24 | /// Gets the average rate calculated over given Period. 25 | /// 26 | public double AvgRate { get; } 27 | 28 | /// 29 | /// Gets the period during which the average rate was calculated. 30 | /// 31 | public TimeSpan Period { get; } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting/Events/MaxRateChanged.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.RateLimiting.Events 2 | { 3 | /// 4 | /// Event handler delegate for the event of max rate of rate limiter being changed. 5 | /// 6 | #pragma warning disable CA1711 7 | public delegate void MaxRateChangedEventHandler(object sender, MaxRateChangedEventArgs e); 8 | #pragma warning restore CA1711 9 | 10 | /// 11 | /// Event arguments for the event of max rate of rate limiter being changed. 12 | /// 13 | public class MaxRateChangedEventArgs : EventArgs 14 | { 15 | internal MaxRateChangedEventArgs( 16 | double newMaxRate, 17 | double previousMaxRate) 18 | { 19 | NewMaxRate = newMaxRate; 20 | PreviousMaxRate = previousMaxRate; 21 | } 22 | 23 | /// 24 | /// Gets the new max rate that has been set. 25 | /// 26 | public double NewMaxRate { get; } 27 | 28 | /// 29 | /// Gets the previous max rate of the rate limiter. 30 | /// 31 | public double PreviousMaxRate { get; } 32 | } 33 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting/Events/MaxRateExceeded.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.RateLimiting.Events 2 | { 3 | /// 4 | /// Event handler delegate for the event of max rate of rate limiter being exceeded. 5 | /// 6 | #pragma warning disable CA1711 7 | public delegate void MaxRateExceededEventHandler(object sender, MaxRateExceededEventArgs e); 8 | #pragma warning restore CA1711 9 | 10 | /// 11 | /// Event arguments for the event of max rate of rate limiter being exceeded. 12 | /// 13 | public class MaxRateExceededEventArgs : EventArgs 14 | { 15 | internal MaxRateExceededEventArgs( 16 | double maxRate, 17 | double accumulatedOps, 18 | double attemptedOpWeight, 19 | double delayMilliseconds) 20 | { 21 | MaxRate = maxRate; 22 | AccumulatedOps = accumulatedOps; 23 | AttemptedOpWeight = attemptedOpWeight; 24 | DelayMilliseconds = delayMilliseconds; 25 | } 26 | 27 | /// 28 | /// Gets the maximum rate of the rate limiter. 29 | /// 30 | public double MaxRate { get; } 31 | 32 | /// 33 | /// Gets the total weight of operations executed so far. 34 | /// 35 | public double AccumulatedOps { get; } 36 | 37 | /// 38 | /// Gets the weight of the attempted operation, which exceeded the max rate. 39 | /// 40 | public double AttemptedOpWeight { get; } 41 | 42 | /// 43 | /// Gets the delay in milliseconds that the rate limiter will wait before executing next operations. 44 | /// 45 | public double DelayMilliseconds { get; } 46 | } 47 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting/IRateLimiter.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.RateLimiting 2 | { 3 | /// 4 | /// Allows to execute operations with rate limiting 5 | /// 6 | public interface IRateLimiter 7 | { 8 | /// 9 | /// Executes operation with rate limiting. 10 | /// This method is equivalent of ExecuteWeighted with weight = 1. 11 | /// 12 | Task ExecuteAsync(Func> operation) => ExecuteWeightedAsync(operation, 1); 13 | 14 | /// 15 | /// Executes operation with rate limiting. 16 | /// This method is equivalent of ExecuteWeighted with weight = 1. 17 | /// 18 | Task ExecuteAsync(Func operation) => ExecuteWeightedAsync(operation, 1); 19 | 20 | /// 21 | /// Executes operation with rate limiting, given the operation weight. 22 | /// Consumes "weight" from the defined limit. 23 | /// 24 | Task ExecuteWeightedAsync(Func> operation, double weight); 25 | 26 | /// 27 | /// Executes operation with rate limiting, given the operation weight. 28 | /// Consumes "weight" from the defined limit. 29 | /// 30 | Task ExecuteWeightedAsync(Func operation, double weight); 31 | 32 | /// 33 | /// Executes operation with rate limiting, estimating its weight based on previous executions of similar operation. 34 | /// 35 | /// Name of the operation (it will be used to estimate weight based on previous executions) 36 | /// Operation to execute 37 | /// Callback function to calculate (post-factum) the weight of the executed operation. 38 | Task ExecuteWithEstimatedWeightAsync( 39 | string operationName, 40 | Func> operation, 41 | Func weightCalculator); 42 | } 43 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/Allegro.Extensions.RateLimiting/IRateLimiterWithVariableRate.cs: -------------------------------------------------------------------------------- 1 | namespace Allegro.Extensions.RateLimiting 2 | { 3 | /// 4 | /// Allows to execute operations with rate limiting and change the rate dynamically. 5 | /// 6 | public interface IRateLimiterWithVariableRate : IRateLimiter 7 | { 8 | /// 9 | /// Gets the calculated average rate metric value. 10 | /// 11 | double AvgRate { get; } 12 | 13 | /// 14 | /// Gets the max rate of the rate limiter. 15 | /// 16 | double MaxRate { get; } 17 | 18 | /// 19 | /// Gets the interval over which the rate is limited. 20 | /// 21 | TimeSpan RateInterval { get; } 22 | 23 | /// 24 | /// Changes the max rate. 25 | /// 26 | /// New max rate to be set 27 | void ChangeMaxRate(double maxRate); 28 | } 29 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.2.0] - 2022-05-06 9 | 10 | ### Removed 11 | 12 | * Removed targeting net5.0 13 | 14 | ## [1.1.0] - 2022-03-28 15 | 16 | ### Changed 17 | 18 | * Multitargeting net5.0;net6.0 19 | 20 | ## [1.0.1] - 2022-03-15 21 | 22 | ### Changed 23 | 24 | * Minor code & tests refactor 25 | 26 | ## [1.0.0] - 2022-03-10 27 | 28 | ### Added 29 | 30 | * Initiated Allegro.Extensions.RateLimiting project 31 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.RateLimiting/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Serialization/Allegro.Extensions.Serialization.Tests.Unit/Allegro.Extensions.Serialization.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | AnyCPU;x64 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Serialization/Allegro.Extensions.Serialization.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Serialization", "Allegro.Extensions.Serialization\Allegro.Extensions.Serialization.csproj", "{67F2FA4E-EA48-4C88-A5D9-0186741456A4}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Serialization.Tests.Unit", "Allegro.Extensions.Serialization.Tests.Unit\Allegro.Extensions.Serialization.Tests.Unit.csproj", "{80E83F63-43D4-406F-BDC5-AFD49213E8C1}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {67F2FA4E-EA48-4C88-A5D9-0186741456A4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {67F2FA4E-EA48-4C88-A5D9-0186741456A4}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {67F2FA4E-EA48-4C88-A5D9-0186741456A4}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {67F2FA4E-EA48-4C88-A5D9-0186741456A4}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {80E83F63-43D4-406F-BDC5-AFD49213E8C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {80E83F63-43D4-406F-BDC5-AFD49213E8C1}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {80E83F63-43D4-406F-BDC5-AFD49213E8C1}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {80E83F63-43D4-406F-BDC5-AFD49213E8C1}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Serialization/Allegro.Extensions.Serialization/Allegro.Extensions.Serialization.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Serialization 5 | Contains serialization extensions and enum member helpers. 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Serialization/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.0.0] - 2022-05-18 9 | 10 | ### Added 11 | 12 | * Initiated Allegro.Extensions.Serialization project with EnumMember extension. 13 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Serialization/README.md: -------------------------------------------------------------------------------- 1 | # Allegro.Extensions.Serialization 2 | 3 | Contains serialization extensions and enum member helpers. -------------------------------------------------------------------------------- /src/Allegro.Extensions.Serialization/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.0.0 4 | 5 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/Allegro.Extensions.Validators.Tests.Unit/Allegro.Extensions.Validators.Tests.Unit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | ${NoWarn},CS8618 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/Allegro.Extensions.Validators.Tests.Unit/InputValidatorTests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using Xunit; 3 | 4 | namespace Allegro.Extensions.Validators.Tests.Unit; 5 | 6 | public class InputValidatorTests 7 | { 8 | [Theory] 9 | [InlineData(null)] 10 | [InlineData("")] 11 | [InlineData(" ")] 12 | public void EnsureHasValue_WhenInvalidInput_ShouldThrowArgumentNullException(string test) 13 | { 14 | var act = () => InputValidator.EnsureHasValue(test); 15 | act.Should().Throw(); 16 | } 17 | 18 | [Theory] 19 | [InlineData("testowy_string")] 20 | [InlineData("12333333")] 21 | public void EnsureHasValue_WhenValidInput_ShouldNotThrowAnyException(string value) 22 | { 23 | var act = () => InputValidator.EnsureHasValue(value); 24 | act.Should().NotThrow(); 25 | } 26 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/Allegro.Extensions.Validators.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Validators", "Allegro.Extensions.Validators\Allegro.Extensions.Validators.csproj", "{FE489585-F1F4-4D01-9EFB-7380CC61EE53}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Allegro.Extensions.Validators.Tests.Unit", "Allegro.Extensions.Validators.Tests.Unit\Allegro.Extensions.Validators.Tests.Unit.csproj", "{1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {FE489585-F1F4-4D01-9EFB-7380CC61EE53}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {1150B88B-C4B7-4D11-B689-ADB0AD2AACD8}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/Allegro.Extensions.Validators/Allegro.Extensions.Validators.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Allegro.Extensions.Validators 5 | Contains useful classes and extensions validators. 6 | ${NoWarn},CS8618,SA1636 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/Allegro.Extensions.Validators/OptionsBuilderFluentValidationExtensions.cs: -------------------------------------------------------------------------------- 1 | /* The MIT License (MIT) 2 | 3 | Copyright (c) 2016 andrewlock 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 | using Microsoft.Extensions.DependencyInjection; 23 | using Microsoft.Extensions.Options; 24 | 25 | namespace Allegro.Extensions.Validators; 26 | 27 | /// 28 | /// Fluent validation extensions for options builder 29 | /// 30 | public static class OptionsBuilderFluentValidationExtensions 31 | { 32 | /// 33 | /// Adds a IValidateOptions<TOptions> service with fluent validation. 34 | /// 35 | public static OptionsBuilder ValidateFluentValidation( 36 | this OptionsBuilder optionsBuilder) where TOptions : class 37 | { 38 | optionsBuilder.Services.AddSingleton>( 39 | provider => new FluentValidationOptions( 40 | optionsBuilder.Name, provider)); 41 | return optionsBuilder; 42 | } 43 | } -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres 6 | to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [1.1.0] - 2022-11-16 9 | 10 | ### Added 11 | 12 | * Fluent validation extensions 13 | 14 | ## [1.0.0] - 2022-07-26 15 | 16 | ### Added 17 | 18 | * Initiated Allegro.Extensions.Validators project with InputValidators -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/README.md: -------------------------------------------------------------------------------- 1 | # Allegro.Extensions.Validators 2 | 3 | Contains useful classes and extensions validators especially null and non empty checks. 4 | 5 | ## Fluent validation 6 | 7 | This package provides extensions for easy registration of fluent validators. 8 | 9 | ### Usage 10 | 11 | Create IOptions with fluent validation enabled 12 | 13 | ```csharp 14 | public void ConfigureServices(IServiceCollection services) 15 | { 16 | services.AddOptionsWithFluentValidation("configuration section name"); 17 | } 18 | ``` 19 | 20 | Add a fluent validator to IOptionsBuilder 21 | 22 | ```csharp 23 | public void ConfigureServices(IServiceCollection services) 24 | { 25 | services.AddOptions() 26 | .BindConfiguration(configurationSection) 27 | .ValidateFluentValidation(); 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /src/Allegro.Extensions.Validators/version.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1.2.0 4 | 5 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(NetCoreVersions) 5 | false 6 | 7 | 8 | 9 | true 10 | 11 | 12 | $(SolutionDir)\bin\$(MSBuildProjectName) 13 | $(SolutionDir)\obj\$(MSBuildProjectName) 14 | $(SolutionDir)\nuget 15 | 16 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /src/Package.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $(NetCoreVersions) 5 | Allegro 6 | Allegro 7 | Copyright © Allegro Group 8 | Apache-2.0 9 | https://github.com/allegro/dotnet-utils 10 | README.md 11 | true 12 | snupkg 13 | true 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | --------------------------------------------------------------------------------