[
  {
    "path": ".editorconfig",
    "content": "﻿[*.cs]\n\n# CS8618: Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.\ndotnet_diagnostic.CS8618.severity = silent\n"
  },
  {
    "path": ".github/dco.yml",
    "content": "allowRemediationCommits:\n  individual: true"
  },
  {
    "path": ".github/workflows/base-liquid-ci-and-cd.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Base Reusable CI & CD workflow used by Liquid Application Framework components\n\non:\n  # Allows this workflow to be called by other workflows\n  workflow_call:\n    inputs:\n      component_name:\n        description: 'The component name to build'\n        required: true\n        type: string\n    secrets:\n      sonar_token:\n        required: true\n      nuget_token:\n        required: false\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Identify Job Type from workflow trigger event type\n      run: |\n        if [ \"$GITHUB_EVENT_NAME\" == \"push\" ]\n        then\n          echo \"Starting CD Job: Build, Test, Analyze, Pack and Publish library to Nuget.org...\"\n        else\n          echo \"Starting CI Job: Build, Test and Analyze...\"\n        fi\n    \n    - name: (CI on PR) Checkout repo on Pull Request\n      if: ${{ github.event_name == 'pull_request' }}\n      uses: actions/checkout@v3\n      with:\n        ref: ${{github.event.pull_request.head.ref}}\n        repository: ${{github.event.pull_request.head.repo.full_name}}\n        fetch-depth: 0 # required to eliminate shallow clone warning in Sonarcloud analysis\n        \n    - name: (CI/CD) Checkout repo\n      if: ${{ github.event_name != 'pull_request' }}\n      uses: actions/checkout@v3\n      with:\n        fetch-depth: 0 # required to eliminate shallow clone warning in Sonarcloud analysis\n\n    # required by sonarcloud scanner\n    - name: (CI/CD) Setup Java JDK\n      if: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') }}\n      uses: actions/setup-java@v3\n      with:\n        # The Java version to make available on the path. Takes a whole or semver Java version, or 1.x syntax (e.g. 1.8 => Java 8.x). Early access versions can be specified in the form of e.g. 14-ea, 14.0.0-ea, or 14.0.0-ea.28\n        distribution: 'microsoft'\n        java-version: 17.x\n        \n    - name: (CI/CD) Setup .NET Core SDK\n      uses: actions/setup-dotnet@v2\n      with:\n        # SDK version to use. Examples: 2.2.104, 3.1, 3.1.x\n        dotnet-version: | \n          3.1.x\n          5.0.x\n          6.0.x\n          8.0.x\n    # required by sonarcloud scanner\n    - name: (CI/CD) Setup Sonar Scanner tool\n      if: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') }}\n      run: dotnet tool install --global dotnet-sonarscanner\n\n    - name: (CI/CD) Install Test Reporting Tool\n      run: dotnet tool install --global dotnet-reportgenerator-globaltool\n\n    - name: (CI/CD) Restore dependencies\n      run: dotnet restore src/${{ inputs.component_name }}/${{ inputs.component_name }}.csproj\n\n    - name: (CI/CD) Build and Analyze Project\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}  # Needed to get PR information, if any\n        SONAR_TOKEN: ${{ secrets.sonar_token }}\n        RUN_SONAR: ${{ github.event_name != 'pull_request' || (github.event.pull_request.head.repo.full_name == github.repository && github.actor != 'dependabot[bot]') }}\n      run: |\n        if [ \"$RUN_SONAR\" == \"true\" ]\n        then\n          if [[ -d test/${{ inputs.component_name }}.Tests && -f test/${{ inputs.component_name }}.Tests/${{ inputs.component_name }}.Tests.csproj ]]\n          then \n            dotnet sonarscanner begin /k:\"${{ inputs.component_name }}\" /o:\"avanade-1\" /d:sonar.login=\"${{ secrets.sonar_token }}\" /d:sonar.host.url=\"https://sonarcloud.io\" /d:sonar.cs.vstest.reportsPaths=$GITHUB_WORKSPACE/test/testresults/*.trx /d:sonar.coverageReportPaths=$GITHUB_WORKSPACE/test/coverlet/reports/SonarQube.xml\n          else\n            dotnet sonarscanner begin /k:\"${{ inputs.component_name }}\" /o:\"avanade-1\" /d:sonar.login=\"${{ secrets.sonar_token }}\" /d:sonar.host.url=\"https://sonarcloud.io\"\n          fi\n        fi\n        \n        dotnet build src/${{ inputs.component_name }}/${{ inputs.component_name }}.csproj --configuration Release --no-restore\n        \n        if [[ -d test/${{ inputs.component_name }}.Tests && -f test/${{ inputs.component_name }}.Tests/${{ inputs.component_name }}.Tests.csproj ]]\n        then \n          dotnet test test/${{ inputs.component_name }}.Tests/${{ inputs.component_name }}.Tests.csproj --collect:\"XPlat Code Coverage\" --logger trx --results-directory $GITHUB_WORKSPACE/test/testresults\n          reportgenerator -reports:$GITHUB_WORKSPACE/test/testresults/**/coverage.cobertura.xml -targetdir:$GITHUB_WORKSPACE/test/coverlet/reports -reporttypes:\"SonarQube\"\n        fi\n        \n        if [ \"$RUN_SONAR\" == \"true\" ]\n        then\n          dotnet sonarscanner end /d:sonar.login=\"${{ secrets.sonar_token }}\"\n        fi\n\n    - name: (CD) Nuget Pack & Push to Nuget.org\n      if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}\n      run: |\n        dotnet pack --no-build --configuration Release src/${{ inputs.component_name }}/${{ inputs.component_name }}.csproj --output .\n        dotnet nuget push *.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{ secrets.nuget_token }} --skip-duplicate\n        \n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-cache-memory.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Cache.Memory component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Cache.Memory/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Cache.Memory/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Cache.Memory\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_CACHE_MEMORY }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-cache-ncache.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Cache.NCache component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Cache.NCache/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Cache.NCache/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Cache.NCache\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_CACHE_NCACHE }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-cache-redis.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Cache.Redis component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Cache.Redis/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Cache.Redis/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Cache.Redis\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_CACHE_REDIS }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-cache-sqlserver.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Cache.SqlServer component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Cache.SqlServer/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Cache.SqlServer/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Cache.SqlServer\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_CACHE_SQLSERVER }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-core-telemetry-elasticapm.yaml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Core.Telemetry.ElasticApm component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Core.Telemetry.ElasticApm/**'\n    \n  pull_request:\n    branches: [ main ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Core.Telemetry.ElasticApm/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Core.Telemetry.ElasticApm\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_ELASTICAPM }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-core.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Core component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Core/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Core/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Core\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_CORE }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-dataverse.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Dataverse component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Dataverse/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Dataverse/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Dataverse\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_DATAVERSE }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-genai-openai.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.GenAi.OpenAi component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main ]\n    paths:\n    - 'src/Liquid.GenAi.OpenAi/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.GenAi.OpenAi/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.GenAi.OpenAi\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_OPENAI }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-http.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.WebApi.Http component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.WebApi.Http/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.WebApi.Http/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.WebApi.Http\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_HTTP }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-messaging-kafka.yaml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Messaging.Kafka cartridge for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Messaging.Kafka/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Messaging.Kafka/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Messaging.Kafka\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_KAFKA }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-messaging-rabbitmq.yaml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Messaging.RabbitMq cartridge for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Messaging.RabbitMq/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Messaging.RabbitMq/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Messaging.RabbitMq\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_RABBIT }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-messaging-servicebus.yaml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Messaging.ServiceBus cartridge for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Messaging.ServiceBus/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Messaging.ServiceBus/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Messaging.ServiceBus\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_SB }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-repository-entityframework.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Repository.EntityFramework Cartridge for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Repository.EntityFramework/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Repository.EntityFramework/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Repository.EntityFramework\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_EF }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-repository-mongodb.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Repository.Mongo Cartridge for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Repository.Mongo/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Repository.Mongo/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Repository.Mongo\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_MONGO }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-repository-odata.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Repository.OData Cartridge for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Repository.OData/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Repository.OData/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Repository.OData\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_ODATA }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-storage-azurestorage.yml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Storage.AzureStorage component for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'src/Liquid.Storage.AzureStorage/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'src/Liquid.Storage.AzureStorage/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  call-reusable-build-workflow:\n    uses: Avanade/Liquid-Application-Framework/.github/workflows/base-liquid-ci-and-cd.yml@main\n    with:\n      component_name: Liquid.Storage.AzureStorage\n    secrets:\n      sonar_token: ${{ secrets.SONAR_TOKEN_STORAGE }}\n      nuget_token: ${{ secrets.PUBLISH_TO_NUGET_ORG }}\n"
  },
  {
    "path": ".github/workflows/liquid-ci-cd-templates.yaml",
    "content": "# CI & CD workflow\nname: CI/CD - Liquid.Templates for Liquid Application Framework\n\non:\n  push:\n    branches: [ main, releases/v2.X.X, releases/v6.X.X ]\n    paths:\n    - 'templates/src/Liquid.Templates/**'\n    \n  pull_request:\n    branches: [ main, releases/** ]\n    types: [opened, synchronize, reopened]\n    paths:\n    - 'templates/src/Liquid.Templates/**'\n\n  # Allows you to run this workflow manually from the Actions tab\n  workflow_dispatch:\n\njobs:\n  build:\n\n    runs-on: ubuntu-latest\n\n    steps:\n    - name: Job Type\n      run: |\n        if [$GITHUB_EVENT_NAME == 'push']\n        then\n          echo \"Starting CD Job: Build, Test, Analyze, Pack and Publish library to Nuget.org...\"\n        else\n          echo \"Starting CI Job: Build, Test and Analyze...\"\n        fi\n    \n    - name: (CI) Checkout repo on Pull Request\n      if: ${{ github.event_name == 'pull_request' }}\n      uses: actions/checkout@v2\n      with:\n        ref: ${{github.event.pull_request.head.ref}}\n        repository: ${{github.event.pull_request.head.repo.full_name}}\n        fetch-depth: 0 # required to eliminate shallow clone warning in Sonarcloud analysis\n        \n    - name: (CI/CD) Checkout repo\n      if: ${{ github.event_name != 'pull_request' }}\n      uses: actions/checkout@v2\n      with:\n        fetch-depth: 0 # required to eliminate shallow clone warning in Sonarcloud analysis\n        \n    - name: (CI/CD) Setup .NET Core SDK\n      uses: actions/setup-dotnet@v1.7.2\n      with:\n        # SDK version to use. Examples: 2.2.104, 3.1, 3.1.x\n        dotnet-version: 3.1.x\n\n    - name: (CI/CD) Restore dependencies\n      run: dotnet restore templates/src/Liquid.Templates/Liquid.Templates.csproj\n\n    - name: (CI/CD) Build and Analyze Project\n      run: |\n        dotnet build templates/src/Liquid.Templates/Liquid.Templates.csproj --configuration Release --no-restore\n        \n    - name: (CD) Nuget Pack & Push to Nuget.org\n      if: ${{ github.event_name == 'push' }}\n      run: |\n        dotnet pack --no-build --configuration Release templates/src/Liquid.Templates/Liquid.Templates.csproj --output .\n        dotnet nuget push *.nupkg --source https://api.nuget.org/v3/index.json --api-key ${{secrets.PUBLISH_TO_NUGET_ORG}} --skip-duplicate\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n##\n## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015/2017 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# Visual Studio 2017 auto generated files\nGenerated\\ Files/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# Benchmark Results\nBenchmarkDotNet.Artifacts/\n\n# .NET Core\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n**/Properties/launchSettings.json\n\n# StyleCop\nStyleCopReport.xml\n\n# Files built by Visual Studio\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.iobj\n*.pch\n*.pdb\n*.ipdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# Visual Studio Trace Files\n*.e2e\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# AxoCover is a Code Coverage Tool\n.axoCover/*\n!.axoCover/settings.json\n\n# Visual Studio code coverage results\n*.coverage\n*.coveragexml\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# Note: Comment the next line if you want to checkin your web deploy settings,\n# but database connection strings (with potential passwords) will be unencrypted\n*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/[Pp]ackages/*\n# except build/, which is used as an MSBuild target.\n!**/[Pp]ackages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/[Pp]ackages/repositories.config\n# NuGet v3's project.json files produces more ignorable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n*.appx\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\norleans.codegen.cs\n\n# Including strong name files can present a security risk \n# (https://github.com/github/gitignore/pull/2483#issue-259490424)\n#*.snk\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\nServiceFabricBackup/\n*.rptproj.bak\n\n# SQL Server files\n*.mdf\n*.ldf\n*.ndf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n*.rptproj.rsuser\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\nnode_modules/\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)\n*.vbw\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n\n# Cake - Uncomment if you are using it\n# tools/**\n# !tools/packages.config\n\n# Tabs Studio\n*.tss\n\n# Telerik's JustMock configuration file\n*.jmconfig\n\n# BizTalk build output\n*.btp.cs\n*.btm.cs\n*.odx.cs\n*.xsd.cs\n\n# OpenCover UI analysis results\nOpenCover/\n\n# Azure Stream Analytics local run output \nASALocalRun/\n\n# MSBuild Binary and Structured Log\n*.binlog\n\n# NVidia Nsight GPU debugger configuration file\n*.nvuser\n\n# MFractors (Xamarin productivity tool) working folder \n.mfractor/\n"
  },
  {
    "path": "CONTRIBUTING.md",
    "content": "# How to contribute\n\nThis project welcomes contributions and suggestions. By contributing, you confirm that you have the right to, and actually do, grant us the rights to use your contribution. More information below.\n\nPlease feel free to contribute code, ideas, improvements, and patches - we've added some general guidelines and information below, and you can propose changes to this document in a pull request.\n\nThis project has adopted the [Contributor Covenant Code of Conduct](https://avanade.github.io/code-of-conduct/).\n\nOne of the easiest ways to contribute is to participate in discussions on GitHub issues. You can also contribute by submitting pull requests with code changes.\n\n## Rights to your contributions\nBy contributing to this project, you:\n- Agree that you have authored 100% of the content\n- Agree that you have the necessary rights to the content\n- Agree that you have received the necessary permissions from your employer to make the contributions (if applicable)\n- Agree that the content you contribute may be provided under the Project license(s)\n- Agree that, if you did not author 100% of the content, the appropriate licenses and copyrights have been added along with any other necessary attribution.\n\n## Code of Conduct\nThis project, and people participating in it, are governed by our [code of conduct](https://avanade.github.io/code-of-conduct/). By taking part, we expect you to try your best to uphold this code of conduct. If you have concerns about unacceptable behaviour, please contact the community leaders responsible for enforcement at\n[ospo@avanade.com](ospo@avanade.com).\n\n## Developer Certificate of Origin (DCO)\nAvanade asks that all commits sign the [Developer Certificate of Origin](https://developercertificate.org/), to ensure that every developer is confirming that they have the right to upload the code they submit.\n\nSign-offs are added to the commit. Git has a  `-s` command line option to append this automatically to your commit message, and [sign offs can be added through the web interface](https://github.blog/changelog/2022-06-08-admins-can-require-sign-off-on-web-based-commits/).\n\n## General feedback and discussions?\n\nStart a discussion on the [repository issue tracker](https://github.com/Avanade/Liquid-Application-Framework/issues).\n\n## Bugs and feature requests?\n\nFor non-security related bugs, log a new issue in the GitHub repository.\n\n## Reporting security issues and bugs\n\nSecurity issues and bugs should be reported privately, via email, to a repository admin. You should receive a response within 24 hours. We also ask you to file via our [security disclosure](https://github.com/Avanade/avanade-template/blob/main/SECURITY.md) policy.\n\n## Contributing code and content\n\nWe accept fixes and features! Here are some resources to help you get started on how to contribute code or new content.\n\n* [\"Help wanted\" issues](https://github.com/Avanade/Liquid-Application-Framework/labels/help%20wanted) - these issues are up for grabs. Comment on an issue if you want to create a fix.\n* [\"Good first issue\" issues](https://github.com/Avanade/Liquid-Application-Framework/labels/good%20first%20issue) - we think these are a good for newcomers.\n\n### Identifying the scale\n\nIf you would like to contribute to one of our repositories, first identify the scale of what you would like to contribute. If it is small (grammar/spelling or a bug fix) feel free to start working on a fix. If you are submitting a feature or substantial code contribution, please discuss it with the team and ensure it follows the product roadmap. You might also read these two blogs posts on contributing code: [Open Source Contribution Etiquette](http://tirania.org/blog/archive/2010/Dec-31.html) by Miguel de Icaza and [Don't \"Push\" Your Pull Requests](https://www.igvita.com/2011/12/19/dont-push-your-pull-requests/) by Ilya Grigorik. All code submissions will be rigorously reviewed and tested by the team, and only those that meet an extremely high bar for both quality and design/roadmap appropriateness will be merged into the source.\n\n### Submitting a pull request\n\nIf you don't know what a pull request is read this article: https://help.github.com/articles/using-pull-requests. **Make sure the repository can build and all tests pass.** Familiarize yourself with the project workflow and our coding conventions. The coding, style, and general engineering guidelines are below on the topic [Engineering guidelines](#Engineering-guidelines).\n\n### Feedback\n\nYour pull request will now go through **extensive checks** by the subject matter experts on our team. Please be patient. Update your pull request according to feedback until it is approved by one of the ASP.NET team members. After that, one of our team members may adjust the branch you merge into based on the expected release schedule.\n\n# Engineering Guidelines\n\n## General\n\nWe try to hold our code to the higher standards. Every pull request must and will be scrutinized in order to maintain our standard. Every pull request should improve on quality, therefore any PR that decreases the quality will not be approved.\n\nWe follow coding best practices to make sure the codebase is clean and newcomers and seniors alike will understand the code. This document provides a guideline that should make most of our practices clear, but gray areas may arise and we might make a judgment call on your code, so, when in doubt, question ahead. Issues are a wonderful tool that should be used by every contributor to help us drive the project.\n\nAll the rules here are mandatory; however, we do not claim to hold all the answers - you can raise a question over any rule any time (through issues) and we'll discuss it.\n\nFinally, this is a new project and we are still learning how to work on a Open Source project. Please bear with us while we learn how to do it best.\n\n## External dependencies\n\nThis refers to dependencies on projects (i.e. NuGet packages) outside of the repo. Every dependency we add enlarges the package, and might have copyright issues that we may need to address.\n\nTherefore, adding or updating any external dependency requires approval. This can be discussed preferrabily on the issue related to the PR or on the PR itself.\n\n## Code reviews and checkins\n\nTo help ensure that only the highest quality code makes its way into the project, please submit all your code changes to GitHub as PRs. This includes runtime code changes, unit test updates, and updates to official samples. For example, sending a PR for just an update to a unit test might seem like a waste of time but the unit tests are just as important as the product code and as such, reviewing changes to them is also just as important. This also helps create visibility for your changes so that others can observe what is going on.\n\nThe advantages are numerous: improving code quality, more visibility on changes and their potential impact, avoiding duplication of effort, and creating general awareness of progress being made in various areas.\n\nTo commit the PR to the repo either use preferably GitHub's \"Squash and Merge\" button on the main PR page, or do a typical push that you would use with Git (e.g. local pull, rebase, merge, push).\n\n## Branching Strategy\n\nWe are using [Trunk-Based branching strategy](https://trunkbaseddevelopment.com/).\n\n## Assembly naming pattern\n\nThe general naming pattern is `Liquid.<area>.<subarea>`.\n\n## Unit tests\n\nWe use NUnit for all unit testing. Additionally, you can use NSubstitute for mocks and such, and leverage AutoFixture for anonymous instances.\n\n## Code Style\n\n### General\n\nThe most general guideline is that we use all the VS default settings in terms of code formatting, except that we put System namespaces before other namespaces (this used to be the default in VS, but it changed in a more recent version of VS). Also, we are leveraging StyleCop to add to code standardization.\n\n1. Use four spaces of indentation (no tabs)\n1. Use `_camelCase` for private fields\n1. Avoid `this`. unless absolutely necessary\n1. Always specify member visibility, even if it's the default (i.e. `private string _foo;` not `string _foo;`)\n1. Open-braces (`{`) go on a new line\n1. Use any language features available to you (expression-bodied members, throw expressions, tuples, etc.) as long as they make for readable, manageable code.\nThis is pretty bad: `public (int, string) GetData(string filter) => (Data.Status, Data.GetWithFilter(filter ?? throw new ArgumentNullException(nameof(filter))));`\n\n### Usage of the var keyword\n\nThe var keyword is to be used as much as the compiler will allow. For example, these are correct:\n\n```csharp\nvar fruit = \"Lychee\";\nvar fruits = new List<Fruit>();\nvar flavor = fruit.GetFlavor();\nstring fruit = null; // can't use \"var\" because the type isn't known (though you could do (string)null, don't!)\nconst string expectedName = \"name\"; // can't use \"var\" with const\n```\n\nThe following are incorrect:\n\n```csharp\nstring fruit = \"Lychee\";\nList<Fruit> fruits = new List<Fruit>();\nFruitFlavor flavor = fruit.GetFlavor();\n```\n\n### Use C# type keywords in favor of .NET type names\n\nWhen using a type that has a C# keyword the keyword is used in favor of the .NET type name. For example, these are correct:\n\n```csharp\npublic string TrimString(string s) {\n    return string.IsNullOrEmpty(s)\n        ? null\n        : s.Trim();\n}\n\n\nvar intTypeName = nameof(Int32); // can't use C# type keywords with nameof\n```\n\nThe following are incorrect:\n\n```csharp\npublic String TrimString(String s) {\n    return String.IsNullOrEmpty(s)\n        ? null\n        : s.Trim();\n}\n```\n\n### Cross-platform coding\n\nOur frameworks should work on CoreCLR, which supports multiple operating systems. Don't assume we only run (and develop) on Windows. Code should be sensitive to the differences between OS's. Here are some specifics to consider.\n\n#### Line breaks\n\nWindows uses \\r\\n, OS X and Linux uses \\n. When it is important, use Environment.NewLine instead of hard-coding the line break.\n\nNote: this may not always be possible or necessary.\n\nBe aware that these line-endings may cause problems in code when using @\"\" text blocks with line breaks.\n\n#### Environment Variables\n\nOS's use different variable names to represent similar settings. Code should consider these differences.\n\nFor example, when looking for the user's home directory, on Windows the variable is USERPROFILE but on most Linux systems it is HOME.\n\n```csharp\nvar homeDir = Environment.GetEnvironmentVariable(\"USERPROFILE\")\n                  ?? Environment.GetEnvironmentVariable(\"HOME\");\n```\n\n#### File path separators\n\nWindows uses \\ and OS X and Linux use / to separate directories. Instead of hard-coding either type of slash, use Path.Combine() or Path.DirectorySeparatorChar.\n\nIf this is not possible (such as in scripting), use a forward slash. Windows is more forgiving than Linux in this regard.\n\n### When to use internals vs. public and when to use InternalsVisibleTo\n\nAs a modern set of frameworks, usage of internal types and members is allowed, but discouraged.\n\n`InternalsVisibleTo` is used only to allow a unit test to test internal types and members of its runtime assembly. We do not use `InternalsVisibleTo` between two runtime assemblies.\n\nIf two runtime assemblies need to share common helpers then we will use a \"shared source\" solution with build-time only packages.\n\nIf two runtime assemblies need to call each other's APIs, the APIs must be public. If we need it, it is likely that our customers need it.\n\n### Async method patterns\n\nBy default all async methods must have the Async suffix. There are some exceptional circumstances where a method name from a previous framework will be grandfathered in.\n\nPassing cancellation tokens is done with an optional parameter with a value of `default(CancellationToken)`, which is equivalent to `CancellationToken.None` (one of the few places that we use optional parameters). The main exception to this is in web scenarios where there is already an `HttpContext` being passed around, in which case the context has its own cancellation token that can be used when needed.\n\nSample async method:\n\n```csharp\npublic Task GetDataAsync(\n    QueryParams query,\n    int maxData,\n    CancellationToken cancellationToken = default(CancellationToken))\n{\n    ...\n}\n```\n\n### Extension method patterns\n\nThe general rule is: if a regular static method would suffice, avoid extension methods.\n\nExtension methods are often useful to create chainable method calls, for example, when constructing complex objects, or creating queries.\n\nInternal extension methods are allowed, but bear in mind the previous guideline: ask yourself if an extension method is truly the most appropriate pattern.\n\nThe namespace of the extension method class should generally be the namespace that represents the functionality of the extension method, as opposed to the namespace of the target type. One common exception to this is that the namespace for middleware extension methods is normally always the same is the namespace of IAppBuilder.\n\nThe class name of an extension method container (also known as a \"sponsor type\") should generally follow the pattern of `<Feature>Extensions`, `<Target><Feature>Extensions`, or `<Feature><Target>Extensions`. For example:\n\n```csharp\nnamespace Food {\n    class Fruit { ... }\n}\n\nnamespace Fruit.Eating {\n    class FruitExtensions { public static void Eat(this Fruit fruit); }\n  OR\n    class FruitEatingExtensions { public static void Eat(this Fruit fruit); }\n  OR\n    class EatingFruitExtensions { public static void Eat(this Fruit fruit); }\n}\n```\n\nWhen writing extension methods for an interface the sponsor type name must not start with an I.\n\n### Analyzers\n\nCode style is usually enforced by Analyzers; any change to those rules must be discussed with the team before it's made. Also, any pull request that changes analyzers rules and commits code will be reproved immediately.\n\n### Good practices\n\nThe items below point out the good practices that all code should follow.\n\n#### Zero warnings\n\nCompiler warnings should usually be dealt with by correcting the code. Only discussed warnings may be allowed to be marked as exceptions.\n\n#### Inner documentation\n\nAll public members must be documented. Documentation should clarify the purpose and usage of code elements, so comments such as FooManager: \"manages foo\" will be rejected. Classes that implement interface may use comment inheritance `/// <inheritdoc/>`, but use it sparingly.\n\nTry to use examples and such in classes to enable users to understand them more easily.\n\nIf you don't believe that a class or method deserves to be documents, ask yourself if it can be marked as non-public.\n\nIf should comment every non-public class or member that is complex enough.\n\nAll comments should be read-proof.\n\n> **Note**: Public means callable by a customer, so it includes protected APIs. However, some public APIs might still be \"for internal use only\" but need to be public for technical reasons. We will still have doc comments for these APIs but they will be documented as appropriate.\n\n## Tests\n\n- Tests need to be provided for every bug/feature that is completed.\n- Tests only need to be present for issues that need to be verified by QA (for example, not tasks)\n- Pull requests must strive to not reduce code coverage.\n- If there is a scenario that is far too hard to test there does not need to be a test for it.\n  - \"Too hard\" is determined by the team as a whole.\n\n### Unit tests and functional tests\n\n#### Assembly naming\n\nThe unit tests for the `Liquid.Fruit` assembly live in the `Liquid.Fruit.Tests` assembly.\n\nThe functional tests for the `Liquid.Fruit` assembly live in the `Liquid.Fruit.AcceptanceTests` assembly.\n\nIn general there should be exactly one unit test assembly for each product runtime assembly. In general there should be one functional test assembly per repo. Exceptions can be made for both.\n\n#### Unit test class naming\n\nTest class names end with Test and live in the same namespace as the class being tested. For example, the unit tests for the Liquid.Fruit.Banana class would be in a Liquid.Fruit.BananaTest class in the test assembly.\n\n#### Unit test method naming\n\nUnit test method names must be descriptive about what is being tested, under what conditions, and what the expectations are. Pascal casing and underscores can be used to improve readability. We will try to follow [Roy Osherove's guidelines](https://osherove.com/blog/2005/4/3/naming-standards-for-unit-tests.html), therefore, the following test names are correct:\n`GetAttachmentWhenItWasInsertedReturnsInsertedData`\n`GetWhenAttachmentDoesntExistsThrows`\n\n> Notice how we use When and Returns / Throws to split the name into recognizable parts.\n\nThe following test names are incorrect:\n\n```csharp\nTest1\nConstructor\nFormatString\nGetData\n```\n\n#### Unit test structure\n\nThe contents of every unit test should be split into three distinct stages, optionally separated by these comments:\n\n```csharp\n// Arrange\n// Act\n// Assert\n```\n\nThe crucial thing here is that the Act stage is exactly one statement. That one statement is nothing more than a call to the one method that you are trying to test. Keeping that one statement as simple as possible is also very important. For example, this is not ideal:\n\n```csharp\nint result = myObj.CallSomeMethod(GetComplexParam1(), GetComplexParam2(), GetComplexParam3());\n```\n\nThis style is not recommended because way too many things can go wrong in this one statement. All the `GetComplexParamN()` calls can throw for a variety of reasons unrelated to the test itself. It is thus unclear to someone running into a problem why the failure occurred.\n\nThe ideal pattern is to move the complex parameter building into the Arrange section:\n\n```csharp\n// Arrange\nP1 p1 = GetComplexParam1();\nP2 p2 = GetComplexParam2();\nP3 p3 = GetComplexParam3();\n\n// Act\nint result = myObj.CallSomeMethod(p1, p2, p3);\n\n// Assert\nAssert.AreEqual(1234, result);\n```\n\nNow the only reason the line with `CallSomeMethod()` can fail is if the method itself blew up. This is especially important when you're using helpers such as ExceptionHelper, where the delegate you pass into it must fail for exactly one reason.\n\n#### Use NUnit's plethora of built-in assertions\n\nNUnit includes many kinds of assertions – please use the most appropriate one for your test. This will make the tests a lot more readable and also allow the test runner report the best possible errors (whether it's local or the CI machine). For example, these are bad:\n\n```csharp\nAssert.AreEqual(true, someBool);\n\nAssert.True(\"abc123\" == someString);\n\nAssert.True(list1.Length == list2.Length);\n\nfor (int i = 0; i < list1.Length; i++) {\n    Assert.True(\n        String.Equals\n            list1[i],\n            list2[i],\n            StringComparison.OrdinalIgnoreCase));\n}\n```\n\nThese are good:\n\n```csharp\nAssert.True(someBool);\n\nAssert.AreEqual(\"abc123\", someString);\n\n// built-in collection assertions!\nAssert.AreEqual(list1, list2, StringComparer.OrdinalIgnoreCase);\n```\n\nIt's also possible (and recommended) to use the new ContraintModel of NUnit:\n\n```csharp\nAssert.That(condition, Is.True);\n\nint[] array = new int[] { 1, 2, 3 };\nAssert.That(array, Has.Exactly(1).EqualTo(3));\nAssert.That(array, Has.Exactly(2).GreaterThan(1));\nAssert.That(array, Has.Exactly(3).LessThan(100));\n```\n\n#### Parallel tests\n\nBy default all unit test assemblies should run in parallel mode, which is the default. Unit tests shouldn't depend on any shared state, and so should generally be runnable in parallel. If the tests fail in parallel, the first thing to do is to figure out why; do not just disable parallel tests!\n\nFor functional tests it is reasonable to disable parallel tests.\n\n### Use only complete words or common/standard abbreviations in public APIs\n\nPublic namespaces, type names, member names, and parameter names must use complete words or common/standard abbreviations.\n\nThese are correct:\n\n```csharp\npublic void AddReference(AssemblyReference reference);\npublic EcmaScriptObject SomeObject { get; }\n```\n\nThese are incorrect:\n\n```csharp\npublic void AddRef(AssemblyReference ref);\npublic EcmaScriptObject SomeObj { get; }\n```\n\nNote that abbreviations still follow camel/pascal casing. Use `Api` instead of `API` and `Ecma` instead of `ECMA`, to make your code more legible.\n\nAvoid abbreviations with only two characters because of the rule above.\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) 2021 Avanade\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "Liquid.Adapters.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.6.34202.202\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Adapter.Dataverse\", \"src\\Liquid.Adapter.Dataverse\\Liquid.Adapter.Dataverse.csproj\", \"{02191AB8-D13C-4CCC-8455-08813FB0C9C3}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Adapter.Dataverse.Tests\", \"test\\Liquid.Adapter.Dataverse.Tests\\Liquid.Adapter.Dataverse.Tests.csproj\", \"{90D60966-6004-4705-907D-780503EBC141}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Dataverse\", \"Dataverse\", \"{0E973865-5B87-43F2-B513-CD1DA96A2A3A}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"AzureStorage\", \"AzureStorage\", \"{81CB75D9-FC31-4533-9A2D-C9277DD4A33E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Adapter.AzureStorage\", \"src\\Liquid.Adapter.AzureStorage\\Liquid.Adapter.AzureStorage.csproj\", \"{E21AF05A-738E-4DA2-AEEE-9900D7534F7C}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Liquid.Adapter.AzureStorage.Tests\", \"test\\Liquid.Adapter.AzureStorage.Tests\\Liquid.Adapter.AzureStorage.Tests.csproj\", \"{A2A7E164-98DF-4953-9679-B35E109E8990}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{02191AB8-D13C-4CCC-8455-08813FB0C9C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{02191AB8-D13C-4CCC-8455-08813FB0C9C3}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{02191AB8-D13C-4CCC-8455-08813FB0C9C3}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{02191AB8-D13C-4CCC-8455-08813FB0C9C3}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{90D60966-6004-4705-907D-780503EBC141}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{90D60966-6004-4705-907D-780503EBC141}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{90D60966-6004-4705-907D-780503EBC141}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{90D60966-6004-4705-907D-780503EBC141}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{E21AF05A-738E-4DA2-AEEE-9900D7534F7C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E21AF05A-738E-4DA2-AEEE-9900D7534F7C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E21AF05A-738E-4DA2-AEEE-9900D7534F7C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E21AF05A-738E-4DA2-AEEE-9900D7534F7C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A2A7E164-98DF-4953-9679-B35E109E8990}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A2A7E164-98DF-4953-9679-B35E109E8990}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A2A7E164-98DF-4953-9679-B35E109E8990}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A2A7E164-98DF-4953-9679-B35E109E8990}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{02191AB8-D13C-4CCC-8455-08813FB0C9C3} = {0E973865-5B87-43F2-B513-CD1DA96A2A3A}\n\t\t{90D60966-6004-4705-907D-780503EBC141} = {0E973865-5B87-43F2-B513-CD1DA96A2A3A}\n\t\t{E21AF05A-738E-4DA2-AEEE-9900D7534F7C} = {81CB75D9-FC31-4533-9A2D-C9277DD4A33E}\n\t\t{A2A7E164-98DF-4953-9679-B35E109E8990} = {81CB75D9-FC31-4533-9A2D-C9277DD4A33E}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {8105640B-39D2-4FFE-8BBD-D8E37F2A070D}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Liquid.Application.Framework.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.8.34408.163\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Core\", \"src\\Liquid.Core\\Liquid.Core.csproj\", \"{C33A89FC-4F4D-4274-8D0F-29456BA8F76B}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Solution Items\", \"Solution Items\", \"{EE1C8DCF-EBC3-43B8-9E9C-433CDD57FB30}\"\n\tProjectSection(SolutionItems) = preProject\n\t\ttest\\CodeCoverage.runsettings = test\\CodeCoverage.runsettings\n\t\t.github\\workflows\\liquid-core-ci-cd-publish.yml = .github\\workflows\\liquid-core-ci-cd-publish.yml\n\t\tlogo.png = logo.png\n\t\tnuget.config = nuget.config\n\tEndProjectSection\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Core.Tests\", \"test\\Liquid.Core.Tests\\Liquid.Core.Tests.csproj\", \"{69B34B22-198D-4BD0-AAFC-39A90F9ADAC2}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Core.Telemetry.ElasticApm\", \"src\\Liquid.Core.Telemetry.ElasticApm\\Liquid.Core.Telemetry.ElasticApm.csproj\", \"{AD354CF6-C132-4B5D-944D-0DFE21509781}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Core.Telemetry.ElasticApm.Tests\", \"test\\Liquid.Core.Telemetry.ElasticApm.Tests\\Liquid.Core.Telemetry.ElasticApm.Tests.csproj\", \"{8863A92B-E1A3-4203-8C08-C017E5B3D2CC}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.Memory\", \"src\\Liquid.Cache.Memory\\Liquid.Cache.Memory.csproj\", \"{C7DD9DB1-E287-4886-AA44-159C0AB4F041}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.NCache\", \"src\\Liquid.Cache.NCache\\Liquid.Cache.NCache.csproj\", \"{74D0605F-5466-423D-B5ED-E2C104BB3180}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.Redis\", \"src\\Liquid.Cache.Redis\\Liquid.Cache.Redis.csproj\", \"{6508D946-4B74-4629-B819-4C2C3F7AF8B5}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.SqlServer\", \"src\\Liquid.Cache.SqlServer\\Liquid.Cache.SqlServer.csproj\", \"{F24D06BE-E608-4DFD-B8F6-B02F87062323}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.Memory.Tests\", \"test\\Liquid.Cache.Memory.Tests\\Liquid.Cache.Memory.Tests.csproj\", \"{28747B1E-0784-4B7B-AE48-F5AD3C937262}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.NCache.Tests\", \"test\\Liquid.Cache.NCache.Tests\\Liquid.Cache.NCache.Tests.csproj\", \"{08A826AA-2C2E-4E21-A3D8-60BF8E57772E}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.SqlServer.Tests\", \"test\\Liquid.Cache.SqlServer.Tests\\Liquid.Cache.SqlServer.Tests.csproj\", \"{ED3C04BC-3DEF-4B5C-BF91-EE8F5C38F8E4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Cache.Redis.Tests\", \"test\\Liquid.Cache.Redis.Tests\\Liquid.Cache.Redis.Tests.csproj\", \"{2E8F3332-545A-4454-9F75-1498A9B7B9BF}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"test\", \"test\", \"{BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Repository.Mongo.Tests\", \"test\\Liquid.Repository.Mongo.Tests\\Liquid.Repository.Mongo.Tests.csproj\", \"{400BD703-3E6F-41E6-929B-5FD888EFD00A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Repository.EntityFramework.Tests\", \"test\\Liquid.Repository.EntityFramework.Tests\\Liquid.Repository.EntityFramework.Tests.csproj\", \"{73A5230F-0A90-4D2C-8D5E-D95C40DEF310}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Repository.EntityFramework\", \"src\\Liquid.Repository.EntityFramework\\Liquid.Repository.EntityFramework.csproj\", \"{376DEF77-CBE3-452A-890C-FF2728D90322}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Repository.Mongo\", \"src\\Liquid.Repository.Mongo\\Liquid.Repository.Mongo.csproj\", \"{D7B0D4F0-756B-4038-9DB2-0A1AD65ED72A}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Messaging.ServiceBus.Tests\", \"test\\Liquid.Messaging.ServiceBus.Tests\\Liquid.Messaging.ServiceBus.Tests.csproj\", \"{A61C6606-A884-47BC-BD9D-DD9A3E4BDCDA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Messaging.ServiceBus\", \"src\\Liquid.Messaging.ServiceBus\\Liquid.Messaging.ServiceBus.csproj\", \"{C00DA46C-9614-4C42-AA89-64A3520F4EE7}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Messaging.Kafka\", \"src\\Liquid.Messaging.Kafka\\Liquid.Messaging.Kafka.csproj\", \"{605AB027-CB0A-4B8E-8E20-55258369C497}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Messaging.Kafka.Tests\", \"test\\Liquid.Messaging.Kafka.Tests\\Liquid.Messaging.Kafka.Tests.csproj\", \"{0D7F5E5F-348D-4606-9CE4-F2FB220E12BA}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Messaging.RabbitMq\", \"src\\Liquid.Messaging.RabbitMq\\Liquid.Messaging.RabbitMq.csproj\", \"{6CFF2DEC-50E9-417C-A6E1-A0EFCD1EB94C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Messaging.RabbitMq.Tests\", \"test\\Liquid.Messaging.RabbitMq.Tests\\Liquid.Messaging.RabbitMq.Tests.csproj\", \"{40E39D18-CEDF-4BA1-8D9D-60DECAA30C9C}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.WebApi.Http\", \"src\\Liquid.WebApi.Http\\Liquid.WebApi.Http.csproj\", \"{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.WebApi.Http.Tests\", \"test\\Liquid.WebApi.Http.Tests\\Liquid.WebApi.Http.Tests.csproj\", \"{DED98401-EAED-4BE0-84A9-494D77B0E70D}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Storage.AzureStorage\", \"src\\Liquid.Storage.AzureStorage\\Liquid.Storage.AzureStorage.csproj\", \"{F599C512-7224-4A27-A474-3AA9510D2A14}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Dataverse\", \"src\\Liquid.Dataverse\\Liquid.Dataverse.csproj\", \"{CD31C6F6-F8DD-4B56-B08C-D9E8D5BA3E73}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Dataverse.Tests\", \"test\\Liquid.Dataverse.Tests\\Liquid.Dataverse.Tests.csproj\", \"{5B0DC38B-5BC9-4DAC-8527-8D1C33E97247}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Storage.AzureStorage.Tests\", \"test\\Liquid.Storage.AzureStorage.Tests\\Liquid.Storage.AzureStorage.Tests.csproj\", \"{53341B04-6D30-4137-943B-20D8706351E8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.GenAi.OpenAi\", \"src\\Liquid.GenAi.OpenAi\\Liquid.GenAi.OpenAi.csproj\", \"{CB199ED6-3D1D-4E12-A15F-597B6A0BA564}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Repository.OData\", \"src\\Liquid.Repository.OData\\Liquid.Repository.OData.csproj\", \"{60AE2AF5-D84C-4A8B-AA36-FD58A6A423D7}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Liquid.Repository.OData.Tests\", \"test\\Liquid.Repository.OData.Tests\\Liquid.Repository.OData.Tests.csproj\", \"{70A43D24-4905-4A16-8CE2-165F73243B8D}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Liquid.GenAi.OpenAi.Tests\", \"test\\Liquid.GenAi.OpenAi.Tests\\Liquid.GenAi.OpenAi.Tests.csproj\", \"{ECDF1DD3-073D-4708-A20B-1F0F2D663065}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C33A89FC-4F4D-4274-8D0F-29456BA8F76B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C33A89FC-4F4D-4274-8D0F-29456BA8F76B}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C33A89FC-4F4D-4274-8D0F-29456BA8F76B}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C33A89FC-4F4D-4274-8D0F-29456BA8F76B}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{69B34B22-198D-4BD0-AAFC-39A90F9ADAC2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{69B34B22-198D-4BD0-AAFC-39A90F9ADAC2}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{69B34B22-198D-4BD0-AAFC-39A90F9ADAC2}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{69B34B22-198D-4BD0-AAFC-39A90F9ADAC2}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{AD354CF6-C132-4B5D-944D-0DFE21509781}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{AD354CF6-C132-4B5D-944D-0DFE21509781}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{AD354CF6-C132-4B5D-944D-0DFE21509781}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{AD354CF6-C132-4B5D-944D-0DFE21509781}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{8863A92B-E1A3-4203-8C08-C017E5B3D2CC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{8863A92B-E1A3-4203-8C08-C017E5B3D2CC}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{8863A92B-E1A3-4203-8C08-C017E5B3D2CC}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{8863A92B-E1A3-4203-8C08-C017E5B3D2CC}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C7DD9DB1-E287-4886-AA44-159C0AB4F041}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C7DD9DB1-E287-4886-AA44-159C0AB4F041}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C7DD9DB1-E287-4886-AA44-159C0AB4F041}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C7DD9DB1-E287-4886-AA44-159C0AB4F041}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{74D0605F-5466-423D-B5ED-E2C104BB3180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{74D0605F-5466-423D-B5ED-E2C104BB3180}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{74D0605F-5466-423D-B5ED-E2C104BB3180}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{74D0605F-5466-423D-B5ED-E2C104BB3180}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6508D946-4B74-4629-B819-4C2C3F7AF8B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6508D946-4B74-4629-B819-4C2C3F7AF8B5}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6508D946-4B74-4629-B819-4C2C3F7AF8B5}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6508D946-4B74-4629-B819-4C2C3F7AF8B5}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F24D06BE-E608-4DFD-B8F6-B02F87062323}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F24D06BE-E608-4DFD-B8F6-B02F87062323}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F24D06BE-E608-4DFD-B8F6-B02F87062323}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F24D06BE-E608-4DFD-B8F6-B02F87062323}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{28747B1E-0784-4B7B-AE48-F5AD3C937262}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{28747B1E-0784-4B7B-AE48-F5AD3C937262}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{28747B1E-0784-4B7B-AE48-F5AD3C937262}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{28747B1E-0784-4B7B-AE48-F5AD3C937262}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{08A826AA-2C2E-4E21-A3D8-60BF8E57772E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{08A826AA-2C2E-4E21-A3D8-60BF8E57772E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{08A826AA-2C2E-4E21-A3D8-60BF8E57772E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{08A826AA-2C2E-4E21-A3D8-60BF8E57772E}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ED3C04BC-3DEF-4B5C-BF91-EE8F5C38F8E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ED3C04BC-3DEF-4B5C-BF91-EE8F5C38F8E4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ED3C04BC-3DEF-4B5C-BF91-EE8F5C38F8E4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ED3C04BC-3DEF-4B5C-BF91-EE8F5C38F8E4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{2E8F3332-545A-4454-9F75-1498A9B7B9BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{2E8F3332-545A-4454-9F75-1498A9B7B9BF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{2E8F3332-545A-4454-9F75-1498A9B7B9BF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{2E8F3332-545A-4454-9F75-1498A9B7B9BF}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{400BD703-3E6F-41E6-929B-5FD888EFD00A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{400BD703-3E6F-41E6-929B-5FD888EFD00A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{400BD703-3E6F-41E6-929B-5FD888EFD00A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{400BD703-3E6F-41E6-929B-5FD888EFD00A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{73A5230F-0A90-4D2C-8D5E-D95C40DEF310}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{73A5230F-0A90-4D2C-8D5E-D95C40DEF310}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{73A5230F-0A90-4D2C-8D5E-D95C40DEF310}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{73A5230F-0A90-4D2C-8D5E-D95C40DEF310}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{376DEF77-CBE3-452A-890C-FF2728D90322}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{376DEF77-CBE3-452A-890C-FF2728D90322}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{376DEF77-CBE3-452A-890C-FF2728D90322}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{376DEF77-CBE3-452A-890C-FF2728D90322}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D7B0D4F0-756B-4038-9DB2-0A1AD65ED72A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D7B0D4F0-756B-4038-9DB2-0A1AD65ED72A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D7B0D4F0-756B-4038-9DB2-0A1AD65ED72A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D7B0D4F0-756B-4038-9DB2-0A1AD65ED72A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{A61C6606-A884-47BC-BD9D-DD9A3E4BDCDA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{A61C6606-A884-47BC-BD9D-DD9A3E4BDCDA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{A61C6606-A884-47BC-BD9D-DD9A3E4BDCDA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{A61C6606-A884-47BC-BD9D-DD9A3E4BDCDA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C00DA46C-9614-4C42-AA89-64A3520F4EE7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C00DA46C-9614-4C42-AA89-64A3520F4EE7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C00DA46C-9614-4C42-AA89-64A3520F4EE7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C00DA46C-9614-4C42-AA89-64A3520F4EE7}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{605AB027-CB0A-4B8E-8E20-55258369C497}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{605AB027-CB0A-4B8E-8E20-55258369C497}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{605AB027-CB0A-4B8E-8E20-55258369C497}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{605AB027-CB0A-4B8E-8E20-55258369C497}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{0D7F5E5F-348D-4606-9CE4-F2FB220E12BA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{0D7F5E5F-348D-4606-9CE4-F2FB220E12BA}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{0D7F5E5F-348D-4606-9CE4-F2FB220E12BA}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{0D7F5E5F-348D-4606-9CE4-F2FB220E12BA}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{6CFF2DEC-50E9-417C-A6E1-A0EFCD1EB94C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{6CFF2DEC-50E9-417C-A6E1-A0EFCD1EB94C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{6CFF2DEC-50E9-417C-A6E1-A0EFCD1EB94C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{6CFF2DEC-50E9-417C-A6E1-A0EFCD1EB94C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{40E39D18-CEDF-4BA1-8D9D-60DECAA30C9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{40E39D18-CEDF-4BA1-8D9D-60DECAA30C9C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{40E39D18-CEDF-4BA1-8D9D-60DECAA30C9C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{40E39D18-CEDF-4BA1-8D9D-60DECAA30C9C}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{DED98401-EAED-4BE0-84A9-494D77B0E70D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{DED98401-EAED-4BE0-84A9-494D77B0E70D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{DED98401-EAED-4BE0-84A9-494D77B0E70D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{DED98401-EAED-4BE0-84A9-494D77B0E70D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{F599C512-7224-4A27-A474-3AA9510D2A14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{F599C512-7224-4A27-A474-3AA9510D2A14}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{F599C512-7224-4A27-A474-3AA9510D2A14}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{F599C512-7224-4A27-A474-3AA9510D2A14}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CD31C6F6-F8DD-4B56-B08C-D9E8D5BA3E73}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CD31C6F6-F8DD-4B56-B08C-D9E8D5BA3E73}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CD31C6F6-F8DD-4B56-B08C-D9E8D5BA3E73}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CD31C6F6-F8DD-4B56-B08C-D9E8D5BA3E73}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{5B0DC38B-5BC9-4DAC-8527-8D1C33E97247}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{5B0DC38B-5BC9-4DAC-8527-8D1C33E97247}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{5B0DC38B-5BC9-4DAC-8527-8D1C33E97247}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{5B0DC38B-5BC9-4DAC-8527-8D1C33E97247}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{53341B04-6D30-4137-943B-20D8706351E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{53341B04-6D30-4137-943B-20D8706351E8}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{53341B04-6D30-4137-943B-20D8706351E8}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{53341B04-6D30-4137-943B-20D8706351E8}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{CB199ED6-3D1D-4E12-A15F-597B6A0BA564}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{CB199ED6-3D1D-4E12-A15F-597B6A0BA564}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{CB199ED6-3D1D-4E12-A15F-597B6A0BA564}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{CB199ED6-3D1D-4E12-A15F-597B6A0BA564}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{60AE2AF5-D84C-4A8B-AA36-FD58A6A423D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{60AE2AF5-D84C-4A8B-AA36-FD58A6A423D7}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{60AE2AF5-D84C-4A8B-AA36-FD58A6A423D7}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{60AE2AF5-D84C-4A8B-AA36-FD58A6A423D7}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{70A43D24-4905-4A16-8CE2-165F73243B8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{70A43D24-4905-4A16-8CE2-165F73243B8D}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{70A43D24-4905-4A16-8CE2-165F73243B8D}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{70A43D24-4905-4A16-8CE2-165F73243B8D}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{ECDF1DD3-073D-4708-A20B-1F0F2D663065}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{ECDF1DD3-073D-4708-A20B-1F0F2D663065}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{ECDF1DD3-073D-4708-A20B-1F0F2D663065}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{ECDF1DD3-073D-4708-A20B-1F0F2D663065}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{69B34B22-198D-4BD0-AAFC-39A90F9ADAC2} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{8863A92B-E1A3-4203-8C08-C017E5B3D2CC} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{28747B1E-0784-4B7B-AE48-F5AD3C937262} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{08A826AA-2C2E-4E21-A3D8-60BF8E57772E} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{ED3C04BC-3DEF-4B5C-BF91-EE8F5C38F8E4} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{2E8F3332-545A-4454-9F75-1498A9B7B9BF} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{400BD703-3E6F-41E6-929B-5FD888EFD00A} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{73A5230F-0A90-4D2C-8D5E-D95C40DEF310} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{A61C6606-A884-47BC-BD9D-DD9A3E4BDCDA} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{0D7F5E5F-348D-4606-9CE4-F2FB220E12BA} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{40E39D18-CEDF-4BA1-8D9D-60DECAA30C9C} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{DED98401-EAED-4BE0-84A9-494D77B0E70D} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{5B0DC38B-5BC9-4DAC-8527-8D1C33E97247} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{53341B04-6D30-4137-943B-20D8706351E8} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{70A43D24-4905-4A16-8CE2-165F73243B8D} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\t\t{ECDF1DD3-073D-4708-A20B-1F0F2D663065} = {BDB77DF2-2D7D-4363-BB2B-D6A3A8A69C7B}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {1D003939-9797-4F37-B391-10047A780641}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "Liquid.WebApi.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.0.31612.314\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.WebApi.Http\", \"src\\Liquid.WebApi.Http\\Liquid.WebApi.Http.csproj\", \"{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}\"\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"workflows\", \"workflows\", \"{7B0BC311-679F-4D1F-BE49-DF3E49863792}\"\n\tProjectSection(SolutionItems) = preProject\n\t\t.github\\workflows\\liquid-ci-cd-http-extensions-crud.yml = .github\\workflows\\liquid-ci-cd-http-extensions-crud.yml\n\t\t.github\\workflows\\liquid-ci-cd-http.yml = .github\\workflows\\liquid-ci-cd-http.yml\n\tEndProjectSection\nEndProject\nProject(\"{2150E333-8FDC-42A3-9474-1A3956D46DE8}\") = \"Http\", \"Http\", \"{13C213E0-722A-4CD5-9209-21E12FDA0CA8}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.WebApi.Http.Tests\", \"test\\Liquid.WebApi.Http.Tests\\Liquid.WebApi.Http.Tests.csproj\", \"{39DDC514-44CD-43BE-9E5B-C3B86665895E}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{39DDC514-44CD-43BE-9E5B-C3B86665895E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{39DDC514-44CD-43BE-9E5B-C3B86665895E}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{39DDC514-44CD-43BE-9E5B-C3B86665895E}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{39DDC514-44CD-43BE-9E5B-C3B86665895E}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(NestedProjects) = preSolution\n\t\t{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4} = {13C213E0-722A-4CD5-9209-21E12FDA0CA8}\n\t\t{39DDC514-44CD-43BE-9E5B-C3B86665895E} = {13C213E0-722A-4CD5-9209-21E12FDA0CA8}\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {83C46B4F-18D0-45CB-B7EC-9A5B8840F6A0}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "README.md",
    "content": "# Liquid Application Framework\n\n![GitHub issues](https://img.shields.io/github/issues/Avanade/Liquid-Application-Framework)\n![GitHub](https://img.shields.io/github/license/Avanade/Liquid-Application-Framework)\n![GitHub Repo stars](https://img.shields.io/github/stars/Avanade/Liquid-Application-Framework?style=social)\n[![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-2.1-4baaaa.svg)](https://avanade.github.io/code-of-conduct/)\n[![Ready Ava Maturity](https://img.shields.io/badge/Ready-Ava--Maturity-%23FF5800?labelColor=green)](https://avanade.github.io/maturity-model/)\n\nThis repository contains Liquid Application Framework full code, samples, templates and [documentation](docs/About-Liquid.md).\n\n## What is Liquid?\n\nLiquid is a **multi-cloud** framework designed to **accelerate the development** of cloud-native microservices while avoiding coupling your code to specific cloud providers.\n\nWhen writing Liquid applications, you stop worrying about the technology and focus on your business logic - Liquid abstracts most of the boilerplate and let you just write domain code that looks great and gets the job done.\n\n## Feature\n\n- Abstracts a number of services from cloud providers such as Azure, AWS and Google Cloud to enable you to write code that could run anywhere.\n- Brings a directed programming model that will save you time on thinking how to structure your application, allowing you to focus on writing business code.\n\n| Liquid Application Framework Binaries | Version |\n| :-- | :--: |\n| [`Liquid.Core`](https://www.nuget.org/packages/Liquid.Core) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Core) |\n| [`Liquid.Repository.Mongo`](https://www.nuget.org/packages/Liquid.Repository.Mongo) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Repository.Mongo) |\n| [`Liquid.Repository.EntityFramework`](https://www.nuget.org/packages/Liquid.Repository.EntityFramework) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Repository.EntityFramework) |\n| [`Liquid.Repository.OData`](https://www.nuget.org/packages/Liquid.Repository.OData) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Repository.OData) |\n| [`Liquid.Cache.Memory`](https://www.nuget.org/packages/Liquid.Cache.Memory) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Cache.Memory) |\n| [`Liquid.Cache.NCache`](https://www.nuget.org/packages/Liquid.Cache.NCache) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Cache.NCache) |\n| [`Liquid.Cache.Redis`](https://www.nuget.org/packages/Liquid.Cache.Redis) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Cache.Redis) |\n| [`Liquid.Cache.SqlServer`](https://www.nuget.org/packages/Liquid.Cache.SqlServer) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Cache.SqlServer) |\n| [`Liquid.Messaging.Kafka`](https://www.nuget.org/packages/Liquid.Messaging.Kafka) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Messaging.Kafka) |\n| [`Liquid.Messaging.RabbitMq`](https://www.nuget.org/packages/Liquid.Messaging.RabbitMq) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Messaging.RabbitMq) |\n| [`Liquid.Messaging.ServiceBus`](https://www.nuget.org/packages/Liquid.Messaging.ServiceBus) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Messaging.ServiceBus) |\n| [`Liquid.WebApi.Http`](https://www.nuget.org/packages/Liquid.WebApi.Http) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.WebApi.Http) |\n| [`Liquid.Dataverse`](https://www.nuget.org/packages/Liquid.Dataverse) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Dataverse) |\n| [`Liquid.Storage.AzureStorage`](https://www.nuget.org/packages/Liquid.Storage.AzureStorage) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.Storage.AzureStorage) |\n| [`Liquid.GenAi.OpenAi`](https://www.nuget.org/packages/Liquid.GenAi.OpenAi) | ![Nuget (with prereleases)](https://img.shields.io/nuget/vpre/Liquid.GenAi.OpenAi) |\n\n\n## Getting Started\n\nYou can use Liquid Templates to get your microservice started.\n\nInstall the templates by running the following dotnet CLI command at the PowerShell prompt :\n\n```Shell\ndotnet new install Liquid.Templates\n```\nand run dotnet new command with the name and parameters of the following templates:\n|Name|Description|\n| :-- | :-- |\n|`liquidcrudsolution`       |Liquid WebAPI CRUD Solution (Domain and WebAPI projects)              |\n|`liquidcrudaddentity`      |Liquid entity class, CRUD mediator handlers and CRUD controller       |\n|`liquiddomainaddhandler`   |Liquid mediator command handler                                       |\n|`liquiddomainproject`      |Liquid Domain project (mediator command handler)                      |\n|`liquidwebapisolution`     |Liquid WebAPI solution (Domain and WebAPI projects)                   |\n|`liquidwebapiaddentity`    |Liquid entity class, mediator command handler and CRUD controller     |\n|`liquidwebapiproject`      |Liquid WebAPI project                                                 |\n|`liquidworkersolution`     |Liquid WorkerService solution (Domain and WorkerService projects)     |\n|`liquidworkerproject`      |Liquid WorkerService project                                          |\n|`liquidbcontextaddentity`  |Liquid DbContext entity configuration class (for Entity Framework)    |\n|`liquiddbcontextproject`   |Liquid Repository project (EntityFramework DbContext configurations)  |\n\n\n### Sample:\nTo create an WebAPI solution with CRUD handlers, you must:\n- execute command :\n```Shell\ndotnet new liquidcrudsolution --projectName \"some root namespace\" --entityName \"some entity\" --entityIdType \"type of your unique ID\"\n```\n\n- open the folder where the command was executed, and open the project created in the IDE of your choice:\n\n![template_sample](https://user-images.githubusercontent.com/30960065/153954780-0ec8a6c0-153e-4bbc-8f3a-4ccc9c1e7858.png)\n\n- follow the instructions found in the generated code TODOs, and run!\n\n> You can make changes in code, add more classes and project if you need, and also using others Liquid templates to do it!\n\n\n## Contribute\n\nSome of the best ways to contribute are to try things out, file issues, and make pull-requests.\n\n- You can provide feedback by filing issues on GitHub or open a discussion in [Discussions tab](https://github.com/Avanade/Liquid-Application-Framework/discussions). We accept issues, ideas and questions.\n- You can contribute by creating pull requests for the issues that are listed. Look for issues marked as _ready_ if you are new to the project.\n- Avanade asks that all commits sign the [Developer Certificate of Origin](https://developercertificate.org/).\n\nIn any case, be sure to take a look at [the contributing guide](CONTRIBUTING.md) before starting, and see our [security disclosure](https://github.com/Avanade/avanade-template/blob/main/SECURITY.md) policy.\n\n## Who is Avanade?\n\n[Avanade](https://www.avanade.com) is the leading provider of innovative digital, cloud and advisory services, industry solutions and design-led experiences across the Microsoft ecosystem.\n"
  },
  {
    "path": "docs/About-Lightweight-Architectures.md",
    "content": "| [Main](About-Liquid.md) > About Lightweight Architectures |\n|----|\n\nSuccessful modern digital solutions, like startups, while starts small and agile, had to cope with accelerated growth, reaching hundreds of millions of concurrent users while still being able to compete and evolve rapidly.\n\nHence, those companies (startups) have set the bar (of technology competence) to a much higher level than traditional enterprises were used to.\n\nNow, a new set of styles, patterns and practices rules the modern application life-cycle, targeting enterprises that are in their way to digital transformation (and competition).\n\nSuch type of enterprise architecture is being so called lightweight, in the sense that it resembles the lightness of **\"born-digital\"** solutions when compared to what has been done in large traditional companies.\n\n## Learn from some thought leaders \n- ### [Microservice Architectural Style by **Martin Fowler, _et al._**](https://www.martinfowler.com/articles/microservices.html)\n\n- ### [Cloud Design Patterns by **Microsoft**](https://docs.microsoft.com/en-us/azure/architecture/patterns/)\n\n- ### [The Twelve-Factor App by **Adam Wiggins**](https://12factor.net/)\n"
  },
  {
    "path": "docs/About-Liquid-Applications.md",
    "content": "| [Main](About-Liquid.md) > About Liquid Applications |\n|----|\n\nAccenture uses the term [Liquid Applications](https://www.accenture.com/us-en/capability-rapid-application-development-studio) to emphasize the ever-changing aspect of a given solution, meant do deal with unpredictable yet presumable external pressure from users, clients, competitors and regulators.\n\nThus, for \"liquid application\", we should think about a custom business solution build on top of a [lightweight architecture](About-Lightweight-Architectures.md) and able to coexist and evolve in the digital environment.\n\nSuch kind of application should be developed using a cloud-first, mobile-first and API-first approach, using Agile & DevOps practices and tools.\n\nLiquid have many [resources to ease the development and operation of such applications](Using-Liquid-for-building-your-application.md).\n"
  },
  {
    "path": "docs/About-Liquid.md",
    "content": "The **Liquid Application Framework** is a set of pre-integrated, ready-to-use binding code that supports the creation of [liquid applications](About-Liquid-Applications.md).\n\nIt is based on reference [lightweight architectures](About-Lightweight-Architectures.md), cloud design patterns and [modern software engineering](https://www.avanade.com/en/technologies/modern-software-engineering) techniques.\n\nFor building business software, Liquid can be thought of as a set of pre-built parts that drives a faster, safer, cheaper development work, while delivering high quality products.\n\n#Liquid boosts the lifecycle of modern applications. How does it do that?\nThe framework increases the development productivity and quality, while eases operation, of business applications by reducing their complexity through use of pre-built and pre-integrated technical components.\n\nIt also adds architectural uniformity and governance by making it possible for software engineers to focus on business domain logic, leaving the technical issues with to the framework.\n\nLast, but not least, Liquid allows for easy and centralized replacement and/or extension of platform components (_e.g._ database server) so applications built on top of it are tech-agnostic, _i.e._ minimizes vendor/platform lock-in.\n\n# See more\n1. [**Introduction**](Introduction.md) \n1. [**Key concepts**](Key-Concepts.md)\n1. [**Using Liquid to build your application**](Using-Liquid-for-building-your-application.md)\n1. [**Sample application: xxx** ](Sample-application-xxx.md)\n\n# Contribute\nSome of the best ways to contribute are to try things out, file issues, and make pull-requests.\n\n- You can provide feedback by filing issues on GitHub. We accept issues, ideas and questions. \n- You can contribute by creating pull requests for the issues that are listed. Look for issues marked as _good first issue_ if you are new to the project.\n\nIn any case, be sure to take a look at [the contributing guide](https://github.com/Avanade/Liquid-Application-Framework/CONTRIBUTING.md) before starting.\n"
  },
  {
    "path": "docs/Business-logic-seggregation.md",
    "content": "| [Main](About-Liquid.md) > [Key Concepts](Key-Concepts.md) > Business Logic Separation |\n|----|\n\nFor the sake of productivity, is better to have source code clear and legible, as much as possible.\n\nHowever, current technology platforms contain many components to be integrated and too many aspects to consider beyond the (business) algorithm in question.\n\nIt is hard to deal with those technology matters in a isolated way, seggregated from the core business logic that is being written.\n\nLiquid seeks to do that, as good as possible, allowing to use only minimum and precise mentions to such technical capabilities in the business code.\n\nTake the following example showing how Liquid hides most of the complexity of connecting to a data repository to find and update some data and, in the same logic, publishing an event in a queue of a message/event bus:\n\nOn Startup.cs:\n```csharp\n...\n    //Injects the Messaging Service\n    services.AddProducersConsumers(typeof(ProductPriceChangedPublisher).Assembly);\n...\n```\nOn ChangeProductPriceCommandHandler.cs:\n```csharp\n    public class ChangeProductPriceCommandHandler : RequestHandlerBase, IRequestHandler<ChangeProductPriceCommand, bool>\n    {\n        private readonly IProductRepository _productRepository;\n        private readonly ILightProducer<ProductPriceChangedMessage> _productPriceChangedPublisher;\n        private readonly IMapper _mapper;\n        private readonly IPostService _postService;\n\n        public ChangeProductPriceCommandHandler(IMediator mediatorService, \n                                                ILightContext contextService, \n                                                ILightTelemetry telemetryService, \n                                                IMapper mapperService,\n                                                IProductRepository productRepository,\n                                                ILightProducer<ProductPriceChangedMessage> productPriceChangedPublisher,\n                                                IPostService postService) : base(mediatorService, contextService, telemetryService, mapperService)\n        {\n        }\n\n\n\n\n        /// <summary>\n        /// Handles the specified request.\n        /// </summary>\n        /// <param name=\"request\">The request.</param>\n        /// <param name=\"cancellationToken\">The cancellation token.</param>\n        /// <returns></returns>\n        public async Task<bool> Handle(ChangeProductPriceCommand request, CancellationToken cancellationToken)\n        {\n            var product = await _productRepository.FindByIdAsync(new ObjectId(request.Id));\n            if (product != null)\n            {\n                product.Price = request.Price;\n                await _productRepository.UpdateAsync(product);\n                var changeProductPriceMessage = _mapper.Map<ProductPriceChangedMessage>(request);\n                await _productPriceChangedPublisher.SendMessageAsync(changeProductPriceMessage);\n                return true;\n            }\n            throw new ProductDoesNotExistException();\n        }\n    }\n```\n\nThe method `public async Task<bool> Handle(...` above is responsible for doing the business logic. It should find Product data in a repository, change its price, persist it back to the repository and publish an event. The classes `_productRepository` and `_productPriceChangedPublisher` hides the technical complexity mentioned before. Besides that, since those classes are injected on this Command Handler, they can be substituted by any other classes implementing the same interfaces (`IProductRepository` and `ILightProducer<ProductPriceChangedMessage>` respectivelly), doing a complete isolation of the business logic and the underlying infrastructure components.\n\nIn this case, Liquid uses a common programming model in DDD hexagonal architectures, where external requests will be translated to Domain Commands or Domain Queries, and those will handle the business logic that responds to those requests. In that way, the requests can came from anywhere and in any format that could be handled outside the Domain. The same for the reponses.\n\nThis strategy is followed for all technology capabilities that Liquid abstracts and pre-integrates. \nFor instance, see bellow, how simple is to create the class to publish that event on a RAbbitMQ:\n```csharp\n    [RabbitMqProducer(\"rabbitMqConnectionString\", \"ProductPriceChanged\")]\n    public class ProductPriceChangedPublisher : RabbitMqProducer<ProductPriceChangedMessage>\n    {\n        /// <summary>\n        /// Gets the rabbit mq settings.\n        /// </summary>\n        /// <value>\n        /// The rabbit mq settings.\n        /// </value>\n        public override RabbitMqSettings RabbitMqSettings => new RabbitMqSettings\n        {\n            Durable = true,\n            Persistent = true,\n            Expiration = \"172800000\"\n        };\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ProductPriceChangedPublisher\"/> class.\n        /// </summary>\n        /// <param name=\"contextFactory\">The context factory.</param>\n        /// <param name=\"telemetryFactory\">The telemetry factory.</param>\n        /// <param name=\"loggerFactory\">The logger factory.</param>\n        /// <param name=\"messagingSettings\">The messaging settings.</param>\n        public ProductPriceChangedPublisher(ILightContextFactory contextFactory, \n                                            ILightTelemetryFactory telemetryFactory, \n                                            ILoggerFactory loggerFactory, \n                                            ILightConfiguration<List<MessagingSettings>> messagingSettings) : base(contextFactory, telemetryFactory, loggerFactory, messagingSettings)\n        {\n        }\n    }\n```\nThe base class `RabbitMqProducer` will handle all the complexities inherent to connect to a RabbitMQ server and publish a message on a queue.\nThat is the beauty of using platform specific \"cartridges\". This way, it should be very easy to develop an application that could run on an on-premises environment using RabbitMQ as the message bus, and, also, the same application could be changed to run on Azure, using Azure ServiceBus as the message bus. In fact, the application could be created to dinamically switch between different platform implementations, in run time.\n\nIn contrast to what Liquid provides, see an example excerpt from the code of [.NET Core reference application](https://github.com/dotnet-architecture/eShopOnContainers/tree/dev/src/Services/Ordering/Ordering.BackgroundTasks):\n\n```\n...\n\nprivate void RegisterEventBus(IServiceCollection services)\n        {\n            var subscriptionClientName = Configuration[\"SubscriptionClientName\"];\n\n            if (Configuration.GetValue<bool>(\"AzureServiceBusEnabled\"))\n            {\n                services.AddSingleton<IEventBus, EventBusServiceBus>(sp =>\n                {\n                    var serviceBusPersisterConnection = sp.GetRequiredService<IServiceBusPersisterConnection>();\n                    var iLifetimeScope = sp.GetRequiredService<ILifetimeScope>();\n                    var logger = sp.GetRequiredService<ILogger<EventBusServiceBus>>();\n                    var eventBusSubcriptionsManager = sp.GetRequiredService<IEventBusSubscriptionsManager>();\n\n                    return new EventBusServiceBus(serviceBusPersisterConnection, logger,\n                        eventBusSubcriptionsManager, subscriptionClientName, iLifetimeScope);\n                });\n            }\n\n            ...\n\n            RegisterEventBus(services);\n\n            //create autofac based service provider\n            var container = new ContainerBuilder();\n            container.Populate(services);\n\n            return new AutofacServiceProvider(container.Build());\n}\n\n...\n\n private void ConfigureEventBus(IApplicationBuilder app)\n\n        {\n            var eventBus = app.ApplicationServices.GetRequiredService<IEventBus>();\n            \n            ...\n\n            eventBus.Subscribe<OrderStatusChangedToShippedIntegrationEvent, OrderStatusChangedToShippedIntegrationEventHandler>();\n        }\n\n...\n\n    public class OrderStatusChangedToShippedIntegrationEventHandler : IIntegrationEventHandler<OrderStatusChangedToShippedIntegrationEvent>\n    {\n        private readonly IHubContext<NotificationsHub> _hubContext;\n\n        public OrderStatusChangedToShippedIntegrationEventHandler(IHubContext<NotificationsHub> hubContext)\n        {\n            _hubContext = hubContext ?? throw new ArgumentNullException(nameof(hubContext));\n        }\n\n        public async Task Handle(OrderStatusChangedToShippedIntegrationEvent @event)\n        {\n        ... \n        }\n\n```\nThere are too many technical (platform specific) lines of code mixed with only a few application (business) ones:  **OrderStatusChangedToShippedIntegrationEvent** and corresponding **Handle()**.\n\nIn this scenario, it is very hard to understand, refactor and evolve this code due to both technical and business demands.\n\nWith Liquid, the business logic will always be inside the domain, seggregated from the underlying technology, making it easier to understand. At same time, the underlying technology specifics will be outside the domain, abstracted in a way that makes possible to use different implementations that will work with the same business logic, while, also, allows to evolve these parts of code separatelly.\n"
  },
  {
    "path": "docs/Introduction.md",
    "content": "| [Main](About-Liquid.md) > Introduction | \n|----|\n\nIn the last years, the always challenging task of developing multi-hundred-line-of-code business applications has reached elevated sophistication and professionalism.\nA high-quality application life-cycle is not only for high-tech companies anymore. To be or to become digital demands distinguished software engineering skills for companies of any industry and any size.\nAvanade has historically helped several companies and professionals achieving proficiency in the development of modern applications during their digital transformation.\nNow Avanade provides Liquid, a framework envisioned to boost such engineering capabilities, available as an Open Source project, for anyone looking for quick, standardized, flexible, extensible and high quality microservices development.\n\n| Topics | \n| :-- | \n| [Technical Context](#Technical-Context) <br> [Avanade as a Thought Leader](#Avanade-as-a-Thought-Leader) <br> [Business Drivers](#Business-Drivers) <br> [Guiding Principles](#Guiding-Principles) | \n\n### Technical Context\n\nThe development of enterprise custom application has passed through several architectural waves in the last couple decades, with each new wave adding some complexity on top of the old ones.\nIn recent years, with the advent of modern architectural standards such as REST APIs, microservices on containers and single page applications as well as DevOps practices, the modern applications do have new strengths that are of great value to businesses and their customers. \nHowever, the complexity of designing, building and running such applications increased a lot, demanding great effort from architects, software and operation engineers to fully implement all the mandatory concepts and capabilities.\nMoreover, such effort is a repeating task while yet an error-prone one. That opens a great space for building a set of pre-built software components following a general-purpose technical design, thereby condensed as a framework for developing and running those so called modern applications.\n\n### Avanade as a Thought Leader\n\nBorn on the union of Microsoft and Accenture, Avanade has quickly become [a major competence center for the Microsoft's ecosystem of technology, services and partners](https://www.avanade.com/en-us/media-center/press-releases/2020-microsoft-global-alliance-si-partner-of-the-year), with a track record of hundreds of enterprise grade, innovative projects delivered.\nMicrosoft, in its transformation into a cloud service company, has made a complete rotation from a proprietary vendor to an open-source friendly company, thus naturally getting more and more influence on the evolution of the industry. \nIn particular, due to its influence in the Single Page Application (SPA) domain [with Angular & Typescript](https://techcrunch.com/2015/03/05/microsoft-and-google-collaborate-on-typescript-hell-has-not-frozen-over-yet/) and microservice architecture with [.NET Core & Docker](https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/) (along with its open cloud offering such [Windows Azure](http://azure.microsoft.com) and VisualStudio.com) Microsoft has helped to pave the way for the building of modern digital applications.\nOn the other hand, Accenture is a top leader in technology consulting field and it continuously infuses Avanade with technical and methodological know-how in enterprise architecture and digital transformation.\nTherefore, Avanade is best positioned to advise methods, patterns and building blocks on top of mature stacks and tools such as Microsoft's as well as to materialize the usual tech-agnostic point of view of Accenture.\n\n### Business Drivers\n\nThe purpose of Liquid is to allow the building of modern applications with better quality in a more efficient way. Therefore, the following business drivers were stated:\n- **Reduce time-to-value with faster development and testing activities:** The learning curve is shorter if developers can abstract technical complexity and have their components easily and automatically put into a DevOps pipeline;\n- **Increase quality with code uniformity:** all application components can be written with the same high-level \"technical\" dialect thus promoting better code analysis, both static and dynamic;\n- **Improve application governance, maintenance and evolution:** a single point of technical decision for the entire code allows better standards implementation, code maintenance as well as easier introduction and/or replacement of technical components;\n- **Catalyze the use of delivery centers:** by getting most of the technical design out of the box, remote teams can focus on requirements (backlog) and on the design of the business solution (business logic on the application layer).\n\n### Guiding Principles\n\nFrom a technical perspective, the Liquid development was stressed toward the following principles:\n- **Prescriptive and non-intrusive programming model for business components:** frameworks and platform services (_e.g._ .NET Core and CosmosDB, respectively) are designed for broad use-case scenarios, very much broader than the vast majority of enterprise digital solutions actually demands. Liquid stands for the later scenarios and this is the high value space that it tries to fulfill. Therefore, Liquid [prescribes a \"light\" way of building business application](Key-Concepts.md/#prescriptive-programming-model) without compromising the capability of developers to use the underlying technology in any other ways, if this is a requirement;\n- **Multi platform based on workbench components replacement:** Liquid puts itself between application (business) components and underlying platform (technical) components to avoid (or, at least, minimize) vendor and/or technology lock-in of the application, during both building and execution time. Hence there ought to be a way of [simply replacing Liquid \"cartridges\"](Platform-Abstraction-Layer.md) of each type (_e.g._ database repository) from one specific technology to another (_e.g._ CosmosDB and DynamoDB) to seamlessly moving application (business) logic from one platform to another. This, obviously, will depend a lot on how the application development team will deal with specific features provided by the underlying technology being used. Most of the time, we only use a small subset of those features, making it very easy to substitute similar technologies. But, even when this is not the case, Liquid helps to isolate those specifics, allowing the creation of portable code with high control, avoiding spreaded infrastructure code that makes maintenance harder;\n- **Built-in lightweight patterns for technology domain:** There are many [design patterns](About-Lightweight-Architectures.md) that must be applied to develop a modern digital application. Many of them can be given to the (upper) application layer as an out-of-the box capability of Liquid;\n- **Abstract technical complexity from business software developer:** The true hard work of enterprise architects is (or should be) the structuring of millions of lines of code a large company has. Legacy code has probably grown over decades in an unsupervised manner. That should not be the case with the brand-new code of modern digital application. While dealing with technology (delta) innovation/rennovation is a task architects deal every new year, dealing with applications' structuring and refactoring is (or should be) their daily job. The same is valid for business software developers. Liquid helps engineers [to focus on their useful (business) code](Business-logic-seggregation.md).\n"
  },
  {
    "path": "docs/Key-Concepts.md",
    "content": "| [Main](About-Liquid) > Key Concepts |\n|----|\n\nA small group of core concepts balances the many aspects dealt by Liquid and determines its general shape and strengths.\n\n\n## Architectural Strategies\n- [**Platform abstraction layer:**](Platform-Abstraction-Layer.md) using the best from PaaS offerings while avoiding lock-in;\n\n- [**Business logic seggregation:**](Business-logic-seggregation.md) avoid mixing domain (business) logic along with underlying platform (technical) logic;\n\n- [**DevOps for microservices:**](DevOps-for-Microservices.md) giving this fine-grained unit of software an easier way of being built, deployed and tested in a continuous fashion.\n\n\n## Prescriptive Programming Model\n- [**APIs as (formal) object models:**](API-as-formal-Object-Model.md) leveraging the abstraction and formality of a well-formed API as a way to avoid code redundancy and error propensity;\n\n- [**Encapsulated domain (business) logic:**](Encapsulated-Domain-Logic.md) putting domain logic in a format (of classes) independent of the protocols used to access it;\n\n- [**Business error handling:**](Business-Error-Handling.md) defining a simple yet comprehensive way of dealing with business logic deviation;\n\n- [**Microservice sizing:**](Microservice-Sizing.md) giving shape to the various parameters of a well-designed microservice.\n"
  },
  {
    "path": "docs/Platform-Abstraction-Layer.md",
    "content": "| [Main](About-Liquid.md) > [Key Concepts](Key-Concepts.md) > Platform Abstraction Layer |\n|----|\n\nThe most fundamental strategy steering Liquid's design is its responsibility to decouple as much as possible the application components from the underlying platforms.\n\n ![PlatformAbstractionLayer.png](PlatformAbstractionLayer.png) \n\nLiquid concentrates most of platform (technology) specific dependencies in one single point of code thus freeing up the many application (business) components to access pre-integrated, high abstraction primitives for doing their jobs.\n\nDoing such technology integration repetitive tasks, while error-prone and risky, can considerably increase costs on software projects. \n\nHence an abstraction layer like Liquid diminishes such costs as much as great is the number of business components written on top of it - without having to deal with those low levels details.\n\nAdditionally (and even more important), now there are only a handful of dependency points on a given set of technology components (_i.e._ on their SDKs and APIs).\n\nFollowing the Liquid guiding principle of [multi-platform components](Introduction.md/#guiding-principles), the pretty easy [replacement of one specific Liquid cartridge by another](Choose-platform-components.md) allows the avoidance of technology lock-in in a controlled and productive way.\n\nSee parts of a sample code that activates RabbitMQ as the message bus for asynchronous communication:\n\nOn Startup.cs:\n```csharp\n    //Injects the Messaging Service\n    services.AddProducersConsumers(typeof(ProductPriceChangedPublisher).Assembly);\n```\n\nOn ProductPriceChangedPublisher.cs:\n```csharp\n    [RabbitMqProducer(\"messageBusConnectionString\", \"ProductPriceChanged\")]\n    public class ProductPriceChangedPublisher : RabbitMqProducer<ProductPriceChangedMessage>\n```\n\nWhile you can easily change this code to use Azure ServiceBus, for sample, this approach makes possible to [use the best of breed from all platforms](Leveling-up-Platform-Providers.md), because you are able to implement specific technical functionalities of each platform on the specific cartridge (RabbitMqProducer in this case). Your point of maintenance in the code for such kind of change will not touch any business logic and will be very easy to do.\nFor use Azure ServiceBus instead of RabbitMQ, the only change would be on ProductPriceChangedPublisher.cs, as follows:\n```csharp\n    [ServiceBusProducer(\"messageBusConnectionString\", \"ProductPriceChanged\")]\n    public class ProductPriceChangedPublisher : ServiceBusProducer<ProductPriceChangedMessage>\n```\n\nActually, the corollary of a given market standard is to be a commodity technology.\n\nAccordingly, Liquid helps to transcend the classical trade-off between being open & commodity or being locked-in & differentiated.\n\nAdding new technology platform capabilities to all business application components can be done, once again, from a centralized point, in a controlled and agile way.\n\n"
  },
  {
    "path": "docs/Using-Liquid-for-building-your-application.md",
    "content": "# WIP - This tutorial is still a Work In Progress and should not be used yet\n - TODO: create the templates\n - TODO: create the documents for each step\n - TODO: confirm this step-by-step strawman\n\n\n| [Main](About-Liquid.md) > Using Liquid for building your application |\n|----|\n\nThe following are the basic instructions on how to build modern [liquid applications](About-Liquid-Applications.md) taking advantage of Liquid's features and [concepts](Key-Concepts.md).\n\n## Prepare your DevOps environment\n1. [Install Liquid project templates for starting](Install-project-templates.md)\n1. [Choose platform components to support your business code](Choose-platform-components.md)\n1. [Setup configurations per environment](Set-up-configurations-per-environment.md)\n1. [Configure CI, CD and CT](Configure-CI-CD-and-CT.md) \n1. [Deploy microservices on containers](Deploy-microservices.md)\n\n## Code your microservices\n6. [Define the APIs (and formats) exposed](Define-the-APIs.md) \n1. [Structure internal (business) logic](Structure-internal-logic.md)\n1. [Validate input parameters and data models](Validate-input-and-data.md)\n1. [Authenticate and authorize the API](Secure-the-APIs.md)\n1. [Persist and query data from repository](Persist-and-query-data.md)\n1. [Make calls to internal classes](Make-internal-calls.md)\n1. [Call other microservices ](Call-other-microservices.md)\n1. [Call third-party APIs](Call-third-party-APIs.md)\n\n# Connect your front-end to your APIs\n14. [Call the back-end](Calling-the-back-end.md)\n1. [Call third-party back-ends](Call-third-party-back-ends.md)\n1. [Add authentication to the front-end](Add-authentication-to-the-front-end.md)\n\n# Develop tests and mocks\n17. [Seed test data](Seeding-test-data.md)\n1. [Test APIs directly](Test-APIs-directly.md)\n1. [Mock authentication](Mock-authentication.md)\n1. [Mock calls to microservices](Mock-calls-to-microservices.md)\n\n# Add advanced behavior \n21. [Gather telemetry from front-ends and back-ends](Gather-telemetry.md)\n1. [Control state of changing data](Control-state-of-changing-data.md)\n1. [Querying and present data with pagination](Querying-data-with-pagination.md)\n1. [Building complex queries](Building-complex-queries.md)\n1. [Deal with multiple cultures](Deal-with-multiple-cultures.md)\n"
  },
  {
    "path": "nuget.config",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<configuration>\n  <packageSources>\n    <add key=\"Nuget.org\" value=\"https://api.nuget.org/v3/index.json\" />\n  </packageSources>\n</configuration>"
  },
  {
    "path": "samples/Liquid.Sample.Dataverse.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.6.34202.202\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Sample.Dataverse.Function\", \"src\\Liquid.Sample.Dataverse.Function\\Liquid.Sample.Dataverse.Function.csproj\", \"{577C7D6D-566D-4EA2-8C32-039C2C4E17DF}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Sample.Dataverse.Domain\", \"src\\Liquid.Sample.Dataverse.Domain\\Liquid.Sample.Dataverse.Domain.csproj\", \"{7C47775D-45C7-463E-84DA-5B5B264D55F0}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{577C7D6D-566D-4EA2-8C32-039C2C4E17DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{577C7D6D-566D-4EA2-8C32-039C2C4E17DF}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{577C7D6D-566D-4EA2-8C32-039C2C4E17DF}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{577C7D6D-566D-4EA2-8C32-039C2C4E17DF}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{7C47775D-45C7-463E-84DA-5B5B264D55F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7C47775D-45C7-463E-84DA-5B5B264D55F0}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7C47775D-45C7-463E-84DA-5B5B264D55F0}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7C47775D-45C7-463E-84DA-5B5B264D55F0}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {FB41E555-2F25-4D02-8513-7EDC443A17D4}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "samples/Liquid.Sample.MessagingConsumer.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.31410.357\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Sample.MessagingConsumer\", \"src\\Liquid.Sample.MessagingConsumer\\Liquid.Sample.MessagingConsumer.csproj\", \"{E4FE9A3E-4610-4EBF-AD0D-71A642B91282}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Sample.Domain\", \"src\\Liquid.Sample.Domain\\Liquid.Sample.Domain.csproj\", \"{54EF1FE4-82A3-4D39-AB35-C589DC73413C}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{E4FE9A3E-4610-4EBF-AD0D-71A642B91282}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{E4FE9A3E-4610-4EBF-AD0D-71A642B91282}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{E4FE9A3E-4610-4EBF-AD0D-71A642B91282}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{E4FE9A3E-4610-4EBF-AD0D-71A642B91282}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{54EF1FE4-82A3-4D39-AB35-C589DC73413C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{54EF1FE4-82A3-4D39-AB35-C589DC73413C}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{54EF1FE4-82A3-4D39-AB35-C589DC73413C}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{54EF1FE4-82A3-4D39-AB35-C589DC73413C}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {FD6C41A9-76DF-4FEE-98D9-154A31618D95}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "samples/Liquid.Sample.WebApi.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.8.34408.163\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"Liquid.Sample.Domain\", \"src\\Liquid.Sample.Domain\\Liquid.Sample.Domain.csproj\", \"{68DCA206-AD43-4D44-AA1B-2F2E52DEE89A}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Liquid.Sample.Api\", \"src\\Liquid.Sample.Api\\Liquid.Sample.Api.csproj\", \"{356B2F4F-0846-42FD-A013-1B68E6C3D484}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{68DCA206-AD43-4D44-AA1B-2F2E52DEE89A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{68DCA206-AD43-4D44-AA1B-2F2E52DEE89A}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{68DCA206-AD43-4D44-AA1B-2F2E52DEE89A}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{68DCA206-AD43-4D44-AA1B-2F2E52DEE89A}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{356B2F4F-0846-42FD-A013-1B68E6C3D484}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{356B2F4F-0846-42FD-A013-1B68E6C3D484}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{356B2F4F-0846-42FD-A013-1B68E6C3D484}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{356B2F4F-0846-42FD-A013-1B68E6C3D484}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {C37CEE66-2BB3-4FF4-970A-2B1518BE93CA}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Api/Controllers/SampleController.cs",
    "content": "using Liquid.Sample.Domain.Entities;\nusing Liquid.Sample.Domain.Handlers;\nusing Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing System.Net;\n\nnamespace Liquid.Sample.Api.Controllers\n{\n    [ApiController]\n    [Route(\"[controller]\")]\n    public class SampleController : LiquidControllerBase\n    {\n        public SampleController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        [HttpGet(\"Sample\")]\n        public async Task<IActionResult> Get([FromQuery] string id) => await ExecuteAsync(new SampleRequest(id), HttpStatusCode.OK);\n\n        [HttpPost]\n        public async Task<IActionResult> Post([FromBody] SampleMessageEntity entity)\n        {\n            await Mediator.Send(new SampleEventRequest(entity));\n\n            return NoContent();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Api/Liquid.Sample.Api.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.WebApi.Http\" Version=\"6.0.1\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"6.6.2\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Liquid.Sample.Domain\\Liquid.Sample.Domain.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Api/Program.cs",
    "content": "using Liquid.Messaging.ServiceBus.Extensions.DependencyInjection;\nusing Liquid.Repository.Mongo.Extensions;\nusing Liquid.Sample.Domain.Entities;\nusing Liquid.Sample.Domain.Handlers;\nusing Liquid.WebApi.Http.Extensions.DependencyInjection;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services to the container.\nbuilder.Services.AddLiquidMongoRepository<SampleEntity, Guid>(\"Liquid:MyMongoDbSettings:Entities\");\n\nbuilder.Services.AddLiquidServiceBusProducer<SampleMessageEntity>(\"Liquid:ServiceBus\", \"liquidoutput\", true);\n\nbuilder.Services.AddLiquidHttp(typeof(SampleRequest).Assembly);\nbuilder.Services.AddControllers();\n// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Api/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft.AspNetCore\": \"Warning\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Api/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    },\n    \"Console\": {\n      \"IncludeScopes\": true\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"Liquid\": {\n    \"swagger\": {\n      \"name\": \"v1\",\n      \"host\": \"\",\n      \"schemes\": [ \"http\", \"https\" ],\n      \"title\": \"Liquidv2.SimpleApi\",\n      \"version\": \"v1\",\n      \"description\": \"Simple WebApi Sample.\",\n      \"SwaggerEndpoint\": {\n        \"url\": \"/swagger/v1/swagger.json\",\n        \"name\": \"SimpleWebApiSample\"\n      }\n    },\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"MyMongoDbSettings\": {\n      \"DefaultDatabaseSettings\": {\n        \"connectionString\": \"\",\n        \"databaseName\": \"MySampleDb\"\n      },\n      \"Entities\": {\n        \"SampleEntity\": {\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      }\n    },\n    \"ServiceBus\": {\n      \"Settings\": [\n        {\n          \"ConnectionString\": \"\",\n          \"EntityPath\": \"liquidoutput\"\n        },\n        {\n          \"ConnectionString\": \"\",\n          \"EntityPath\": \"liquidinput\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Domain/Liquid.Sample.Dataverse.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Adapter.Dataverse\" Version=\"6.0.0\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Domain/PostSampleService.cs",
    "content": "﻿using Liquid.Adapter.Dataverse;\nusing Liquid.Adapter.Dataverse.Extensions;\nusing Microsoft.Xrm.Sdk;\n\nnamespace Liquid.Sample.Dataverse.Domain\n{\n    public class PostSampleService\n    {\n        private readonly ILiquidDataverseAdapter _adapter;\n\n        private readonly ILiquidMapper<string,Entity> _mapper;\n\n        public PostSampleService(ILiquidDataverseAdapter adapter, ILiquidMapper<string, Entity> mapper)\n        {\n            _adapter = adapter ?? throw new ArgumentNullException(nameof(adapter));\n            _mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));\n        }\n\n        public async Task<string> PostSample(string body)\n        {\n            var bodyEntity = await _mapper.Map(body, \"sample\");\n\n            var result = await _adapter.Create(bodyEntity);\n\n            bodyEntity.Id = result;\n\n            var response = bodyEntity.ToJsonString();\n\n            return response;\n        }\n    }\n}"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/.gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# Azure Functions localsettings file\n#local.settings.json\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n#*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/DataverseIntegration.cs",
    "content": "using System;\nusing System.IO;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Mvc;\nusing Microsoft.Azure.WebJobs;\nusing Microsoft.Azure.WebJobs.Extensions.Http;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Newtonsoft.Json;\nusing Liquid.Sample.Dataverse.Domain;\n\nnamespace Liquid.Sample.Dataverse.Function\n{\n    public class DataverseIntegration\n    {\n        private readonly PostSampleService _service;\n\n        public DataverseIntegration(PostSampleService service)\n        {\n            _service = service ?? throw new ArgumentNullException(nameof(service));\n        }\n\n        [FunctionName(\"PostSample\")]\n        public async Task<IActionResult> Run(\n            [HttpTrigger(AuthorizationLevel.Function, \"post\", Route = null)] HttpRequest req,\n            ILogger log)\n        {\n            log.LogInformation(\"C# HTTP trigger function processed a request.\");\n\n            string requestBody = await new StreamReader(req.Body).ReadToEndAsync();\n\n            dynamic data = JsonConvert.DeserializeObject(requestBody);\n\n            string responseMessage = await _service.PostSample(data);\n\n            return new OkObjectResult(responseMessage);\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/Liquid.Sample.Dataverse.Function.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <AzureFunctionsVersion>v4</AzureFunctionsVersion>\n  </PropertyGroup>\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Azure.Functions.Extensions\" Version=\"1.1.0\" />\n    <PackageReference Include=\"Microsoft.NET.Sdk.Functions\" Version=\"4.2.0\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Liquid.Sample.Dataverse.Domain\\Liquid.Sample.Dataverse.Domain.csproj\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Update=\"host.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n    </None>\n    <None Update=\"local.settings.json\">\n      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>\n      <CopyToPublishDirectory>Never</CopyToPublishDirectory>\n    </None>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/Properties/serviceDependencies.json",
    "content": "{\n  \"dependencies\": {\n    \"appInsights1\": {\n      \"type\": \"appInsights\"\n    },\n    \"storage1\": {\n      \"type\": \"storage\",\n      \"connectionId\": \"AzureWebJobsStorage\"\n    }\n  }\n}"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/Properties/serviceDependencies.local.json",
    "content": "{\n  \"dependencies\": {\n    \"appInsights1\": {\n      \"type\": \"appInsights.sdk\"\n    },\n    \"storage1\": {\n      \"type\": \"storage.emulator\",\n      \"connectionId\": \"AzureWebJobsStorage\"\n    }\n  }\n}"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/Startup.cs",
    "content": "﻿using Liquid.Adapter.Dataverse.Extensions.DependencyInjection;\nusing Liquid.Sample.Dataverse.Function;\nusing Microsoft.Azure.Functions.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Configuration;\nusing System.IO;\n\n[assembly: FunctionsStartup(typeof(Startup))]\n\nnamespace Liquid.Sample.Dataverse.Function\n{\n    public class Startup : FunctionsStartup\n    {\n        public override void Configure(IFunctionsHostBuilder builder)\n        {\n            builder.Services.AddLiquidDataverseAdapter(\"DataverseClient\");\n        }\n\n        public override void ConfigureAppConfiguration(IFunctionsConfigurationBuilder builder)\n        {\n            FunctionsHostBuilderContext context = builder.GetContext();\n\n            builder.ConfigurationBuilder\n                .AddJsonFile(Path.Combine(context.ApplicationRootPath, $\"local.setttings.json\"), optional: true, reloadOnChange: true)\n                .AddEnvironmentVariables();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/host.json",
    "content": "{\n    \"version\": \"2.0\",\n    \"logging\": {\n        \"applicationInsights\": {\n            \"samplingSettings\": {\n                \"isEnabled\": true,\n                \"excludedTypes\": \"Request\"\n            },\n            \"enableLiveMetricsFilters\": true\n        }\n    }\n}"
  },
  {
    "path": "samples/src/Liquid.Sample.Dataverse.Function/local.settings.json",
    "content": "{\n  \"IsEncrypted\": false,\n  \"Values\": {\n    \"AzureWebJobsStorage\": \"UseDevelopmentStorage=true\",\n    \"FUNCTIONS_WORKER_RUNTIME\": \"dotnet\",\n    \"DataverseClient:ClientId\": \"\",\n    \"DataverseClient:ClientSecret\": \"\",\n    \"DataverseClient:url\": \"\"\n  }\n}"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Entities/SampleEntity.cs",
    "content": "﻿using Liquid.Repository;\nusing System;\n\nnamespace Liquid.Sample.Domain.Entities\n{\n    public class SampleEntity : LiquidEntity<Guid>\n    {\n        public string MyProperty { get; set; }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Entities/SampleMessageEntity.cs",
    "content": "﻿using Liquid.Repository;\nusing System;\n\nnamespace Liquid.Sample.Domain.Entities\n{\n    [Serializable]\n    public class SampleMessageEntity\n    {\n        public string Id { get; set; }\n        public string MyProperty { get; set; }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SampleGet/SampleCommandHandler.cs",
    "content": "﻿using Liquid.Repository;\nusing Liquid.Sample.Domain.Entities;\nusing MediatR;\nusing System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleCommandHandler : IRequestHandler<SampleRequest, SampleResponse>\n    {\n        private ILiquidRepository<SampleEntity, Guid> _repository;\n        public SampleCommandHandler(ILiquidRepository<SampleEntity, Guid> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>\n        public async Task<SampleResponse> Handle(SampleRequest request, CancellationToken cancellationToken)\n        {\n            var item = await _repository.FindByIdAsync(Guid.Parse(request.Id));\n\n            var result = new SampleResponse(item);\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SampleGet/SampleRequest.cs",
    "content": "﻿using MediatR;\nusing System;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleRequest : IRequest<SampleResponse>\n    {\n        public string Id { get; set; }\n\n        public SampleRequest(string id)\n        {\n            Id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SampleGet/SampleRequestValidator.cs",
    "content": "﻿using FluentValidation;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleRequestValidator : AbstractValidator<SampleRequest>\n    {\n        public SampleRequestValidator()\n        {\n            RuleFor(request => request.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SampleGet/SampleResponse.cs",
    "content": "﻿using Liquid.Sample.Domain.Entities;\nusing System.Collections.Generic;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleResponse\n    {\n        public SampleEntity Response { get; set; }\n\n\n        public SampleResponse(SampleEntity response)\n        {\n            Response = response;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SamplePost/SampleEventCommandHandler.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging;\nusing Liquid.Messaging.Interfaces;\nusing Liquid.Repository;\nusing Liquid.Sample.Domain.Entities;\nusing MediatR;\nusing System;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleEventCommandHandler : IRequestHandler<SampleEventRequest>\n    {\n        private ILiquidProducer<SampleMessageEntity> _producer;\n        private readonly ILiquidRepository<SampleEntity, Guid> _repository;\n        private readonly ILiquidContext _context;\n\n        public SampleEventCommandHandler(ILiquidProducer<SampleMessageEntity> producer, ILiquidContext context, ILiquidRepository<SampleEntity, Guid> repository)\n        {\n            _producer = producer;\n            _context = context;\n            _repository = repository;\n        }\n\n        public async Task Handle(SampleEventRequest request, CancellationToken cancellationToken)\n        {\n            await _repository.AddAsync(new SampleEntity()\n            {\n                Id = Guid.Parse(request.Entity.Id),\n                MyProperty = request.Entity.MyProperty\n            });\n\n            await _producer.SendMessageAsync(request.Entity, _context.current);\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SamplePost/SampleEventRequest.cs",
    "content": "﻿using Liquid.Sample.Domain.Entities;\nusing MediatR;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleEventRequest : IRequest\n    {\n        public SampleMessageEntity Entity { get; set; }\n\n        public SampleEventRequest(SampleMessageEntity entity)\n        {\n            Entity = entity;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SamplePost/SampleEventRequestValidator.cs",
    "content": "﻿using FluentValidation;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Sample.Domain.Handlers\n{\n    public class SampleEventRequestValidator : AbstractValidator<SampleEventRequest>\n    {\n        public SampleEventRequestValidator()\n        {\n            RuleFor(request => request.Entity.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SamplePut/PutCommandHandler.cs",
    "content": "﻿using Liquid.Repository;\nusing Liquid.Sample.Domain.Entities;\nusing MediatR;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Sample.Domain.Handlers.SamplePut\n{\n    public class PutCommandHandler : IRequestHandler<PutCommandRequest>\n    {\n        private readonly ILiquidRepository<SampleEntity, Guid> _repository;\n\n        public PutCommandHandler(ILiquidRepository<SampleEntity, Guid> repository)\n        {\n            _repository = repository;\n        }\n\n        public async Task Handle(PutCommandRequest request, CancellationToken cancellationToken)\n        {\n            await _repository.UpdateAsync(new SampleEntity()\n            {\n                Id = Guid.Parse(request.Message.Id),\n                MyProperty = request.Message.MyProperty\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SamplePut/PutCommandRequest.cs",
    "content": "﻿using Liquid.Sample.Domain.Entities;\nusing MediatR;\n\nnamespace Liquid.Sample.Domain.Handlers.SamplePut\n{\n    public class PutCommandRequest : IRequest\n    {\n        public SampleMessageEntity Message { get; set; }\n\n        public PutCommandRequest(SampleMessageEntity message)\n        {\n            Message = message;\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Handlers/SamplePut/PutCommandRequestValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace Liquid.Sample.Domain.Handlers.SamplePut\n{\n    public class PutCommandRequestValidator : AbstractValidator<PutCommandRequest>\n    {\n        public PutCommandRequestValidator()\n        {\n            RuleFor(request => request.Message.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.Domain/Liquid.Sample.Domain.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"FluentValidation\" Version=\"11.9.2\" />\n    <PackageReference Include=\"Liquid.Messaging.ServiceBus\" Version=\"6.0.0\" />\n    <PackageReference Include=\"Liquid.Repository.Mongo\" Version=\"6.0.0\" />\n    <PackageReference Include=\"MediatR\" Version=\"12.1.1\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "samples/src/Liquid.Sample.MessagingConsumer/Liquid.Sample.MessagingConsumer.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Worker\">\n\n  <PropertyGroup>\n    <TargetFramework>net6.0</TargetFramework>\n    <UserSecretsId>dotnet-Liquid.Sample.MessagingConsumer-5B39CB3F-CC5C-4EBB-AB99-178E83416FC9</UserSecretsId>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" Version=\"6.0.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\Liquid.Sample.Domain\\Liquid.Sample.Domain.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "samples/src/Liquid.Sample.MessagingConsumer/Program.cs",
    "content": "using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Messaging.ServiceBus.Extensions.DependencyInjection;\nusing Liquid.Repository.Mongo.Extensions;\nusing Liquid.Sample.Domain.Entities;\nusing Liquid.Sample.Domain.Handlers.SamplePut;\nusing Microsoft.Extensions.Hosting;\nusing System;\n\nnamespace Liquid.Sample.MessagingConsumer\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureServices((hostContext, services) =>\n                {\n                    services.AddLiquidConfiguration();\n                    services.AddLiquidMongoRepository<SampleEntity, Guid>(\"Liquid:MyMongoDbSettings:Entities\");\n                    services.AddLiquidServiceBusProducer<SampleMessageEntity>(\"ServiceBus\", \"liquidoutput\", false);\n                    services.AddLiquidServiceBusConsumer<Worker, SampleMessageEntity> (\"ServiceBus\", \"liquidinput\", false, typeof(PutCommandRequest).Assembly);\n                });\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.MessagingConsumer/Worker.cs",
    "content": "using Liquid.Messaging;\nusing Liquid.Messaging.Interfaces;\nusing Liquid.Sample.Domain.Entities;\nusing Liquid.Sample.Domain.Handlers.SamplePut;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Sample.MessagingConsumer\n{\n    public class Worker : ILiquidWorker<SampleMessageEntity>\n    {\n        private readonly ILogger<Worker> _logger;\n        private readonly IMediator _mediator;\n\n        public Worker(ILogger<Worker> logger, IMediator mediator)\n        {\n            _logger = logger;\n            _mediator = mediator;\n        }\n\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<SampleMessageEntity> args, CancellationToken cancellationToken)\n        {\n            await _mediator.Send(new PutCommandRequest(args.Data));\n        }\n    }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.MessagingConsumer/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "samples/src/Liquid.Sample.MessagingConsumer/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"Liquid\": {\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"ScopedContext\": {\n      \"keys\": [\n        {\n          \"keyName\": \"Connection\",\n          \"required\": false\n        }\n      ]\n    },\n    \"ScopedLogging\": {\n      \"keys\": [\n        {\n          \"keyName\": \"Connection\",\n          \"required\": false\n        }\n      ]\n    },\n    \"MyMongoDbSettings\": {\n      \"DefaultDatabaseSettings\": {\n        \"connectionString\": \"\",\n        \"databaseName\": \"MySampleDb\"\n      },\n      \"Entities\": {\n        \"SampleEntity\": {\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      }\n    }\n  },\n  \"ServiceBus\": {\n    \"Settings\": [\n      {\n        \"ConnectionString\": \"\",\n        \"EntityPath\": \"liquidoutput\"\n      },\n      {\n        \"ConnectionString\": \"\",\n        \"EntityPath\": \"liquidinput\"\n      }\n    ]\n  }\n}\n"
  },
  {
    "path": "src/Liquid.Cache.Memory/Extensions/DependencyInjection/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Microsoft.Extensions.Caching.Distributed;\nusing Microsoft.Extensions.Caching.Memory;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\n\nnamespace Liquid.Cache.Memory.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// LiquidCache using Redis <see cref=\"IServiceCollection\"/> extensions class.\n    /// </summary>\n    public static class IServiceCollectionExtension\n    {\n        /// <summary>\n        /// Registers <see cref=\"MemoryDistributedCache\"/> service and <see cref=\"LiquidCache\"/> decorator,\n        /// with its <see cref=\"LiquidTelemetryInterceptor\"/>.\n        /// </summary>\n        /// <param name=\"services\"></param>\n        /// <param name=\"setupAction\">An System.Action`1 to configure the provided \n        /// <see cref=\"MemoryDistributedCacheOptions\"/>.</param>\n        /// <param name=\"withTelemetry\">Indicates if this method must register a <see cref=\"LiquidTelemetryInterceptor\"/></param>\n        public static IServiceCollection AddLiquidMemoryDistributedCache(this IServiceCollection services,\n            Action<MemoryDistributedCacheOptions> setupAction, bool withTelemetry = true)\n        {\n            services.AddDistributedMemoryCache(setupAction);\n\n            return services.AddLiquidDistributedCache(withTelemetry);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Cache.Memory/Liquid.Cache.Memory.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t  <PackageId>Liquid.Cache.Memory</PackageId>\n\t<Nullable>enable</Nullable>\n\t  <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <DebugType>Full</DebugType>\n\t  <Description>\n\t\t  Distributed cache extension of Microsoft.Extensions.Caching.Memory.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n      <PackagePath></PackagePath>\n      <Pack>True</Pack>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Caching.Memory\" Version=\"8.0.1\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Cache.NCache/Extensions/DependencyInjection/IServiceCollectionExtension.cs",
    "content": "﻿using Alachisoft.NCache.Caching.Distributed;\nusing Alachisoft.NCache.Caching.Distributed.Configuration;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\n\nnamespace Liquid.Cache.NCache.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// LiquidCache using NCache <see cref=\"IServiceCollection\"/> extensions class.\n    /// </summary>\n    public static class IServiceCollectionExtension\n    {\n        /// <summary>\n        /// Registers <see cref=\"NCacheDistributedCache\"/> service and <see cref=\"LiquidCache\"/> decorator,\n        /// with its <see cref=\"LiquidTelemetryInterceptor\"/>.\n        /// </summary>\n        /// <param name=\"services\"></param>\n        /// <param name=\"setupAction\">An System.Action`1 to configure the provided\n        /// <see cref=\"NCacheConfiguration\"/>.</param>\n        /// <param name=\"withTelemetry\">Indicates if this method must register a <see cref=\"LiquidTelemetryInterceptor\"/></param>\n        public static IServiceCollection AddLiquidNCacheDistributedCache(this IServiceCollection services,\n             Action<NCacheConfiguration> setupAction, bool withTelemetry = true)\n        {\n            services.AddNCacheDistributedCache(setupAction);\n\n            return services.AddLiquidDistributedCache(withTelemetry);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Cache.NCache/Liquid.Cache.NCache.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t  <PackageId>Liquid.Cache.NCache</PackageId>\n\t\t<Nullable>enable</Nullable>\n\t   <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <DebugType>Full</DebugType>\n\t  <Description>\n\t\t  Distributed cache extension of NCache.Microsoft.Extensions.Caching.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n      <PackagePath></PackagePath>\n      <Pack>True</Pack>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Alachisoft.NCache.SDK\" Version=\"5.3.5\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"NCache.Microsoft.Extensions.Caching\" Version=\"5.3.3\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Update=\"client.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"config.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"tls.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Cache.NCache/client.ncconf",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n  <configuration>\n    <ncache-server connection-retries=\"3\" retry-connection-delay=\"0\" retry-interval=\"1\" command-retries=\"3\" command-retry-interval=\"0.1\" client-request-timeout=\"90\" connection-timeout=\"5\" port=\"9800\"/>\n    <cache id=\"myReplicatedCache\" client-cache-id=\"\" client-cache-syncmode=\"optimistic\" default-readthru-provider=\"\" default-writethru-provider=\"\" load-balance=\"True\"  enable-client-logs=\"False\" log-level=\"error\">\n      <server name=\"10.0.5.1\" />\n    </cache>\n  </configuration>\n"
  },
  {
    "path": "src/Liquid.Cache.NCache/config.ncconf",
    "content": "<configuration>\n  <cache-config cache-name=\"myCache\" alias=\"\" config-id=\"e097c2c0-88af-4aa2-8a8a-c6432eeaa3fe\" config-version=\"0\" store-type=\"distributed-cache\">\n    <cache-settings inproc=\"True\" last-modified=\"\" auto-start=\"False\" data-format=\"Binary\">\n      <logging enable-logs=\"True\" trace-errors=\"True\" trace-notices=\"False\" trace-warnings=\"False\" trace-debug=\"False\" log-path=\"\"/>\n      <performance-counters enable-counters=\"True\" snmp-port=\"0\"/>\n      <data-load-balancing enabled=\"False\" auto-balancing-threshold=\"60%\" auto-balancing-interval=\"30sec\"/>\n      <compression enable-compression=\"False\" threshold=\"100kb\"/>\n      <client-death-detection/>\n      <client-activity-notification enabled=\"False\" retention-period=\"5sec\"/>\n      <cache-notifications item-remove=\"False\" item-add=\"False\" item-update=\"False\"/>\n      <cleanup interval=\"15sec\"/>\n      <storage type=\"heap\" cache-size=\"1024mb\"/>\n      <eviction-policy enabled-eviction=\"True\" default-priority=\"normal\" policy=\"lru\" eviction-ratio=\"5%\"/>\n      <expiration-policy enabled=\"False\">\n        <absolute-expiration longer-enabled=\"False\" longer-value=\"0\" default-enabled=\"False\" default-value=\"0\"/>\n        <sliding-expiration longer-enabled=\"False\" longer-value=\"0\" default-enabled=\"False\" default-value=\"0\"/>\n      </expiration-policy>\n      <cache-topology topology=\"local-cache\"/>\n      <tasks-config max-tasks=\"10\" chunk-size=\"100\" communicate-stats=\"False\" queue-size=\"10\" max-avoidable-exceptions=\"10\"/>\n      <split-brain-recovery enable=\"False\" detection-interval=\"60\"/>\n    </cache-settings>\n  </cache-config>\n\n\n</configuration>"
  },
  {
    "path": "src/Liquid.Cache.NCache/tls.ncconf",
    "content": "<tls-info>\n\t<server-certificate-cn>certificate-name</server-certificate-cn>\n\t<server-certificate-thumbprint>your-thumbprint</server-certificate-thumbprint>\n\t<client-certificate-cn>certificate-name</client-certificate-cn>\n\t<client-certificate-thumbprint>your-thumbprint</client-certificate-thumbprint>\n\t<enable>false</enable>\n\t<enable-client-server-tls>false</enable-client-server-tls>\n\t<use-mutual-tls-for-client-to-server>false</use-mutual-tls-for-client-to-server>\n\t<protocol-version>tls12</protocol-version>\n</tls-info>"
  },
  {
    "path": "src/Liquid.Cache.Redis/Extensions/DependencyInjection/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Microsoft.Extensions.Caching.StackExchangeRedis;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\n\nnamespace Liquid.Cache.Redis.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// LiquidCache using Redis <see cref=\"IServiceCollection\"/> extensions class.\n    /// </summary>\n    public static class IServiceCollectionExtension\n    {\n        /// <summary>\n        /// Registers <see cref=\"RedisCache\"/> service and <see cref=\"LiquidCache\"/> decorator,\n        /// with its <see cref=\"LiquidTelemetryInterceptor\"/>.\n        /// </summary>\n        /// <param name=\"services\"></param>\n        /// <param name=\"setupAction\">An System.Action`1 to configure the provided\n        /// Microsoft.Extensions.Caching.StackExchangeRedis.RedisCacheOptions.</param>\n        /// <param name=\"withTelemetry\">Indicates if this method must register a <see cref=\"LiquidTelemetryInterceptor\"/></param>\n        public static IServiceCollection AddLiquidRedisDistributedCache(this IServiceCollection services,\n            Action<RedisCacheOptions> setupAction, bool withTelemetry = true)\n        {\n            services.AddStackExchangeRedisCache(setupAction);\n\n            return services.AddLiquidDistributedCache(withTelemetry);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Cache.Redis/Liquid.Cache.Redis.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>enable</Nullable>\n\t  <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <DebugType>Full</DebugType>\n\t  <Description>\n\t\t  Distributed cache extension of Microsoft.Extensions.Caching.StackExchangeRedis.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n      <PackagePath></PackagePath>\n      <Pack>True</Pack>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Caching.StackExchangeRedis\" Version=\"8.0.6\" />\n    <PackageReference Include=\"System.Drawing.Common\" Version=\"8.0.6\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Cache.SqlServer/Extensions/DependencyInjection/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Microsoft.Extensions.Caching.SqlServer;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\n\nnamespace Liquid.Cache.SqlServer.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// LiquidCache using SqlServer <see cref=\"IServiceCollection\"/> extensions class.\n    /// </summary>\n    public static class IServiceCollectionExtension\n    {\n        /// <summary>\n        /// Registers <see cref=\"SqlServerCache\"/> service and <see cref=\"LiquidCache\"/> decorator,\n        /// with its <see cref=\"LiquidTelemetryInterceptor\"/>.\n        /// </summary>\n        /// <param name=\"services\"></param>\n        /// <param name=\"setupAction\">An System.Action`1 to configure the provided\n        ///<see cref=\"SqlServerCacheOptions\"/>.</param>\n        /// <param name=\"withTelemetry\">Indicates if this method must register a <see cref=\"LiquidTelemetryInterceptor\"/></param>\n        public static IServiceCollection AddLiquidSqlServerDistributedCache(this IServiceCollection services,\n            Action<SqlServerCacheOptions> setupAction, bool withTelemetry = true)\n        {\n            services.AddDistributedSqlServerCache(setupAction);\n\n            return services.AddLiquidDistributedCache(withTelemetry);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Cache.SqlServer/Liquid.Cache.SqlServer.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n     <PackageId>Liquid.Cache.SqlServer</PackageId>\n\t  <Nullable>enable</Nullable>\n\t  <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <DebugType>Full</DebugType>\n\t  <Description>\n\t\t  Distributed cache extension of Microsoft.Extensions.Caching.SqlServer.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n      <PackagePath></PackagePath>\n      <Pack>True</Pack>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Identity\" Version=\"1.13.2\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Data.SqlClient\" Version=\"6.0.2\" />\n    <PackageReference Include=\"Microsoft.Extensions.Caching.SqlServer\" Version=\"8.0.6\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection.Abstractions\" Version=\"8.0.2\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Core/AbstractMappers/LiquidMapper.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.AbstractMappers\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    public abstract class LiquidMapper<TFrom, TTo> : ILiquidMapper<TFrom, TTo>\n    {\n        private readonly string _mapperName;\n\n        /// <summary>\n        /// Create a new instance of <see cref=\"LiquidMapper{TFrom, TTo}\"/>\n        /// </summary>\n        /// <param name=\"mapperName\">Mapper implementation name.</param>\n        protected LiquidMapper(string mapperName)\n        {\n            _mapperName = mapperName;\n        }\n        ///<inheritdoc/>\n        public async Task<TTo> Map(TFrom dataObject, string entityName = null)\n        {\n            if (dataObject is null)\n            {\n                throw new ArgumentNullException(nameof(dataObject));\n            }\n\n            try\n            {\n                return await MapImpl(dataObject, entityName);\n            }\n            catch (Exception e)\n            {\n                var msg = $\"{_mapperName} throw data mapping error: '{e.Message}'\";\n\n                throw new DataMappingException(msg, e);\n            }\n        }\n        /// <summary>\n        /// \n        /// </summary>\n        /// <param name=\"dataObject\"></param>\n        /// <param name=\"entityName\"></param>\n        /// <returns></returns>\n        protected abstract Task<TTo> MapImpl(TFrom dataObject, string entityName = null);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/AbstractMappers/OcrResultMapper.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.AbstractMappers\n{\n    /// <summary>\n    /// Defines object that map data between two instance types.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">type of data source object.</typeparam>\n    [ExcludeFromCodeCoverage]\n    public abstract class OcrResultMapper<TFrom> : ILiquidMapper<TFrom, OcrResult>\n    {\n        private readonly string _mapperName;\n\n        /// <summary>\n        /// Create a new instance of <see cref=\"OcrResultMapper{TFrom}\"/>\n        /// </summary>\n        /// <param name=\"mapperName\">Mapper implementation name.</param>\n        public OcrResultMapper(string mapperName)\n        {\n            _mapperName = mapperName;\n        }\n        ///<inheritdoc/>\n        public async Task<OcrResult> Map(TFrom dataObject, string entityName = null)\n        {\n            if (dataObject is null)\n            {\n                throw new ArgumentNullException(nameof(dataObject));\n            }\n\n            try\n            {\n                return await MapImpl(dataObject);\n            }\n            catch (Exception e)\n            {\n                var msg = $\"{_mapperName} throw data mapping error: '{e.Message}'\";\n\n                throw new DataMappingException(msg, e);\n            }\n        }\n        /// <summary>\n        /// Create a new instance of <see cref=\"OcrResult\"/>\n        /// with values obtained from <see cref=\"TFrom\"/>. \n        /// </summary>\n        /// <param name=\"dataObject\">data source object instance.</param>\n        protected abstract Task<OcrResult> MapImpl(TFrom dataObject);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Attributes/LiquidSectionNameAttribute.cs",
    "content": "﻿using System;\n\nnamespace Liquid.Core.Attributes\n{\n    /// <summary>\n    /// Defines which configuration section, the custom configuration will read from json file.\n    /// </summary>\n    /// <seealso cref=\"Attribute\" />\n    [AttributeUsage(AttributeTargets.Class)]\n    public class LiquidSectionNameAttribute : Attribute\n    {\n        /// <summary>\n        /// Gets the name of the section.\n        /// </summary>\n        /// <value>\n        /// The name of the section.\n        /// </value>\n        public string SectionName { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidSectionNameAttribute\"/> class.\n        /// </summary>\n        /// <param name=\"sectionName\">Name of the section.</param>\n        public LiquidSectionNameAttribute(string sectionName)\n        {\n            SectionName = sectionName;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Base/Enumeration.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Liquid.Core.Base\n{\n    /// <summary>\n    /// Enumeration Base Class.\n    /// </summary>\n    /// <seealso cref=\"System.IComparable\" />\n    [ExcludeFromCodeCoverage]\n    public abstract class Enumeration : IComparable\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"Enumeration\"/> class.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"displayName\">The display name.</param>\n        protected Enumeration(int value, string displayName)\n        {\n            Value = value;\n            DisplayName = displayName;\n        }\n\n        /// <summary>\n        /// Gets the value.\n        /// </summary>\n        /// <value>\n        /// The value.\n        /// </value>\n        public int Value { get; }\n\n        /// <summary>\n        /// Gets the display name.\n        /// </summary>\n        /// <value>\n        /// The display name.\n        /// </value>\n        public string DisplayName { get; }\n\n        /// <summary>\n        /// Converts to string.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"System.String\" /> that represents this instance.\n        /// </returns>\n        public override string ToString()\n        {\n            return DisplayName;\n        }\n\n        /// <summary>\n        /// Gets all.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns></returns>\n        public static IEnumerable<T> GetAll<T>() where T : Enumeration, new()\n        {\n            var type = typeof(T);\n            var fields = type.GetFields(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);\n\n            foreach (var info in fields)\n            {\n                var instance = new T();\n\n                if (info.GetValue(instance) is T locatedValue)\n                {\n                    yield return locatedValue;\n                }\n            }\n        }\n\n        /// <summary>\n        /// Determines whether the specified <see cref=\"System.Object\" />, is equal to this instance.\n        /// </summary>\n        /// <param name=\"obj\">The <see cref=\"System.Object\" /> to compare with this instance.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified <see cref=\"System.Object\" /> is equal to this instance; otherwise, <c>false</c>.\n        /// </returns>\n        public override bool Equals(object obj)\n        {\n            var otherValue = obj as Enumeration;\n\n            if (otherValue == null)\n            {\n                return false;\n            }\n\n            var typeMatches = GetType() == obj.GetType();\n            var valueMatches = Value.Equals(otherValue.Value);\n\n            return typeMatches && valueMatches;\n        }\n\n        /// <summary>\n        /// Returns a hash code for this instance.\n        /// </summary>\n        /// <returns>\n        /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. \n        /// </returns>\n        public override int GetHashCode()\n        {\n            return Value.GetHashCode();\n        }\n\n        /// <summary>\n        /// Absolutes the difference.\n        /// </summary>\n        /// <param name=\"firstValue\">The first value.</param>\n        /// <param name=\"secondValue\">The second value.</param>\n        /// <returns></returns>\n        public static int AbsoluteDifference(Enumeration firstValue, Enumeration secondValue)\n        {\n            var absoluteDifference = Math.Abs(firstValue.Value - secondValue.Value);\n            return absoluteDifference;\n        }\n\n        /// <summary>\n        /// Gets the enumeration from id value.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"value\">The value.</param>\n        /// <returns></returns>\n        public static T FromValue<T>(int value) where T : Enumeration, new()\n        {\n            var matchingItem = Parse<T, int>(value, \"value\", item => item.Value == value);\n            return matchingItem;\n        }\n\n        /// <summary>\n        /// Gets the enumeration from display name.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"displayName\">The display name.</param>\n        /// <returns></returns>\n        public static T FromDisplayName<T>(string displayName) where T : Enumeration, new()\n        {\n            var matchingItem = Parse<T, string>(displayName, \"display name\", item => item.DisplayName == displayName);\n            return matchingItem;\n        }\n\n        /// <summary>\n        /// Parses the specified value.\n        /// </summary>\n        /// <typeparam name=\"TEnumerable\"></typeparam>\n        /// <typeparam name=\"TValue\"></typeparam>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"description\">The description.</param>\n        /// <param name=\"predicate\">The predicate.</param>\n        /// <returns></returns>\n        /// <exception cref=\"ApplicationException\"></exception>\n        private static TEnumerable Parse<TEnumerable, TValue>(TValue value, string description, Func<TEnumerable, bool> predicate) where TEnumerable : Enumeration, new()\n        {\n            var matchingItem = GetAll<TEnumerable>().FirstOrDefault(predicate);\n\n            if (matchingItem != null) return matchingItem;\n            var message = $\"'{value}' is not a valid {description} in {typeof(TEnumerable)}\";\n            throw new LiquidException(message);\n        }\n\n        /// <summary>\n        /// Compares to.\n        /// </summary>\n        /// <param name=\"obj\">The other object to be compared.</param>\n        /// <returns></returns>\n        public int CompareTo(object obj)\n        {\n            return Value.CompareTo(((Enumeration)obj).Value);\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Base/LiquidInterceptorBase.cs",
    "content": "﻿using Castle.DynamicProxy;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Base\n{\n    /// <summary>\n    /// Base class to implement interceptors with actions after, before and on exception.\n    /// </summary>\n    public abstract class LiquidInterceptorBase : AsyncInterceptorBase\n    {\n        /// <summary>\n        /// Initialize an instace of <see cref=\"LiquidInterceptorBase\"/>\n        /// </summary>\n        protected LiquidInterceptorBase()\n        {\n        }\n\n        /// <summary>\n        /// Traces start, stop and exception of the intercepted method.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"proceed\">The function to proceed the proceedInfo.</param>\n        protected override async Task InterceptAsync(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task> proceed)\n        {\n            try\n            {\n                await BeforeInvocation(invocation, proceedInfo);\n                await proceed(invocation, proceedInfo).ConfigureAwait(false);\n            }\n            catch (Exception ex)\n            {\n                await OnExceptionInvocation(invocation, proceedInfo, ex);\n                throw;\n            }\n            finally\n            {\n                await AfterInvocation(invocation, proceedInfo, default(object));\n            }\n        }\n\n        /// <summary>\n        /// Traces start, stop and exception of the intercepted method.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"proceed\">The function to proceed the proceedInfo.</param>\n        protected sealed override async Task<TResult> InterceptAsync<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, Func<IInvocation, IInvocationProceedInfo, Task<TResult>> proceed)\n        {\n            TResult result = default;\n            try\n            {\n                await BeforeInvocation(invocation, proceedInfo);\n                return await proceed(invocation, proceedInfo).ConfigureAwait(false);\n            }\n            catch (Exception ex)\n            {\n                await OnExceptionInvocation(invocation, proceedInfo, ex);\n                throw;\n            }\n            finally\n            {\n                await AfterInvocation(invocation, proceedInfo, result).ConfigureAwait(false);\n            }\n        }\n\n        /// <summary>\n        ///   Override in derived classes to intercept method invocations.\n        /// </summary>\n        /// <typeparam name=\"TResult\">The type of result object.</typeparam>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"result\">Result object.</param>\n        /// <returns></returns>\n        protected abstract Task AfterInvocation<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, TResult result);\n\n        /// <summary>\n        /// Override in derived classes to intercept method invocations.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <returns></returns>\n        protected abstract Task BeforeInvocation(IInvocation invocation, IInvocationProceedInfo proceedInfo);\n\n        /// <summary>\n        /// Override in derived classes to intercept method invocations.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"exception\">THe exception object.</param>\n        /// <returns></returns>\n        protected abstract Task OnExceptionInvocation(IInvocation invocation, IInvocationProceedInfo proceedInfo, Exception exception);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Decorators/LiquidContextDecorator.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Decorators\n{\n    /// <summary>\n    /// Inserts configured context keys in LiquidContext service.\n    /// Includes its behavior in worker service before process execution.\n    /// </summary>\n    public class LiquidContextDecorator<TEntity> : ILiquidWorker<TEntity>\n    {\n        private readonly ILiquidWorker<TEntity> _inner;\n        private readonly ILiquidContext _context;\n        private readonly IOptions<ScopedContextSettings> _options;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidContextDecorator{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"inner\">Decorated service.</param>\n        /// <param name=\"context\">Scoped Context service.</param>\n        /// <param name=\"options\">Scoped context keys set.</param>\n        public LiquidContextDecorator(ILiquidWorker<TEntity> inner, ILiquidContext context, IOptions<ScopedContextSettings> options)\n        {\n            _inner = inner ?? throw new ArgumentNullException(nameof(inner));\n            _context = context ?? throw new ArgumentNullException(nameof(context));\n            _options = options ?? throw new ArgumentNullException(nameof(options));\n        }\n\n        ///<inheritdoc/>\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<TEntity> args, CancellationToken cancellationToken)\n        {\n            object value = default;\n\n            foreach (var key in _options.Value.Keys)\n            {\n                args.Headers?.TryGetValue(key.KeyName, out value);\n\n                if (value is null && key.Required)\n                    throw new MessagingMissingContextKeysException(key.KeyName);\n\n                _context.Upsert(key.KeyName, value);\n            }\n\n            if (_options.Value.Culture)\n            {\n                _context.Upsert(\"culture\", CultureInfo.CurrentCulture.Name);\n            }\n\n            await _inner.ProcessMessageAsync(args, cancellationToken);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Decorators/LiquidCultureDecorator.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Decorators\n{\n    /// <summary>\n    /// Configures the culture in the current thread.\n    /// Includes its behavior in worker service before process execution.\n    /// </summary>\n    public class LiquidCultureDecorator<TEntity> : ILiquidWorker<TEntity>\n    {\n        private const string _culture = \"culture\";\n        private readonly IOptions<CultureSettings> _options;\n        private readonly ILiquidWorker<TEntity> _inner;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidCultureDecorator{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"inner\">Decorated service.</param>\n        /// <param name=\"options\">Default culture configuration.</param>\n        public LiquidCultureDecorator(ILiquidWorker<TEntity> inner, IOptions<CultureSettings> options)\n        {\n            _inner = inner ?? throw new ArgumentNullException(nameof(inner));\n            _options = options ?? throw new ArgumentNullException(nameof(options));\n        }\n\n        ///<inheritdoc/>\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<TEntity> args, CancellationToken cancellationToken)\n        {\n            object cultureCode = default;\n\n            args.Headers?.TryGetValue(_culture, out cultureCode);\n\n            if (cultureCode is null && !string.IsNullOrEmpty(_options.Value.DefaultCulture))\n            {\n                cultureCode = _options.Value.DefaultCulture;\n            }\n\n            if (cultureCode != null)\n            {\n                CultureInfo.DefaultThreadCurrentCulture = new CultureInfo(cultureCode.ToString());\n                CultureInfo.DefaultThreadCurrentUICulture = new CultureInfo(cultureCode.ToString());\n            }\n\n            await _inner.ProcessMessageAsync(args, cancellationToken);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Decorators/LiquidScopedLoggingDecorator.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Decorators\n{\n    /// <summary>\n    /// Inserts configured context keys in ILogger service scope.\n    /// Includes its behavior in worker service before process execution.\n    /// </summary>\n    public class LiquidScopedLoggingDecorator<TEntity> : ILiquidWorker<TEntity>\n    {\n        private readonly ILogger<LiquidScopedLoggingDecorator<TEntity>> _logger;\n        private readonly IOptions<ScopedLoggingSettings> _options;\n        private readonly ILiquidWorker<TEntity> _inner;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidScopedLoggingDecorator{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"inner\">Decorated service.</param>\n        /// <param name=\"options\">Default culture configuration.</param>\n        /// <param name=\"logger\">Logger service instance.</param>\n        public LiquidScopedLoggingDecorator(ILiquidWorker<TEntity> inner\n            , IOptions<ScopedLoggingSettings> options\n            , ILogger<LiquidScopedLoggingDecorator<TEntity>> logger)\n        {\n            _inner = inner ?? throw new ArgumentNullException(nameof(inner));\n            _options = options ?? throw new ArgumentNullException(nameof(options));\n            _logger = logger ?? throw new ArgumentNullException(nameof(logger));\n        }\n\n        ///<inheritdoc/>\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<TEntity> args, CancellationToken cancellationToken)\n        {\n            var scope = new List<KeyValuePair<string, object>>();\n\n            object value = default;\n\n            foreach (var key in _options.Value.Keys)\n            {\n                args.Headers?.TryGetValue(key.KeyName, out value);\n\n                if (value is null && key.Required)\n                    throw new MessagingMissingScopedKeysException(key.KeyName);\n\n                scope.Add(new KeyValuePair<string, object>(key.KeyName, value));\n            }\n\n            using (_logger.BeginScope(scope.ToArray()))\n            {\n                await _inner.ProcessMessageAsync(args, cancellationToken);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Entities/ChatCompletionResult.cs",
    "content": "﻿namespace Liquid.Core.Entities\n{\n    /// <summary>\n    ///  Chat completions result set.\n    /// </summary>\n    public class ChatCompletionResult\n    {\n        /// <summary>\n        /// The content of the response message.\n        /// </summary>\n        public string Content { get; set; }\n\n        /// <summary>\n        /// The reason the model stopped generating tokens, together with any applicable details.\n        /// </summary>\n        public string FinishReason { get; set; }\n\n        /// <summary>\n        /// The total number of tokens processed for the completions request and response.\n        /// </summary>\n        public int Usage { get; set; }\n\n        /// <summary>\n        /// The number of tokens used by the prompt.\n        /// </summary>\n        public int PromptUsage { get; set; }\n\n        /// <summary>\n        /// The number of tokens used by the completion.\n        /// </summary>\n        public int CompletionUsage { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Entities/ClientDictionary.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// Client dictionary to store client instances.\n    /// </summary>\n    /// <typeparam name=\"T\">Type of client service.</typeparam>\n    [ExcludeFromCodeCoverage]\n    public class ClientDictionary<T>\n    {\n        /// <summary>\n        /// Number of executions for this client.\n        /// </summary>\n        public int Executions { get; set; } = 1;\n\n\n        /// <summary>\n        /// Client connection alias.\n        /// </summary>\n        public string ClientId { get; set; }\n\n        /// <summary>\n        /// Client instance.\n        /// </summary>\n        public T Client { get; set; }\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"ClientDictionary{T}\"/>.\n        /// </summary>\n        /// <param name=\"clientId\">Client connection alias.</param>\n        /// <param name=\"client\">Client instance.</param>\n        public ClientDictionary(string clientId, T client)\n        {\n            ClientId = clientId;\n            Client = client;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Entities/ConsumerErrorEventArgs.cs",
    "content": "﻿using System;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// Arguments for processing errors occurred during process execution.\n    /// </summary>\n    public class ConsumerErrorEventArgs\n    {\n        /// <summary>\n        ///   Represents errors that occur during process execution.\n        /// </summary>\n        public Exception Exception { get; set; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Entities/ConsumerMessageEventArgs.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// \n    /// </summary>\n    /// <typeparam name=\"TEvent\"></typeparam>\n    public class ConsumerMessageEventArgs<TEvent>\n    {\n        /// <summary>\n        /// \n        /// </summary>\n        public TEvent Data { get; set; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public IDictionary<string, object> Headers { get; set; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Entities/FunctionBody.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// The body of a function to be called.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class FunctionBody\n    {\n\n        /// <summary> The name of the function to be called. </summary>\n        public string Name { get; set; }\n        /// <summary>\n        /// A description of what the function does. The model will use this description when selecting the function and\n        /// interpreting its parameters.\n        /// </summary>\n        public string Description { get; set; }\n        /// <summary>\n        /// The parameters the function accepts, described as a JSON Schema object.\n        /// <para>\n        /// To assign an object to this property use <see cref=\"BinaryData.FromObjectAsJson{T}(T, JsonSerializerOptions)\"/>.\n        /// </para>\n        /// <para>\n        /// To assign an already formatted json string to this property use <see cref=\"BinaryData.FromString(string)\"/>.\n        /// </para>\n        /// </summary>\n        public BinaryData Parameters { get; set; }\n\n        /// <summary> Initializes a new instance of <see cref=\"FunctionBody\"/>. </summary>\n        /// <param name=\"name\"> The name of the function to be called. </param>\n        /// <param name=\"description\">\n        /// A description of what the function does. The model will use this description when selecting the function and\n        /// interpreting its parameters.\n        /// </param>\n        /// <param name=\"parameters\"> The parameters the function accepts, described as a JSON Schema object. </param>\n        /// <exception cref=\"ArgumentException\"></exception>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public FunctionBody(string name, string description, BinaryData parameters)\n        {\n            if (string.IsNullOrEmpty(name))\n            {\n                throw new ArgumentException($\"'{nameof(name)}' cannot be null or empty.\", nameof(name));\n            }\n\n            if (string.IsNullOrEmpty(description))\n            {\n                throw new ArgumentException($\"'{nameof(description)}' cannot be null or empty.\", nameof(description));\n            }\n\n            Name = name;\n            Description = description;\n            Parameters = parameters ?? throw new ArgumentNullException(nameof(parameters));\n\n        }\n\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"FunctionBody\"/>.\n        /// </summary>\n        /// <param name=\"functionBody\">function definition JSON string. </param>\n        public FunctionBody(string functionBody)\n        {\n            var function = JsonSerializer.Deserialize<JsonElement>(functionBody);\n\n            Name = function.GetProperty(\"name\").ToString();\n            Description = function.GetProperty(\"description\").ToString();\n            Parameters = BinaryData.FromObjectAsJson(function.GetProperty(\"parameters\"));\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Entities/LiquidBlob.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// Set de propriedades referentes à um item do BlobStorage.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidBlob\n    {\n        /// <summary>\n        /// Lista de tags referentes ao blob.\n        /// </summary>\n        public IDictionary<string, string> Tags { get; set; } = new Dictionary<string, string>();\n\n        /// <summary>\n        /// Conteúdo do blob.\n        /// </summary>\n        public byte[] Blob { get; set; }\n\n        /// <summary>\n        /// Nome do arquivo no Storage.\n        /// </summary>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Caminho do blob.\n        /// </summary>\n        public string AbsoluteUri { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Entities/LiquidEntity.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// Represents the repository entity\n    /// </summary>\n    /// <typeparam name=\"TIdentifier\">The type of the identifier.</typeparam>\n    [ExcludeFromCodeCoverage]\n    public class LiquidEntity<TIdentifier>\n    {\n        /// <summary>\n        /// Gets or sets the identifier.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        public virtual TIdentifier Id { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Entities/OcrResult.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Drawing;\n\nnamespace Liquid.Core.Entities\n{\n    /// <summary>\n    /// Optical Character Recognition result set.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class OcrResult\n    {\n        /// <summary>\n        /// Recognition result content.\n        /// </summary>\n        public string Content { get; set; }\n\n        /// <summary>\n        ///Analyzed pages.\n        /// </summary>\n        public List<PageInfo> Pages { get; set; }\n    }\n    /// <summary>\n    /// Analyzed page content.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class PageInfo\n    {\n        /// <summary>\n        /// recognition result page index.\n        /// </summary>\n        public int PageNumber { get; set; }\n\n        /// <summary>\n        /// The unit used by the words and lines data polygon properties.\n        /// </summary>\n        public string PolygonUnit { get; set; }\n\n        /// <summary>\n        /// Extracted words from the page.\n        /// </summary>\n        public List<WordData> Words { get; set; } = new List<WordData>();\n\n        /// <summary>\n        /// Extracted lines from the page.\n        /// </summary>\n        public List<LineData> Lines { get; set; } = new List<LineData>();\n    }\n    /// <summary>\n    /// A word object consisting of a contiguous sequence of characters.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class WordData\n    {\n        /// <summary>\n        /// Text content of the word.\n        /// </summary>\n        public string Content { get; set; }\n        /// <summary>\n        /// Confidence of correctly extracting the word.\n        /// </summary>\n        public float Confidence { get; set; }\n\n        /// <summary>\n        /// The polygon that outlines the content of this word. Coordinates are specified relative to the\n        /// top-left of the page, and points are ordered clockwise from the left relative to the word\n        /// orientation.\n        /// </summary>\n        public List<PointF> Polygon { get; set; } = new List<PointF>();\n    }\n\n    /// <summary>\n    ///  A content line object consisting of an adjacent sequence of content elements\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LineData\n    {\n        /// <summary>\n        /// Concatenated content of the contained elements in reading order.\n        /// </summary>\n        public string Content { get; set; }\n\n        /// <summary>\n        /// The polygon that outlines the content of this line. Coordinates are specified relative to the\n        /// top-left of the page, and points are ordered clockwise from the left relative to the line\n        /// orientation.\n        /// </summary>\n        public List<PointF> Polygon { get; set; } = new List<PointF>();\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/DataMappingException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when an exception is raised during data mapping.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class DataMappingException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataMappingException\"/> class.\n        /// </summary>\n        public DataMappingException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataMappingException\"/> class with a specified error message.\n        /// </summary>\n        /// <param name=\"message\"></param>\n        public DataMappingException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DataMappingException\"/> class with a specified error message and a reference to the inner exception that is the cause of this exception.\n        /// </summary>\n        /// <param name=\"message\"></param>\n        /// <param name=\"innerException\"></param>\n        public DataMappingException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Exceptions/DatabaseContextException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when a Repository database throw an error.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class DatabaseContextException : LiquidException\n    {\n        ///<inheritdoc/>\n        public DatabaseContextException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DatabaseContextException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">Error message custom text.</param>\n        /// <param name=\"innerException\">Exception throwed by the client.</param>\n        public DatabaseContextException(string message, Exception innerException)\n            : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/ExceptionCustomCodes.cs",
    "content": "﻿using Liquid.Core.Base;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Contains Exceptions Custom Codes to be processed and converted to custom error codes.\n    /// </summary>\n    /// <seealso cref=\"Liquid.Core.Base.Enumeration\" />\n    [ExcludeFromCodeCoverage]\n    public class ExceptionCustomCodes : Enumeration\n    {\n        /// <summary>\n        /// Indicates that the item is not found.\n        /// </summary>\n        public static readonly ExceptionCustomCodes NotFound = new ExceptionCustomCodes(404, \"NotFound\");\n\n        /// <summary>\n        /// Indicates that an internal error has occurred.\n        /// </summary>\n        public static readonly ExceptionCustomCodes InternalError = new ExceptionCustomCodes(500, \"InternalError\");\n\n        /// <summary>\n        /// Indicates that the request is bad formatted a validation error has occurred.\n        /// </summary>\n        public static readonly ExceptionCustomCodes BadRequest = new ExceptionCustomCodes(400, \"BadRequest\");\n\n        /// <summary>\n        /// Indicates a conflict.\n        /// </summary>\n        public static readonly ExceptionCustomCodes Conflict = new ExceptionCustomCodes(409, \"Conflict\");\n\n        /// <summary>\n        /// Indicates the resource is not accessible.\n        /// </summary>\n        public static readonly ExceptionCustomCodes Forbidden = new ExceptionCustomCodes(403, \"Forbidden\");\n\n        /// <summary>\n        /// Indicates a timeout error.\n        /// </summary>\n        public static readonly ExceptionCustomCodes Timeout = new ExceptionCustomCodes(408, \"Timeout\");\n\n        /// <summary>\n        /// Indicates the item is not authorized.\n        /// </summary>\n        public static readonly ExceptionCustomCodes Unauthorized = new ExceptionCustomCodes(401, \"Unauthorized\");\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"ExceptionCustomCodes\"/> class.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"displayName\">The display name.</param>\n        public ExceptionCustomCodes(int value, string displayName) : base(value, displayName)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/LiquidCustomException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Class responsible for custom exception codes handling.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class LiquidCustomException : LiquidException\n    {\n        /// <summary>\n        /// Gets the response code.\n        /// </summary>\n        /// <value>\n        /// The response code.\n        /// </value>\n        public ExceptionCustomCodes ResponseCode { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidCustomException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"responseCode\">The response code.</param>\n        public LiquidCustomException(string message, ExceptionCustomCodes responseCode) : base(message)\n        {\n            ResponseCode = responseCode;\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidCustomException\"/> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"responseCode\">The response code.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public LiquidCustomException(string message, ExceptionCustomCodes responseCode, Exception innerException) : base(message, innerException)\n        {\n            ResponseCode = responseCode;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Exceptions/LiquidDatabaseSettingsDoesNotExistException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when the database connection string is not found in appsettings file. Check the connection id and the configuration file.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class LiquidDatabaseSettingsDoesNotExistException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidDatabaseSettingsDoesNotExistException\"/> class.\n        /// </summary>\n        /// <param name=\"databaseName\">The connection identifier.</param>\n        public LiquidDatabaseSettingsDoesNotExistException(string databaseName)\n            : base($\"The connection string for database '{databaseName}' does not exist.\")\n        {\n        }\n        ///<inheritdoc/>\n        public LiquidDatabaseSettingsDoesNotExistException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/LiquidException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Liquid Base Custom Exception Class. Derived from <see cref=\"T:System.Exception\"></see> class.\n    /// </summary>\n    /// <seealso cref=\"Exception\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class LiquidException : Exception\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:LightException\"></see> class.\n        /// </summary>\n        public LiquidException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:LightException\"></see> class with a specified error message.\n        /// </summary>\n        /// <param name=\"message\">The message that describes the error.</param>\n        public LiquidException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"T:LightException\"></see> class with a specified error message and a reference to the inner exception that is the cause of this exception.\n        /// </summary>\n        /// <param name=\"message\">The error message that explains the reason for the exception.</param>\n        /// <param name=\"innerException\">The exception that is the cause of the current exception, or a null reference (Nothing in Visual Basic) if no inner exception is specified.</param>\n        public LiquidException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n        /// <summary>\n        /// Returns a <see cref=\"System.String\" /> that represents this instance.\n        /// </summary>\n        /// <returns>\n        /// A <see cref=\"System.String\" /> that represents this instance.\n        /// </returns>\n        public override string ToString()\n        {\n            return $\"Liquid Exception -> {base.ToString()}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Exceptions/MessagingConsumerException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when an exception is raised consuming a message.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class MessagingConsumerException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MessagingConsumerException\"/> class.\n        /// </summary>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public MessagingConsumerException(Exception innerException) : base(\"An error has occurred consuming message. See inner exception for more detail.\", innerException)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Exceptions/MessagingMissingConfigurationException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when a Configuration in settings configuration does not exist.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class MessagingMissingConfigurationException : LiquidException\n    {\n        ///<inheritdoc/>\n        public MessagingMissingConfigurationException(Exception innerException, string settingsName)\n            : base($\"The messaging configuration section {settingsName} is missing. See inner exception for more detail.\", innerException)\n        {\n        }\n\n        ///<inheritdoc/>\n        public MessagingMissingConfigurationException(string message) : base(message)\n        {\n        }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Exceptions/MessagingMissingContextKeysException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class MessagingMissingContextKeysException : LiquidException\n    {\n        ///<inheritdoc/>\n        public MessagingMissingContextKeysException()\n        {\n        }\n\n        ///<inheritdoc/>\n        public MessagingMissingContextKeysException(string contextKey) : base($\"The value of required context key '{contextKey}' was not found in request.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public MessagingMissingContextKeysException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/MessagingMissingScopedKeysException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class MessagingMissingScopedKeysException : LiquidException\n    {\n        ///<inheritdoc/>\n        public MessagingMissingScopedKeysException()\n        {\n        }\n\n        ///<inheritdoc/>\n        public MessagingMissingScopedKeysException(string contextKey) : base($\"The value of required logging scoped key '{contextKey}' was not found in request.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public MessagingMissingScopedKeysException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/MessagingMissingSettingsException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when a Configuration in settings configuration does not exist.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class MessagingMissingSettingsException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of <see cref=\"MessagingMissingSettingsException\"/>\n        /// </summary>\n        /// <param name=\"settingsName\">Configuration set name.</param>\n        public MessagingMissingSettingsException(string settingsName) : base($\"The messaging configuration settings name {settingsName} does not exist. Please check your configuration file.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public MessagingMissingSettingsException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/MessagingProducerException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when an exception occurs sending a message.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class MessagingProducerException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MessagingProducerException\"/> class.\n        /// </summary>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public MessagingProducerException(Exception innerException) : base(\"An error has occurred when sending message. See inner exception for more detail.\", innerException)\n        {\n        }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Exceptions/SerializerFailException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when the serialization fail.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class SerializerFailException : LiquidException\n    {\n        ///<inheritdoc/>\n        public SerializerFailException(string message) : base(message)\n        {\n        }\n\n        ///<inheritdoc/>\n        public SerializerFailException(string nameOfContent, Exception innerException) : base($\"An error occurred whilst serializing of content {nameOfContent} : \", innerException)\n        {\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/UnitOfWorkTransactionNotStartedException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when the transaction is not started.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class UnitOfWorkTransactionNotStartedException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnitOfWorkTransactionNotStartedException\"/> class.\n        /// </summary>\n        public UnitOfWorkTransactionNotStartedException() :\n            base(\"The transaction has been not started. Please start the transaction\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public UnitOfWorkTransactionNotStartedException(string message) : base(message)\n        {\n        }\n\n        ///<inheritdoc/>\n        public UnitOfWorkTransactionNotStartedException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Exceptions/UnitOfWorkTransactionWithoutRepositoryException.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Exceptions\n{\n    /// <summary>\n    /// Occurs when the transaction is called before a repository method is called.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class UnitofWorkTransactionWithoutRepositoryException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"UnitofWorkTransactionWithoutRepositoryException\"/> class.\n        /// </summary>\n        public UnitofWorkTransactionWithoutRepositoryException() :\n            base(\"You need to get a repository first to start an transaction. Use 'GetRepository' method.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public UnitofWorkTransactionWithoutRepositoryException(string message) : base(message)\n        {\n        }\n\n        ///<inheritdoc/>\n        public UnitofWorkTransactionWithoutRepositoryException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Extensions/ByteExtension.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text;\nusing System.Text.Json;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Byte Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class ByteExtension\n    {\n        /// <summary>\n        /// Gets the size of the kb.\n        /// </summary>\n        /// <param name=\"bytes\">The bytes.</param>\n        /// <returns></returns>\n        public static double GetKbSize(this byte[] bytes)\n        {\n            if (bytes == null || bytes.Length == 0) return 0;\n            return bytes.Length / 1024d;\n        }\n\n        /// <summary>\n        /// Gets the size of the mb.\n        /// </summary>\n        /// <param name=\"bytes\">The bytes.</param>\n        /// <returns></returns>\n        public static double GetMbSize(this byte[] bytes)\n        {\n            if (bytes == null || bytes.Length == 0) return 0;\n            return bytes.Length / Math.Pow(1024, 2);\n        }\n\n        /// <summary>\n        /// Gets the size of the gb.\n        /// </summary>\n        /// <param name=\"bytes\">The bytes.</param>\n        /// <returns></returns>\n        public static double GetGbSize(this byte[] bytes)\n        {\n            if (bytes == null || bytes.Length == 0) return 0;\n            return bytes.Length / Math.Pow(1024, 3);\n        }\n\n        /// <summary>\n        /// Parses byte array json to a specific object type.\n        /// </summary>\n        /// <typeparam name=\"T\">type of object to be parsed.</typeparam>\n        /// <param name=\"json\"></param>\n        /// <param name=\"options\">Provides options to be used with System.Text.Json.JsonSerializer.</param>\n        public static T ParseJson<T>(this byte[] json, JsonSerializerOptions options = null)\n        {\n            if (json == null || json.Length == 0) return default;\n\n            var result = JsonSerializer.Deserialize<T>(Encoding.Default.GetString(json), options);\n            return result;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/CommonExtensions.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Linq;\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Util Extensions Class\n    /// </summary>\n    public static class CommonExtensions\n    {\n        /// <summary>\n        /// The Gzip content type\n        /// </summary>\n        public const string GZipContentType = \"application/gzip\";\n\n        /// <summary>\n        /// The content type header\n        /// </summary>\n        public const string ContentTypeHeader = \"ContentType\";\n\n        /// <summary>\n        /// Adds the range from the elements dictionary to the source dictionary. If the element from elements dictionary alreads exists in source, it will be discarded.\n        /// </summary>\n        /// <param name=\"source\">The source dictionary.</param>\n        /// <param name=\"elements\">The elements to be added to source.</param>\n        public static void AddRange(this IDictionary<string, object> source, IDictionary<string, object> elements)\n        {\n            if (elements == null || !elements.Any()) return;\n\n            foreach (var element in elements)\n            {\n                if (!source.ContainsKey(element.Key)) source.Add(element);\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/DateTimeExtension.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Date time extensions class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class DateTimeExtension\n    {\n        /// <summary>\n        /// Converts datetime to Iso 8601 format.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <returns></returns>\n        public static string ToIso8601(this DateTime date)\n        {\n            return date.ToString(\"o\", DateTimeFormatInfo.InvariantInfo);\n        }\n\n        /// <summary>\n        /// Converts datetime to SQL invariant format.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <returns></returns>\n        public static string ToSql(this DateTime date)\n        {\n            return date.ToString(\"yyyy-MM-dd HH:mm:ss\", DateTimeFormatInfo.InvariantInfo);\n        }\n\n        /// <summary>\n        /// To the Oracle SQL date.\n        /// </summary>\n        /// <param name=\"dateTime\">The date time.</param>\n        /// <returns></returns>\n        public static string ToOracleSql(this DateTime dateTime)\n        {\n            return $\"to_date('{dateTime:dd.MM.yyyy HH:mm:ss}','dd.mm.yyyy hh24.mi.ss')\";\n        }\n\n        /// <summary>\n        /// Converts datetime to Unix format.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <returns></returns>\n        public static long ToUnix(this DateTime date)\n        {\n            var timeSpan = date - new DateTime(1970, 1, 1, 0, 0, 0);\n            return (long)timeSpan.TotalSeconds;\n        }\n\n        /// <summary>\n        /// Gets date time from unix format.\n        /// </summary>\n        /// <param name=\"unix\">The unix.</param>\n        /// <returns></returns>\n        public static DateTime FromUnix(this long unix)\n        {\n            var epoch = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);\n            return epoch.AddSeconds(unix);\n        }\n\n        /// <summary>\n        /// Gets the age from the birth date.\n        /// </summary>\n        /// <param name=\"birthDate\">The birth date.</param>\n        /// <returns></returns>\n        public static int GetAge(this DateTime birthDate)\n        {\n            var today = DateTime.Today;\n            var result = today.Year - birthDate.Year;\n\n            if (today.DayOfYear < birthDate.DayOfYear)\n            {\n                result--;\n            }\n\n            return result;\n        }\n\n        /// <summary>\n        /// Converts the datetime to a specific time zone.\n        /// </summary>\n        /// <param name=\"dateTime\">The date time.</param>\n        /// <param name=\"timeZoneId\">The time zone identifier.</param>\n        /// <returns></returns>\n        public static DateTime ToTimeZone(this DateTime dateTime, string timeZoneId)\n        {\n            var universalDateTime = dateTime.ToUniversalTime();\n            var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);\n            var convertedDateTime = TimeZoneInfo.ConvertTimeFromUtc(universalDateTime, timeZone);\n            return convertedDateTime;\n        }\n\n        /// <summary>\n        /// Determines whether this date is weekend.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified d is weekend; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsWeekend(this DateTime date)\n        {\n            return !date.IsWeekday();\n        }\n\n        /// <summary>\n        /// Determines whether this instance is weekday.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified date is weekday; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsWeekday(this DateTime date)\n        {\n            switch (date.DayOfWeek)\n            {\n                case DayOfWeek.Sunday:\n                case DayOfWeek.Saturday:\n                    return false;\n                default:\n                    return true;\n            }\n        }\n\n        /// <summary>\n        /// Adds the workdays.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <param name=\"days\">The days.</param>\n        /// <returns></returns>\n        public static DateTime AddWorkdays(this DateTime date, int days)\n        {\n            while (date.IsWeekend()) date = date.AddDays(1.0);\n            for (var i = 0; i < days; ++i)\n            {\n                date = date.AddDays(1.0);\n                while (date.IsWeekend()) date = date.AddDays(1.0);\n            }\n            return date;\n        }\n\n        /// <summary>\n        /// Gets the last day of month.\n        /// </summary>\n        /// <param name=\"date\">The date time.</param>\n        /// <returns></returns>\n        public static DateTime GetLastDayOfMonth(this DateTime date)\n        {\n            return new DateTime(date.Year, date.Month, 1).AddMonths(1).AddDays(-1);\n        }\n\n        /// <summary>\n        /// Gets the first day of month.\n        /// </summary>\n        /// <param name=\"date\">The date.</param>\n        /// <returns></returns>\n        public static DateTime GetFirstDayOfMonth(this DateTime date)\n        {\n            return new DateTime(date.Year, date.Month, 1);\n        }\n\n        /// <summary>\n        /// Get the elapsed time from date time now since the input DateTime\n        /// </summary>\n        /// <param name=\"date\">Input DateTime</param>\n        /// <returns>Returns a TimeSpan value with the elapsed time since the input DateTime</returns>\n        /// <example>\n        /// TimeSpan elapsed = dtStart.Elapsed();\n        /// </example>\n        public static TimeSpan Elapsed(this DateTime date)\n        {\n            return DateTime.Now.Subtract(date);\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/DependencyInjection/IServiceCollectionAutoMapperExtensions.cs",
    "content": "﻿using AutoMapper;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Liquid.Core.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Extensions to scan for AutoMapper classes and register the configuration, mapping, and extensions with the service collection:\n    /// <list type=\"bullet\">\n    /// <item> Finds <see cref=\"Profile\"/> classes and initializes a new <see cref=\"MapperConfiguration\" />,</item> \n    /// <item> Scans for <see cref=\"ITypeConverter{TSource,TDestination}\"/>, <see cref=\"IValueResolver{TSource,TDestination,TDestMember}\"/>, <see cref=\"IMemberValueResolver{TSource,TDestination,TSourceMember,TDestMember}\" /> and <see cref=\"IMappingAction{TSource,TDestination}\"/> implementations and registers them as <see cref=\"ServiceLifetime.Transient\"/>, </item>\n    /// <item> Registers <see cref=\"IConfigurationProvider\"/> as <see cref=\"ServiceLifetime.Singleton\"/>, and</item>\n    /// <item> Registers <see cref=\"IMapper\"/> as a configurable <see cref=\"ServiceLifetime\"/> (default is <see cref=\"ServiceLifetime.Transient\"/>)</item>\n    /// </list>\n    /// After calling LiquidAddAutoMapper you can resolve an <see cref=\"IMapper\" /> instance from a scoped service provider, or as a dependency\n    /// To use <see>\n    ///     <cref>\n    ///         QueryableExtensions.Extensions.ProjectTo{TDestination}(IQueryable,IConfigurationProvider,\n    ///         System.Linq.Expressions.Expression{System.Func{TDestination, object}}[])\n    ///     </cref>\n    /// </see>\n    /// you can resolve the <see cref=\"IConfigurationProvider\"/> instance directly for from an <see cref=\"IMapper\" /> instance.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionAutoMapperExtensions\n    {\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <returns></returns>\n        public static IServiceCollection LiquidAddAutoMapper(this IServiceCollection services, params Assembly[] assemblies)\n            => AddAutoMapperClasses(services, null, assemblies);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <returns></returns>\n        public static IServiceCollection LiquidAddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, params Assembly[] assemblies)\n            => AddAutoMapperClasses(services, (sp, cfg) => configAction?.Invoke(cfg), assemblies);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, params Assembly[] assemblies)\n            => AddAutoMapperClasses(services, configAction, assemblies);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <param name=\"serviceLifetime\">The service lifetime.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, IEnumerable<Assembly> assemblies, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\n            => AddAutoMapperClasses(services, (sp, cfg) => configAction?.Invoke(cfg), assemblies, serviceLifetime);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <param name=\"serviceLifetime\">The service lifetime.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, IEnumerable<Assembly> assemblies, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\n            => AddAutoMapperClasses(services, configAction, assemblies, serviceLifetime);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <param name=\"serviceLifetime\">The service lifetime.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, IEnumerable<Assembly> assemblies, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\n            => AddAutoMapperClasses(services, null, assemblies, serviceLifetime);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"profileAssemblyMarkerTypes\">The profile assembly marker types.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, params Type[] profileAssemblyMarkerTypes)\n            => AddAutoMapperClasses(services, null, profileAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly));\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"profileAssemblyMarkerTypes\">The profile assembly marker types.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, params Type[] profileAssemblyMarkerTypes)\n            => AddAutoMapperClasses(services, (sp, cfg) => configAction?.Invoke(cfg), profileAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly));\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"profileAssemblyMarkerTypes\">The profile assembly marker types.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, params Type[] profileAssemblyMarkerTypes)\n            => AddAutoMapperClasses(services, configAction, profileAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly));\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"profileAssemblyMarkerTypes\">The profile assembly marker types.</param>\n        /// <param name=\"serviceLifetime\">The service lifetime.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction,\n            IEnumerable<Type> profileAssemblyMarkerTypes, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\n            => AddAutoMapperClasses(services, (sp, cfg) => configAction?.Invoke(cfg), profileAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly), serviceLifetime);\n\n        /// <summary>\n        /// Adds the automatic mapper.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"profileAssemblyMarkerTypes\">The profile assembly marker types.</param>\n        /// <param name=\"serviceLifetime\">The service lifetime.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction,\n            IEnumerable<Type> profileAssemblyMarkerTypes, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\n            => AddAutoMapperClasses(services, configAction, profileAssemblyMarkerTypes.Select(t => t.GetTypeInfo().Assembly), serviceLifetime);\n\n        /// <summary>\n        /// Adds the automatic mapper classes.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"configAction\">The configuration action.</param>\n        /// <param name=\"assembliesToScan\">The assemblies to scan.</param>\n        /// <param name=\"serviceLifetime\">The service lifetime.</param>\n        /// <returns></returns>\n        private static IServiceCollection AddAutoMapperClasses(IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction,\n            IEnumerable<Assembly> assembliesToScan, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)\n        {\n            // Just return if we've already added AutoMapper to avoid double-registration\n            if (services.Any(sd => sd.ServiceType == typeof(IMapper)))\n                return services;\n\n            assembliesToScan = assembliesToScan as Assembly[] ?? assembliesToScan.ToArray();\n\n            var toScan = (Assembly[])assembliesToScan;\n            var allTypes = toScan\n                .Where(a => !a.IsDynamic && a.GetName().Name != nameof(AutoMapper))\n                .Distinct() // avoid AutoMapper.DuplicateTypeMapConfigurationException\n                .SelectMany(a => a.DefinedTypes)\n                .ToArray();\n\n            void ConfigAction(IServiceProvider serviceProvider, IMapperConfigurationExpression cfg)\n            {\n                configAction?.Invoke(serviceProvider, cfg);\n\n                cfg.AddMaps(toScan);\n            }\n\n            var openTypes = new[]\n            {\n                typeof(IValueResolver<,,>),\n                typeof(IMemberValueResolver<,,,>),\n                typeof(ITypeConverter<,>),\n                typeof(IValueConverter<,>),\n                typeof(IMappingAction<,>)\n            };\n            foreach (var type in openTypes.SelectMany(openType => allTypes\n                .Where(t => t.IsClass\n                    && !t.IsAbstract\n                    && t.AsType().ImplementGenericInterface(openType))))\n            {\n                services.AddTransientAssemblies(type.AsType());\n            }\n\n            services.AddSingleton<IConfigurationProvider>(sp => new MapperConfiguration(cfg => ConfigAction(sp, cfg)));\n            services.Add(new ServiceDescriptor(typeof(IMapper),\n                sp => new Mapper(sp.GetRequiredService<IConfigurationProvider>(), sp.GetService), serviceLifetime));\n\n            return services;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Extensions/DependencyInjection/IServiceCollectionCoreExtensions.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.PipelineBehaviors;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Reflection;\nusing FluentValidation;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System.Linq;\nusing System;\nusing Liquid.Core.Decorators;\n\nnamespace Liquid.Core.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// LiquidCache <see cref=\"IServiceCollection\"/> extensions class.\n    /// </summary>\n    public static class IServiceCollectionCoreExtensions\n    {\n        /// <summary>\n        /// Registers a <see cref=\"LiquidCache\"/> service and its <see cref=\"LiquidTelemetryInterceptor\"/> \n        /// depending on the value of <paramref name=\"withTelemetry\"/>.\n        /// </summary>\n        /// <param name=\"services\">Extended IServiceCollection.</param>\n        /// <param name=\"withTelemetry\">indicates if this method must register a <see cref=\"LiquidTelemetryInterceptor\"/></param>\n        /// <returns></returns>\n        public static IServiceCollection AddLiquidDistributedCache(this IServiceCollection services, bool withTelemetry)\n        {\n            if (withTelemetry)\n            {\n                services.AddScoped<LiquidCache>();\n                services.AddScopedLiquidTelemetry<ILiquidCache, LiquidCache>();\n            }\n            else\n                services.AddScoped<ILiquidCache, LiquidCache>();\n\n            return services;\n        }\n\n        /// <summary>\n        /// Injects mediator handler, validator and Liquid native telemetry for handlers.\n        /// </summary>\n        /// <param name=\"services\">Extended service collection.</param>\n        /// <param name=\"withTelemetry\">Indicates if method should inject Liquid Telemetry Behavior.</param>\n        /// <param name=\"withValidators\">Indicates if method should inject Validators.</param>\n        /// <param name=\"assemblies\">List of assemblies that contains handlers and validators implemantations to be injected.</param>\n        public static void AddLiquidHandlers(this IServiceCollection services, bool withTelemetry, bool withValidators, params Assembly[] assemblies)\n        {\n            if (withValidators)\n            {\n                services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LiquidValidationBehavior<,>));\n                services.AddValidatorsFromAssemblies(assemblies);\n            }\n\n            if (withTelemetry)\n                services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LiquidTelemetryBehavior<,>));\n\n            services.AddMediatR(cfg => cfg.RegisterServicesFromAssemblies(assemblies));\n        }\n\n        /// <summary>\n        /// Register Liquid Worker Service <see cref=\"AddLiquidWorkerService{TService, TEntity}(IServiceCollection)\"/>\n        /// with messaging pipeline <see cref=\"AddLiquidPipeline(IServiceCollection)\"/>,\n        /// and domain handlers <see cref=\"AddLiquidDomain(IServiceCollection, Assembly[])\"/>\n        /// that exists in <paramref name=\"assemblies\"/>, with telemetry and validators.\n        /// </summary>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"assemblies\">Array of assemblies that contains domain handlers implementation.</param>\n        /// <returns></returns>\n        public static IServiceCollection AddLiquidMessageConsumer<TWorker, TEntity>(this IServiceCollection services, params Assembly[] assemblies)\n            where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddLiquidWorkerService<TWorker, TEntity>();\n            services.AddLiquidPipeline<TEntity>();\n            services.AddLiquidDomain(assemblies);\n            return services;\n        }\n        /// <summary>\n        /// Register <see cref=\"ILiquidWorker{TEntity}\"/> implementation service  \n        /// <typeparamref name=\"TWorker\"/> and <see cref=\"LiquidBackgroundService{TEntity}\"/>.\n        /// </summary>\n        /// <typeparam name=\"TWorker\"><see cref=\"ILiquidWorker{TEntity}\"/> implementation type.</typeparam>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        public static IServiceCollection AddLiquidWorkerService<TWorker, TEntity>(this IServiceCollection services)\n            where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddScoped<ILiquidWorker<TEntity>, TWorker>();\n\n            services.AddHostedService<LiquidBackgroundService<TEntity>>();\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register domain handlers <see cref=\"AddLiquidDomain(IServiceCollection, Assembly[])\"/> and\n        /// its mappers <see cref=\"IServiceCollectionAutoMapperExtensions.LiquidAddAutoMapper(IServiceCollection, Action{AutoMapper.IMapperConfigurationExpression}, Assembly[])\"/>\n        /// that exists in <paramref name=\"assemblies\"/>, with telemetry and validators.\n        /// </summary>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"assemblies\">Array of assemblies that contains domain handlers implementation.</param>\n        public static IServiceCollection AddLiquidDomain(this IServiceCollection services, params Assembly[] assemblies)\n        {\n            services.LiquidAddAutoMapper(assemblies);\n            services.AddLiquidHandlers(withTelemetry: true, withValidators: true, assemblies);\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register <see cref=\"LiquidContext\"/> and aditional behaviors\n        /// <see cref=\"LiquidContextDecorator{TEntity}\"/>, <see cref=\"LiquidScopedLoggingDecorator{TEntity}\"/>\n        /// and <see cref=\"LiquidCultureDecorator{TEntity}\"/>. These additional behaviors will be \n        /// performed in the reverse order they were registered.\n        /// </summary>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        public static IServiceCollection AddLiquidPipeline<TEntity>(this IServiceCollection services)\n        {\n            services.AddScoped<ILiquidContext, LiquidContext>();\n            services.Decorate<ILiquidWorker<TEntity>, LiquidContextDecorator<TEntity>>();\n            services.Decorate<ILiquidWorker<TEntity>, LiquidScopedLoggingDecorator<TEntity>>();\n            services.Decorate<ILiquidWorker<TEntity>, LiquidCultureDecorator<TEntity>>();\n\n            return services;\n        }\n        /// <summary>\n        /// Changes the previously registered <typeparamref name=\"TInterface\"/> service descriptor \n        /// to the <typeparamref name=\"TDecorator\"/> service.\n        /// </summary>\n        /// <typeparam name=\"TInterface\">Interface type of service that should be decorated.</typeparam>\n        /// <typeparam name=\"TDecorator\">Type of decorator service implementation.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        public static IServiceCollection Decorate<TInterface, TDecorator>(this IServiceCollection services)\n           where TInterface : class\n           where TDecorator : class, TInterface\n        {\n            ServiceDescriptor innerDescriptor = services.FirstOrDefault(s => s.ServiceType == typeof(TInterface));\n\n            if (innerDescriptor == null) { throw new InvalidOperationException($\"{typeof(TInterface).Name} is not registered\"); }\n\n            var objectFactory = ActivatorUtilities.CreateFactory(\n              typeof(TDecorator),\n              new[] { typeof(TInterface) });\n\n            services.Replace(ServiceDescriptor.Describe(\n              typeof(TInterface),\n              s => (TInterface)objectFactory(s, new[] { s.CreateInstance(innerDescriptor) }), innerDescriptor.Lifetime)\n            );\n\n            return services;\n        }\n\n        private static object CreateInstance(this IServiceProvider services, ServiceDescriptor descriptor)\n        {\n            if (descriptor.ImplementationInstance != null)\n                return descriptor.ImplementationInstance;\n\n            if (descriptor.ImplementationFactory != null)\n                return descriptor.ImplementationFactory(services);\n\n            return ActivatorUtilities.GetServiceOrCreateInstance(services, descriptor.ImplementationType);\n        }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/DependencyInjection/IServiceCollectionLiquidExtension.cs",
    "content": "﻿using Castle.DynamicProxy;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System;\nusing System.Linq;\n\nnamespace Liquid.Core.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Extends <see cref=\"IServiceCollection\"/> interface.\n    /// </summary>\n    public static class IServiceCollectionLiquidExtension\n    {\n        \n        /// <summary>\n        /// Register telemetry interceptor <see cref=\"LiquidTelemetryInterceptor\"/> for defined <typeparamref name=\"TService\"/> services. \n        /// </summary>\n        /// <typeparam name=\"TInterface\">Interface type of service that should be intercepted.</typeparam>\n        /// <typeparam name=\"TService\">Type of service that should be intercepted.</typeparam>\n        /// <param name=\"services\">Extended IServiceCollection instance.</param>\n        [Obsolete(\"This method will be removed in the next release. \" +\n            \"Please use AddScopedLiquidTelemetry, AddTransientLiquidTelemetry or AddSingletonLiquidTelemetry.\")]\n        public static IServiceCollection AddLiquidTelemetryInterceptor<TInterface, TService>(this IServiceCollection services)\n            where TInterface : class where TService : TInterface\n        {\n            services.TryAddTransient(typeof(IAsyncInterceptor), typeof(LiquidTelemetryInterceptor));\n\n            services.TryAddSingleton(new ProxyGenerator());\n\n            return services.AddTransient((provider) =>\n            {\n                var proxyGenerator = provider.GetService<ProxyGenerator>();\n                var service = (TInterface)provider.GetRequiredService<TService>();\n\n                return proxyGenerator.CreateInterfaceProxyWithTarget(service, provider.GetServices<IAsyncInterceptor>().ToArray());\n            });\n        }\n\n        /// <summary>\n        /// Register telemetry interceptor <see cref=\"LiquidTelemetryInterceptor\"/> for defined <typeparamref name=\"TService\"/> services. \n        /// </summary>\n        /// <typeparam name=\"TInterface\">Interface type of service that should be intercepted.</typeparam>\n        /// <typeparam name=\"TService\">Type of service that should be intercepted.</typeparam>\n        /// <param name=\"services\">Extended IServiceCollection instance.</param>\n        public static IServiceCollection AddScopedLiquidTelemetry<TInterface, TService>(this IServiceCollection services)\n            where TInterface : class where TService : TInterface\n        {\n            services.AddInterceptor<LiquidTelemetryInterceptor>();\n\n            return services.AddScoped((provider) =>\n            {\n                var proxyGenerator = provider.GetService<ProxyGenerator>();\n                var service = (TInterface)provider.GetRequiredService<TService>();\n\n                return proxyGenerator.CreateInterfaceProxyWithTarget(service, provider.GetServices<IAsyncInterceptor>().ToArray());\n            });\n        }\n\n        /// <summary>\n        /// Register telemetry interceptor <see cref=\"LiquidTelemetryInterceptor\"/> for defined <typeparamref name=\"TService\"/> services. \n        /// </summary>\n        /// <typeparam name=\"TInterface\">Interface type of service that should be intercepted.</typeparam>\n        /// <typeparam name=\"TService\">Type of service that should be intercepted.</typeparam>\n        /// <param name=\"services\">Extended IServiceCollection instance.</param>\n        public static IServiceCollection AddTransientLiquidTelemetry<TInterface, TService>(this IServiceCollection services)\n            where TInterface : class where TService : TInterface\n        {\n            services.AddInterceptor<LiquidTelemetryInterceptor>();\n\n            return services.AddTransient((provider) =>\n            {\n                var proxyGenerator = provider.GetService<ProxyGenerator>();\n                var service = (TInterface)provider.GetRequiredService<TService>();\n\n                return proxyGenerator.CreateInterfaceProxyWithTarget(service, provider.GetServices<IAsyncInterceptor>().ToArray());\n            });\n        }\n\n        /// <summary>\n        /// Register telemetry interceptor <see cref=\"LiquidTelemetryInterceptor\"/> for defined <typeparamref name=\"TService\"/> services. \n        /// </summary>\n        /// <typeparam name=\"TInterface\">Interface type of service that should be intercepted.</typeparam>\n        /// <typeparam name=\"TService\">Type of service that should be intercepted.</typeparam>\n        /// <param name=\"services\">Extended IServiceCollection instance.</param>\n        public static IServiceCollection AddSingletonLiquidTelemetry<TInterface, TService>(this IServiceCollection services)\n            where TInterface : class where TService : TInterface\n        {\n            services.AddInterceptor<LiquidTelemetryInterceptor>();\n\n            return services.AddSingleton((provider) =>\n            {\n                var proxyGenerator = provider.GetService<ProxyGenerator>();\n                var service = (TInterface)provider.GetRequiredService<TService>();\n\n                return proxyGenerator.CreateInterfaceProxyWithTarget(service, provider.GetServices<IAsyncInterceptor>().ToArray());\n            });\n        }\n\n        /// <summary>\n        /// Register a <typeparamref name=\"TInterceptor\"/> service instance\n        /// with <see cref=\"IAsyncInterceptor\"/> service type.\n        /// </summary>\n        /// <typeparam name=\"TInterceptor\">Service implementation type.</typeparam>\n        /// <param name=\"services\">Extended IServiceCollection instance.</param>\n        public static IServiceCollection AddInterceptor<TInterceptor>(this IServiceCollection services)\n        {\n            services.TryAddTransient(typeof(IAsyncInterceptor), typeof(TInterceptor));\n\n            services.TryAddSingleton(new ProxyGenerator());\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register Liquid implementation of Serializer services and Serializer provider. \n        /// <see cref=\"LiquidJsonSerializer\"/>, <see cref=\"LiquidXmlSerializer\"/> and <see cref=\"LiquidSerializerProvider\"/>\n        /// </summary>\n        /// <param name=\"services\">Extended IServiceCollection instance.</param>\n        public static IServiceCollection AddLiquidSerializers(this IServiceCollection services)\n        {\n            services.AddTransient<ILiquidSerializer, LiquidJsonSerializer>();\n            services.AddTransient<ILiquidSerializer, LiquidXmlSerializer>();\n            services.AddTransient<ILiquidSerializerProvider, LiquidSerializerProvider>();\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Extensions/DependencyInjection/IServiceCollectionTypeExtensions.cs",
    "content": "﻿using Liquid.Core.Utils;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Liquid.Core.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Service Collection Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionTypeExtensions\n    {\n        /// <summary>\n        /// Adds a scoped service of the type specified in <paramref name=\"serviceType\" /> with an\n        /// implementation of the types specified inside <paramref name=\"assemblies\" /> to the\n        /// specified <see cref=\"IServiceCollection\" />.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\" /> to add the service to.</param>\n        /// <param name=\"serviceType\">The type of the service to register.</param>\n        /// <param name=\"assemblies\">The assemblies that contains all implementation types.</param>\n        /// <seealso cref=\"ServiceLifetime.Scoped\" />\n        public static IServiceCollection AddScopedAssemblies(this IServiceCollection services, Type serviceType, params Assembly[] assemblies)\n        {\n            var typesToRegister = TypeUtils.GetTypesToRegister(serviceType, assemblies);\n\n            foreach (var typeToRegister in typesToRegister)\n            {\n                var interfaces = typeToRegister.GetInterfaces();\n                var interfaceToRegister = interfaces.FirstOrDefault(t => t.GetGenericTypeDefinition() == serviceType);\n\n                if (interfaceToRegister != null)\n                {\n                    services.AddScoped(interfaceToRegister, typeToRegister);\n                }\n            }\n            return services;\n        }\n\n        /// <summary>\n        /// Adds a scoped service of the type specified in <paramref name=\"serviceType\" /> with an\n        /// implementation of the types specified in <paramref name=\"implementationTypes\" /> to the\n        /// specified <see cref=\"IServiceCollection\" />.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\" /> to add the service to.</param>\n        /// <param name=\"serviceType\">The type of the service to register.</param>\n        /// <param name=\"implementationTypes\">The implementation types.</param>\n        /// <seealso cref=\"ServiceLifetime.Scoped\" />\n        public static IServiceCollection AddScopedAssemblies(this IServiceCollection services, Type serviceType, IEnumerable<Type> implementationTypes)\n        {\n            foreach (var typeToRegister in implementationTypes)\n            {\n                var interfaces = typeToRegister.GetInterfaces();\n                var interfaceToRegister = interfaces.FirstOrDefault(t => t.GetGenericTypeDefinition() == serviceType);\n\n                if (interfaceToRegister != null)\n                {\n                    services.AddScoped(interfaceToRegister, typeToRegister);\n                }\n            }\n            return services;\n        }\n\n        /// <summary>\n        /// Adds a transient service of the type specified in <paramref name=\"serviceType\" /> with an\n        /// implementation of the types specified inside <paramref name=\"assemblies\" /> to the\n        /// specified <see cref=\"IServiceCollection\" />.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\" /> to add the service to.</param>\n        /// <param name=\"serviceType\">The type of the service to register.</param>\n        /// <param name=\"assemblies\">The assemblies that contains all implementation types.</param>\n        /// <seealso cref=\"ServiceLifetime.Transient\" />\n        public static IServiceCollection AddTransientAssemblies(this IServiceCollection services, Type serviceType, params Assembly[] assemblies)\n        {\n            var typesToRegister = TypeUtils.GetTypesToRegister(serviceType, assemblies);\n\n            foreach (var typeToRegister in typesToRegister)\n            {\n                var interfaces = typeToRegister.GetInterfaces();\n                var interfaceToRegister = interfaces.FirstOrDefault(t => t.GetGenericTypeDefinition() == serviceType);\n\n                if (interfaceToRegister != null)\n                {\n                    services.AddTransient(interfaceToRegister, typeToRegister);\n                }\n            }\n            return services;\n        }\n\n        /// <summary>\n        /// Adds a transient service of the type specified in <paramref name=\"serviceType\" /> with an\n        /// implementation of the types specified in <paramref name=\"implementationTypes\" /> to the\n        /// specified <see cref=\"IServiceCollection\" />.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\" /> to add the service to.</param>\n        /// <param name=\"serviceType\">The type of the service to register.</param>\n        /// <param name=\"implementationTypes\">The implementation types.</param>\n        /// <seealso cref=\"ServiceLifetime.Transient\" />\n        public static IServiceCollection AddTransientAssemblies(this IServiceCollection services, Type serviceType, IEnumerable<Type> implementationTypes)\n        {\n            foreach (var typeToRegister in implementationTypes)\n            {\n                var interfaces = typeToRegister.GetInterfaces();\n                var interfaceToRegister = interfaces.FirstOrDefault(t => t.GetGenericTypeDefinition() == serviceType);\n\n                if (interfaceToRegister != null)\n                {\n                    services.AddTransient(interfaceToRegister, typeToRegister);\n                }\n            }\n            return services;\n        }\n\n        /// <summary>\n        /// Adds a singleton service of the type specified in <paramref name=\"serviceType\" /> with an\n        /// implementation of the types specified inside <paramref name=\"assemblies\" /> to the\n        /// specified <see cref=\"IServiceCollection\" />.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\" /> to add the service to.</param>\n        /// <param name=\"serviceType\">The type of the service to register.</param>\n        /// <param name=\"assemblies\">The assemblies that contains all implementation types.</param>\n        /// <seealso cref=\"ServiceLifetime.Singleton\" />\n        public static IServiceCollection AddSingletonAssemblies(this IServiceCollection services, Type serviceType, params Assembly[] assemblies)\n        {\n            var typesToRegister = TypeUtils.GetTypesToRegister(serviceType, assemblies);\n\n            foreach (var typeToRegister in typesToRegister)\n            {\n                var interfaces = typeToRegister.GetInterfaces();\n                var interfaceToRegister = interfaces.FirstOrDefault(t => t.GetGenericTypeDefinition() == serviceType);\n\n                if (interfaceToRegister != null)\n                {\n                    services.AddSingleton(interfaceToRegister, typeToRegister);\n                }\n            }\n            return services;\n        }\n\n        /// <summary>\n        /// Adds a singleton service of the type specified in <paramref name=\"serviceType\" /> with an\n        /// implementation of the types specified in <paramref name=\"implementationTypes\" /> to the\n        /// specified <see cref=\"IServiceCollection\" />.\n        /// </summary>\n        /// <param name=\"services\">The <see cref=\"IServiceCollection\" /> to add the service to.</param>\n        /// <param name=\"serviceType\">The type of the service to register.</param>\n        /// <param name=\"implementationTypes\">The implementation types.</param>\n        /// <seealso cref=\"ServiceLifetime.Singleton\" />\n        public static IServiceCollection AddSingletonAssemblies(this IServiceCollection services, Type serviceType, IEnumerable<Type> implementationTypes)\n        {\n            foreach (var typeToRegister in implementationTypes)\n            {\n                var interfaces = typeToRegister.GetInterfaces();\n                var interfaceToRegister = interfaces.FirstOrDefault(t => t.GetGenericTypeDefinition() == serviceType);\n\n                if (interfaceToRegister != null)\n                {\n                    services.AddSingleton(interfaceToRegister, typeToRegister);\n                }\n            }\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/DependencyInjection/IServiceProviderExtensions.cs",
    "content": "﻿using Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Service Provider Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceProviderExtensions\n    {\n        /// <summary>\n        /// Get all registered <see cref=\"ServiceDescriptor\"/>\n        /// </summary>\n        /// <param name=\"provider\"></param>\n        /// <returns></returns>\n        public static Dictionary<Type, ServiceDescriptor> GetAllServiceDescriptors(this IServiceProvider provider)\n        {\n            if (provider is ServiceProvider serviceProvider)\n            {\n                var result = new Dictionary<Type, ServiceDescriptor>();\n\n                var engine = serviceProvider.GetFieldValue(\"_engine\");\n                var callSiteFactory = engine.GetPropertyValue(\"CallSiteFactory\");\n                var descriptorLookup = callSiteFactory.GetFieldValue(\"_descriptorLookup\");\n                if (descriptorLookup is IDictionary dictionary)\n                {\n                    foreach (DictionaryEntry entry in dictionary)\n                    {\n                        result.Add((Type)entry.Key, (ServiceDescriptor)entry.Value.GetPropertyValue(\"Last\"));\n                    }\n                }\n\n                return result;\n            }\n\n            throw new NotSupportedException($\"Type '{provider.GetType()}' is not supported!\");\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Extensions/EnumExtension.cs",
    "content": "﻿using System;\nusing System.ComponentModel;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Enum Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class EnumExtension\n    {\n        /// <summary>\n        /// Gets the description from enum value.\n        /// </summary>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>The enum description.</returns>\n        public static string GetDescription(this Enum value)\n        {\n            var attribute = value.GetType()\n                .GetField(value.ToString())\n                .GetCustomAttributes(typeof(DescriptionAttribute), false)\n                .SingleOrDefault() as DescriptionAttribute;\n            return attribute == null ? value.ToString() : attribute.Description;\n        }\n\n        /// <summary>\n        /// Gets the enum attribute.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>the enum attribute.</returns>\n        public static T GetAttribute<T>(this Enum value) where T : Attribute\n        {\n            var type = value.GetType();\n            var name = Enum.GetName(type, value);\n\n            return type.GetField(name)\n                .GetCustomAttributes(false)\n                .OfType<T>()\n                .SingleOrDefault();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Extensions/IEnumerableExtension.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Text;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Extensions for IEnumerable class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IEnumerableExtension\n    {\n        /// <summary>\n        /// Executes the action in each specified item in enumerable.\n        /// </summary>\n        /// <typeparam name=\"T\">Type of element inside enumerable.</typeparam>\n        /// <param name=\"enumerable\">The enumerable.</param>\n        /// <param name=\"action\">The action.</param>\n        public static void Each<T>(this IEnumerable<T> enumerable, Action<T> action)\n        {\n            foreach (var item in enumerable)\n            {\n                action(item);\n            }\n        }\n\n        /// <summary>\n        /// Produces a comma separated values of string out of an IEnumerable. \n        /// This would be useful if you want to automatically generate a CSV out of integer, string, or any other primitive data type collection or array. \n        /// </summary>\n        /// <typeparam name=\"T\">Type of element inside enumerable.</typeparam>\n        /// <param name=\"instance\">The instance.</param>\n        /// <param name=\"separator\">The separator.</param>\n        /// <returns></returns>\n        public static string ToSeparatedString<T>(this IEnumerable<T> instance, char separator)\n        {\n            var array = instance?.ToArray();\n            if (array == null || !array.Any()) return null;\n\n            var csv = new StringBuilder();\n            array.Each(value => csv.AppendFormat(\"{0}{1}\", value, separator));\n            return csv.ToString(0, csv.Length - 1);\n        }\n\n        /// <summary>\n        /// Produces a comma separated values of string out of an IEnumerable. \n        /// This would be useful if you want to automatically generate a CSV out of integer, string, or any other primitive data type collection or array. \n        /// </summary>\n        /// <typeparam name=\"T\">Type of element inside enumerable.</typeparam>\n        /// <param name=\"instance\">The instance.</param>\n        /// <returns></returns>\n        public static string ToSeparatedString<T>(this IEnumerable<T> instance)\n        {\n            return instance.ToSeparatedString(',');\n        }\n\n        /// <summary>\n        /// Determines whether this collection is null or empty.\n        /// </summary>\n        /// <typeparam name=\"T\">Type of element in collection.</typeparam>\n        /// <param name=\"collection\">The collection.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified collection is null or empty; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsNullOrEmpty<T>(this IEnumerable<T> collection)\n        {\n            return collection == null || !collection.Any();\n        }\n\n        /// <summary>\n        /// Determines whether a enumerable is not null or empty.\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"collection\">The collection.</param>\n        /// <returns>\n        ///   <c>true</c> if [is not null or empty] [the specified collection]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsNotNullOrEmpty<T>(this IEnumerable<T> collection)\n        {\n            return collection != null && collection.Any();\n        }\n\n        /// <summary>\n        /// Orders the enumerable based on a property ASC or DESC. Example \"OrderBy(\"Name desc\")\"\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"list\">The list.</param>\n        /// <param name=\"sortExpression\">The sort expression.</param>\n        /// <returns></returns>\n        /// <exception cref=\"Exception\">No property '\" + property + \"' in + \" + typeof(T).Name + \"'</exception>\n        public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> list, string sortExpression)\n        {\n            sortExpression += \"\";\n            var parts = sortExpression.Split(' ');\n            var descending = false;\n\n            if (parts.Length > 0 && parts[0] != \"\")\n            {\n                var property = parts[0];\n\n                if (parts.Length > 1)\n                {\n                    descending = parts[1].ToLower().Contains(\"desc\");\n                }\n\n                var prop = typeof(T).GetProperty(property);\n\n                if (prop == null)\n                {\n                    throw new LiquidException(\"No property '\" + property + \"' in + \" + typeof(T).Name + \"'\");\n                }\n\n                return descending ? list.OrderByDescending(x => prop.GetValue(x, null)) : list.OrderBy(x => prop.GetValue(x, null));\n            }\n\n            return list;\n        }\n    }\n\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/IntExtension.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Utils\n{\n    /// <summary>\n    /// Number Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IntExtension\n    {\n        /// <summary>\n        /// Determines whether a number is is prime number.\n        /// </summary>\n        /// <param name=\"number\">The number.</param>\n        /// <returns>\n        ///   <c>true</c> if [is prime number] [the specified number]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsPrimeNumber(this int number)\n        {\n            if (number % 2 == 0)\n            {\n                return number == 2;\n            }\n            var sqrt = (int)Math.Sqrt(number);\n            for (var t = 3; t <= sqrt; t += 2)\n            {\n                if (number % t == 0)\n                {\n                    return false;\n                }\n            }\n            return number != 1;\n        }\n\n        /// <summary>\n        /// Determines whether a number is odd.\n        /// </summary>\n        /// <param name=\"number\">The number.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified number is odd; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsOdd(this int number)\n        {\n            return number % 2 == 0;\n        }\n\n        /// <summary>\n        /// Determines whether a number is even.\n        /// </summary>\n        /// <param name=\"number\">The number.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified number is even; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsEven(this int number)\n        {\n            return number % 2 != 0;\n        }\n\n        /// <summary>\n        /// Format a double using the local culture currency settings.\n        /// </summary>\n        /// <param name=\"value\">The double to be formatted.</param>\n        /// <returns>The double formatted based on the local culture currency settings.</returns>\n        public static string ToLocalCurrencyString(this double value)\n        {\n            return $\"{value:C}\";\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/ObjectExtension.cs",
    "content": "﻿using Liquid.Core.Utils;\nusing System;\nusing System.Globalization;\nusing System.IO;\nusing System.Runtime.Serialization.Formatters.Binary;\nusing System.Text;\nusing System.Text.Json;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Object extensions class.\n    /// </summary>\n    public static class ObjectExtension\n    {\n        /// <summary>\n        /// Determines whether [is of type] [the specified value].\n        /// </summary>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <param name=\"value\">The value.</param>\n        /// <returns>\n        ///   <c>true</c> if [is of type] [the specified value]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsOfType<T>(this object value)\n        {\n            return value is T;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is datetime.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified expression is datetime; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsDatetime(this object expression)\n        {\n            return expression.ToDatetime(out DateTime? _);\n        }\n\n        /// <summary>\n        /// Converts object to date time.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <param name=\"outer\">The outer.</param>\n        /// <returns></returns>\n        public static bool ToDatetime(this object expression, out DateTime? outer)\n        {\n            outer = null;\n            if (expression == null)\n                return false;\n\n            if (expression.IsOfType<DateTime>())\n                return true;\n\n            if (DateTime.TryParseExact(\n                Convert.ToString(expression, CultureInfo.InvariantCulture),\n                DateTimeFormatInfo.CurrentInfo?.GetAllDateTimePatterns('d'),\n                CultureInfo.CurrentCulture, DateTimeStyles.None, out var parsed))\n                outer = parsed;\n\n            return outer.HasValue;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is boolean.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified expression is boolean; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsBoolean(this object expression)\n        {\n            return expression.ToBoolean(out bool? _);\n        }\n\n        /// <summary>\n        /// Converts object to boolean.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <param name=\"outer\">The outer.</param>\n        /// <returns></returns>\n        public static bool ToBoolean(this object expression, out bool? outer)\n        {\n            outer = null;\n            if (expression == null)\n                return false;\n\n            if (bool.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture), out var parsed))\n                outer = parsed;\n            return outer.HasValue;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is unique identifier.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified expression is unique identifier; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsGuid(this object expression)\n        {\n            return expression.ToGuid(out _);\n        }\n\n        /// <summary>\n        /// Converts object to  unique identifier.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <param name=\"outer\">The outer.</param>\n        /// <returns></returns>\n        private static bool ToGuid(this object expression, out Guid? outer)\n        {\n            outer = null;\n            if (expression == null)\n                return false;\n\n            if (Guid.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture), out var parsed))\n                outer = parsed;\n            return outer.HasValue;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is numeric.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified expression is numeric; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsNumeric(this object expression)\n        {\n            return expression != null && double.TryParse(expression.ToString(), out _);\n        }\n\n        /// <summary>\n        /// Determines whether this instance is integer.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified expression is integer; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsInteger(this object expression)\n        {\n            return expression.ToInteger(out long? _);\n        }\n\n        /// <summary>\n        /// Converts object to integer.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <param name=\"outer\">The outer.</param>\n        /// <returns></returns>\n        public static bool ToInteger(this object expression, out long? outer)\n        {\n            outer = null;\n            if (expression == null)\n                return false;\n\n            if (long.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture),\n                NumberStyles.Integer | NumberStyles.AllowParentheses | NumberStyles.AllowThousands | NumberStyles.AllowTrailingSign,\n                CultureInfo.InvariantCulture, out var parsed))\n                outer = parsed;\n            return outer.HasValue;\n        }\n\n        /// <summary>\n        /// Determines whether this instance is double.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified expression is double; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsDouble(this object expression)\n        {\n            return expression.ToDouble(out double? _);\n        }\n\n        /// <summary>\n        /// Converts object to double.\n        /// </summary>\n        /// <param name=\"expression\">The expression.</param>\n        /// <param name=\"outer\">The outer.</param>\n        /// <returns></returns>\n        public static bool ToDouble(this object expression, out double? outer)\n        {\n            outer = null;\n            if (expression == null)\n                return false;\n\n            if (double.TryParse(Convert.ToString(expression, CultureInfo.InvariantCulture),\n                NumberStyles.AllowThousands | NumberStyles.AllowTrailingSign | NumberStyles.Currency | NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed))\n                outer = parsed;\n            return outer.HasValue;\n        }\n\n        /// <summary>\n        /// Determines whether [is primitive type].\n        /// </summary>\n        /// <param name=\"obj\">The object.</param>\n        /// <returns>\n        ///   <c>true</c> if [is primitive type] [the specified object]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsPrimitiveType(this object obj)\n        {\n            return obj.GetType().IsPrimitive;\n        }\n\n        /// <summary>\n        /// Converts the object to json string.\n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <param name=\"options\">Provides options to be used with System.Text.Json.JsonSerializer.</param>\n        public static string ToJsonString(this object source, JsonSerializerOptions options = null)\n        {\n            return source == null ? null : JsonSerializer.Serialize(source, options);\n        }\n\n        /// <summary>\n        /// Converts the object to json bytes.\n        /// </summary>\n        /// <param name=\"source\"></param>\n        /// <param name=\"options\">Provides options to be used with System.Text.Json.JsonSerializer.</param>\n        public static byte[] ToJsonBytes(this object source, JsonSerializerOptions options = null)\n        {\n            if (source == null)\n                return new byte[0];\n            var instring = JsonSerializer.Serialize(source, options);\n\n            return Encoding.Default.GetBytes(instring);\n        }\n        /// <summary>\n        /// Gets the field value.\n        /// </summary>\n        /// <param name=\"obj\">The object.</param>\n        /// <param name=\"fieldName\">Name of the field.</param>\n        /// <returns></returns>\n        /// <exception cref=\"ArgumentNullException\">obj</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Couldn't find field {fieldName} in type {objType.FullName}</exception>\n        public static object GetFieldValue(this object obj, string fieldName)\n        {\n            ArgumentNullException.ThrowIfNull(obj);\n\n            Type objType = obj.GetType();\n            var fieldInfo = TypeUtils.GetFieldInfo(objType, fieldName);\n            if (fieldInfo == null)\n                throw new ArgumentOutOfRangeException(fieldName,\n                    $\"Couldn't find field {fieldName} in type {objType.FullName}\");\n            return fieldInfo.GetValue(obj);\n        }\n\n        /// <summary>\n        /// Sets the field value.\n        /// </summary>\n        /// <param name=\"obj\">The object.</param>\n        /// <param name=\"fieldName\">Name of the field.</param>\n        /// <param name=\"val\">The value.</param>\n        /// <exception cref=\"ArgumentNullException\">obj</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Couldn't find field {fieldName} in type {objType.FullName}</exception>\n        public static void SetFieldValue(this object obj, string fieldName, object val)\n        {\n            ArgumentNullException.ThrowIfNull(obj);\n\n            Type objType = obj.GetType();\n            var fieldInfo = TypeUtils.GetFieldInfo(objType, fieldName);\n            if (fieldInfo == null)\n                throw new ArgumentOutOfRangeException(fieldName,\n                    $\"Couldn't find field {fieldName} in type {objType.FullName}\");\n            fieldInfo.SetValue(obj, val);\n        }\n\n        /// <summary>\n        /// Gets the property value.\n        /// </summary>\n        /// <param name=\"obj\">The object.</param>\n        /// <param name=\"propertyName\">Name of the property.</param>\n        /// <returns></returns>\n        /// <exception cref=\"ArgumentNullException\">obj</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Couldn't find property {propertyName} in type {objType.FullName}</exception>\n        public static object GetPropertyValue(this object obj, string propertyName)\n        {\n            ArgumentNullException.ThrowIfNull(obj);\n\n            Type objType = obj.GetType();\n            var propertyInfo = TypeUtils.GetPropertyInfo(objType, propertyName);\n            if (propertyInfo == null)\n                throw new ArgumentOutOfRangeException(propertyName,\n                    $\"Couldn't find property {propertyName} in type {objType.FullName}\");\n            return propertyInfo.GetValue(obj, null);\n        }\n\n        /// <summary>\n        /// Sets the property value.\n        /// </summary>\n        /// <param name=\"obj\">The object.</param>\n        /// <param name=\"propertyName\">Name of the property.</param>\n        /// <param name=\"val\">The value.</param>\n        /// <exception cref=\"ArgumentNullException\">obj</exception>\n        /// <exception cref=\"ArgumentOutOfRangeException\">Couldn't find property {propertyName} in type {objType.FullName}</exception>\n        public static void SetPropertyValue(this object obj, string propertyName, object val)\n        {\n            ArgumentNullException.ThrowIfNull(obj);\n\n            Type objType = obj.GetType();\n            var propertyInfo = TypeUtils.GetPropertyInfo(objType, propertyName);\n            if (propertyInfo == null)\n                throw new ArgumentOutOfRangeException(propertyName,\n                    $\"Couldn't find property {propertyName} in type {objType.FullName}\");\n            propertyInfo.SetValue(obj, val, null);\n        }\n    }\n}\n\n"
  },
  {
    "path": "src/Liquid.Core/Extensions/StreamExtension.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.Text;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// Stream extensions class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class StreamExtension\n    {\n        /// <summary>\n        /// Gets the string from UTF8 stream.\n        /// </summary>\n        /// <param name=\"source\">The stream source.</param>\n        /// <returns>The result string from stream.</returns>\n        public static string AsStringUtf8(this Stream source)\n        {\n            if (source == null) return null;\n            string documentContents;\n            using (var readStream = new StreamReader(source, Encoding.UTF8))\n            {\n                documentContents = readStream.ReadToEnd();\n            }\n\n            return documentContents;\n        }\n\n        /// <summary>\n        /// Gets the string from ASCII stream.\n        /// </summary>\n        /// <param name=\"source\">The stream source.</param>\n        /// <returns>The result string from stream.</returns>\n        public static string AsStringAscii(this Stream source)\n        {\n            if (source == null) return null;\n            string documentContents;\n            using (var readStream = new StreamReader(source, Encoding.ASCII))\n            {\n                documentContents = readStream.ReadToEnd();\n            }\n\n            return documentContents;\n        }\n\n        /// <summary>\n        /// Gets the string from UNICODE stream.\n        /// </summary>\n        /// <param name=\"source\">The stream source.</param>\n        /// <returns>The result string from stream.</returns>\n        public static string AsStringUnicode(this Stream source)\n        {\n            if (source == null) return null;\n            string documentContents;\n            using (var readStream = new StreamReader(source, Encoding.Unicode))\n            {\n                documentContents = readStream.ReadToEnd();\n            }\n            return documentContents;\n        }\n\n        /// <summary>\n        /// Converts a stream to byte array.\n        /// </summary>\n        /// <param name=\"stream\">The stream.</param>\n        /// <returns></returns>\n        public static byte[] ToByteArray(this Stream stream)\n        {\n            using var ms = new MemoryStream();\n            stream.CopyTo(ms);\n            return ms.ToArray();\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/StringExtension.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.Security.Cryptography;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.RegularExpressions;\nusing System.Xml;\nusing System.Xml.Serialization;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// String Extensions Class.\n    /// </summary>\n    /// \n    [ExcludeFromCodeCoverage]\n    public static class StringExtension\n    {       \n\n        /// <summary>\n        /// Determines whether a string contains a specified value.\n        /// </summary>\n        /// <param name=\"source\">The string source.</param>\n        /// <param name=\"value\">The value to compare.</param>\n        /// <param name=\"comparisonType\">Type of the comparison.</param>\n        /// <returns>\n        ///   <c>true</c> if source contains the specified value; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool Contains(this string source, string value, StringComparison comparisonType = StringComparison.InvariantCultureIgnoreCase)\n        {\n            return source.IndexOf(value, comparisonType) >= 0;\n        }\n\n        /// <summary>\n        /// Removes the line endings.\n        /// </summary>\n        /// <param name=\"value\">The string value.</param>\n        /// <returns>The string without line endings.</returns>\n        public static string RemoveLineEndings(this string value)\n        {\n            if (string.IsNullOrEmpty(value)) { return value; }\n\n            var lineSeparator = ((char)0x2028).ToString();\n            var paragraphSeparator = ((char)0x2029).ToString();\n\n            return value.Replace(\"\\r\\n\", string.Empty)\n                        .Replace(\"\\n\", string.Empty)\n                        .Replace(\"\\r\", string.Empty)\n                        .Replace(lineSeparator, string.Empty)\n                        .Replace(paragraphSeparator, string.Empty);\n        }\n\n        /// <summary>\n        /// Converts the string representation of a Guid to its Guid \n        /// equivalent. A return value indicates whether the operation \n        /// succeeded. \n        /// </summary>\n        /// <param name=\"guid\">A string containing a Guid to convert.</param>\n        /// <value>\n        /// <see langword=\"true\" /> if <paramref name=\"guid\"/> was converted \n        /// successfully; otherwise, <see langword=\"false\" />.\n        /// </value>\n        /// <remarks>\n        /// When this method returns, contains the Guid value equivalent to \n        /// the Guid contained in <paramref name=\"guid\"/>, if the conversion \n        /// succeeded, or <see cref=\"Guid.Empty\"/> if the conversion failed. \n        /// The conversion fails if the <paramref name=\"guid\"/> parameter is a \n        /// <see langword=\"null\" /> reference (<see langword=\"Nothing\" /> in \n        /// Visual Basic), or is not of the correct format.  \n        /// </remarks>\n        public static bool IsGuid(this string guid)\n        {\n            return guid != null && Guid.TryParse(guid, out _);\n        }\n\n        /// <summary>\n        /// Determines whether this string is a valid http url.\n        /// </summary>\n        /// <param name=\"str\">The string.</param>\n        /// <returns>\n        ///   <c>true</c> if [is valid URL] [the specified text]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsValidHttpUrl(this string str)\n        {\n            return Uri.TryCreate(str, UriKind.Absolute, out _);\n        }\n\n        /// <summary>\n        /// Appends to the string builder if matchers the condition.\n        /// </summary>\n        /// <param name=\"builder\">The builder.</param>\n        /// <param name=\"value\">The value.</param>\n        /// <param name=\"condition\">if set to <c>true</c> appends to string builder.</param>\n        /// <returns></returns>\n        public static StringBuilder AppendIf(this StringBuilder builder, string value, bool condition)\n        {\n            if (condition) builder.Append(value);\n            return builder;\n        }\n\n        /// <summary>\n        /// Converts a string to guid.\n        /// </summary>\n        /// <param name=\"str\">The string.</param>\n        /// <returns></returns>\n        public static Guid ToGuid(this string str)\n        {\n            Guid.TryParse(str, out var returnValue);\n            return returnValue;\n        }\n\n        /// <summary>\n        /// Converts string to enum object\n        /// </summary>\n        /// <typeparam name=\"T\">Type of enum</typeparam>\n        /// <param name=\"value\">String value to convert</param>\n        /// <returns>Returns enum object</returns>\n        public static T ToEnum<T>(this string value) where T : struct\n        {\n            return (T)Enum.Parse(typeof(T), value, true);\n        }\n\n        /// <summary>\n        /// Computes the hash of the string using a specified hash algorithm\n        /// </summary>\n        /// <param name=\"input\">The string to hash</param>\n        /// <param name=\"key\">The hash key.</param>\n        /// <param name=\"hashType\">The hash algorithm to use</param>\n        /// <returns>\n        /// The resulting hash or an empty string on error\n        /// </returns>\n        public static string CreateHash(this string input, string key, HashType hashType)\n        {\n            try\n            {\n                var hash = GetComputedHash(input, key, hashType);\n                var ret = new StringBuilder();\n\n                foreach (var hashByte in hash)\n                    ret.Append(hashByte.ToString(\"x2\"));\n\n                return ret.ToString();\n            }\n            catch\n            {\n                return string.Empty;\n            }\n        }\n\n        /// <summary>\n        /// Gets the hash.\n        /// </summary>\n        /// <param name=\"input\">The input.</param>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"hash\">The hash.</param>\n        /// <returns></returns>\n        private static byte[] GetComputedHash(string input, string key, HashType hash)\n        {\n            var inputBytes = Encoding.UTF8.GetBytes(input);\n            var inputKey = Encoding.UTF8.GetBytes(key);\n\n            return hash switch\n            {\n                HashType.HMacSha256 => new HMACSHA256(inputKey).ComputeHash(inputBytes),\n                HashType.HMacSha384 => new HMACSHA384(inputKey).ComputeHash(inputBytes),\n                HashType.HMacSha512 => new HMACSHA512(inputKey).ComputeHash(inputBytes),\n                HashType.Sha256 => SHA256.Create().ComputeHash(inputBytes),\n                HashType.Sha384 => SHA384.Create().ComputeHash(inputBytes),\n                HashType.Sha512 => SHA512.Create().ComputeHash(inputBytes),\n                _ => inputBytes,\n            };\n        }\n\n        /// <summary>\n        /// Parses a string json to a specific object.\n        /// </summary>\n        /// <typeparam name=\"T\">type of object to be parsed.</typeparam>\n        /// <param name=\"json\"></param>\n        /// <param name=\"options\">Provides options to be used with System.Text.Json.JsonSerializer.</param>\n        /// <returns>the object parsed from json.</returns>\n        public static T ParseJson<T>(this string json, JsonSerializerOptions options = null)\n        {\n            if (string.IsNullOrEmpty(json)) return default;\n            var result = JsonSerializer.Deserialize<T>(json, options);\n            return result;\n        }\n        /// <summary>\n        /// Gets the stream from string using UTF8 encoding.\n        /// </summary>\n        /// <param name=\"source\">The string source.</param>\n        /// <returns>UTF8 encoded stream.</returns>\n        public static Stream ToStreamUtf8(this string source)\n        {\n            if (source == null) return null;\n            var stream = new MemoryStream(Encoding.UTF8.GetBytes(source));\n            return stream;\n        }\n\n        /// <summary>\n        /// Gets the stream from string using ASCII encoding.\n        /// </summary>\n        /// <param name=\"source\">The string source.</param>\n        /// <returns>ASCII encoded stream.</returns>\n        public static Stream ToStreamAscii(this string source)\n        {\n            if (source == null) return null;\n            var stream = new MemoryStream(Encoding.ASCII.GetBytes(source));\n            return stream;\n        }\n\n        /// <summary>\n        /// Gets the stream from string using UTF8 encoding.\n        /// </summary>\n        /// <param name=\"source\">The string source.</param>\n        /// <returns>Unicode encoded stream.</returns>\n        public static Stream ToStreamUnicode(this string source)\n        {\n            if (source == null) return null;\n            var stream = new MemoryStream(Encoding.Unicode.GetBytes(source));\n            return stream;\n        }\n\n        /// <summary>\n        /// Serializes an object to xml.\n        /// </summary>\n        /// <param name=\"obj\">The object.</param>\n        /// <returns></returns>\n        public static string ToXml(this object obj)\n        {\n            string retVal;\n            using (var ms = new MemoryStream())\n            {\n                var xs = new XmlSerializer(obj.GetType());\n                xs.Serialize(ms, obj);\n                ms.Flush();\n                ms.Position = 0;\n                retVal = ms.AsStringUtf8();\n            }\n            return retVal;\n        }\n\n        /// <summary>\n        /// Parse a xml to an object.\n        /// </summary>\n        /// <typeparam name=\"T\">type of object.</typeparam>\n        /// <param name=\"str\">The xml string.</param>\n        /// <returns></returns>\n        public static T ParseXml<T>(this string str) where T : new()\n        {\n            var xs = new XmlSerializer(typeof(T));\n            var stream = str.ToStreamUtf8();\n            if (xs.CanDeserialize(new XmlTextReader(stream)))\n            {\n                stream.Position = 0;\n                return (T)xs.Deserialize(stream);\n            }\n            return default;\n        }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public enum HashType\n        {\n            /// <summary>\n            /// The HMACSHA256 Hash type.\n            /// </summary>\n            HMacSha256,\n            /// <summary>\n            /// The HMACSHA384 Hash type.\n            /// </summary>\n            HMacSha384,\n            /// <summary>\n            /// The HMACSHA512 Hash type.\n            /// </summary>\n            HMacSha512,\n            /// <summary>\n            /// The SHA256 Hash type.\n            /// </summary>\n            Sha256,\n            /// <summary>\n            /// The SHA384 Hash type.\n            /// </summary>\n            Sha384,\n            /// <summary>\n            /// The SHA512 Hash type.\n            /// </summary>\n            Sha512\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Extensions/TypeExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Liquid.Core.Extensions\n{\n    /// <summary>\n    /// \n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class TypeExtensions\n    {\n        /// <summary>\n        /// Implements the generic interface.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"interfaceType\">Type of the interface.</param>\n        /// <returns></returns>\n        public static bool ImplementGenericInterface(this Type type, Type interfaceType)\n            => type.IsGenericType(interfaceType) || type.GetTypeInfo().ImplementedInterfaces.Any(@interface => @interface.IsGenericType(interfaceType));\n\n        /// <summary>\n        /// Determines whether [is generic type] [the specified generic type].\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"genericType\">Type of the generic.</param>\n        /// <returns>\n        ///   <c>true</c> if [is generic type] [the specified generic type]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsGenericType(this Type type, Type genericType)\n            => type.GetTypeInfo().IsGenericType && type.GetGenericTypeDefinition() == genericType;\n\n        /// <summary>\n        /// Determines whether [is generic type].\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>\n        ///   <c>true</c> if [is generic type] [the specified type]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsGenericType(this Type type)\n        {\n            return type.GetTypeInfo().IsGenericType;\n        }\n\n        /// <summary>\n        /// Determines whether [is concrete type].\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>\n        ///   <c>true</c> if [is concrete type] [the specified type]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsConcreteType(this Type type)\n        {\n            return !type.IsAbstract() && !type.IsArray && type != typeof(object) && !typeof(Delegate).IsAssignableFrom(type);\n        }\n\n        /// <summary>\n        /// Determines whether this instance is abstract.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>\n        ///   <c>true</c> if the specified type is abstract; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsAbstract(this Type type)\n        {\n            return type.GetTypeInfo().IsAbstract;\n        }\n        /// <summary>\n        /// Determines whether [is generic type definition of] [the specified type to check].\n        /// </summary>\n        /// <param name=\"genericTypeDefinition\">The generic type definition.</param>\n        /// <param name=\"typeToCheck\">The type to check.</param>\n        /// <returns>\n        ///   <c>true</c> if [is generic type definition of] [the specified type to check]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsGenericTypeDefinitionOf(this Type genericTypeDefinition, Type typeToCheck)\n        {\n            return typeToCheck.IsGenericType() && typeToCheck.GetGenericTypeDefinition() == genericTypeDefinition;\n        }        \n\n        /// <summary>\n        /// Determines whether [is generic implementation of] [the specified type].\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"serviceType\">Type of the service.</param>\n        /// <returns>\n        ///   <c>true</c> if [is generic implementation of] [the specified type]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsGenericImplementationOf(this Type type, Type serviceType)\n        {\n            if (type == serviceType || serviceType.IsVariantVersionOf(type))\n                return true;\n            return type.IsGenericType() && serviceType.IsGenericTypeDefinition() && type.GetGenericTypeDefinition() == serviceType;\n        }\n\n        /// <summary>\n        /// Determines whether [is variant version of] [the specified other type].\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"otherType\">Type of the other.</param>\n        /// <returns>\n        ///   <c>true</c> if [is variant version of] [the specified other type]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsVariantVersionOf(this Type type, Type otherType)\n        {\n            return type.IsGenericType() && otherType.IsGenericType() && type.GetGenericTypeDefinition() == otherType.GetGenericTypeDefinition() && type.IsAssignableFrom(otherType);\n        }\n\n        /// <summary>\n        /// Determines whether [is generic type definition].\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns>\n        ///   <c>true</c> if [is generic type definition] [the specified type]; otherwise, <c>false</c>.\n        /// </returns>\n        public static bool IsGenericTypeDefinition(this Type type)\n        {\n            return type.GetTypeInfo().IsGenericTypeDefinition;\n        }\n\n        /// <summary>\n        /// Bases the type.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <returns></returns>\n        public static Type GetBaseType(this Type type)\n        {\n            return type.GetTypeInfo().BaseType;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/GenAi/Entities/LiquidChatContent.cs",
    "content": "﻿using Liquid.Core.GenAi.Enums;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.GenAi.Entities\n{\n    /// <summary>\n    /// The content of the chat message.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidChatContent\n    {\n        /// <summary>\n        /// The kind of content.\n        /// </summary>\n        public LiquidContentKind Kind { get; set; }\n\n        /// <summary>\n        /// The text content of the message.\n        /// </summary>\n        public string Text { get; set; }\n\n        /// <summary>\n        /// The image content url of the message.\n        /// </summary>\n        public Uri ImageUri { get; set; }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/GenAi/Entities/LiquidChatMessage.cs",
    "content": "﻿using Liquid.Core.GenAi.Enums;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.GenAi.Entities\n{\n    /// <summary>\n    /// Context message associated with a chat completions request.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidChatMessage\n    {\n        /// <summary>\n        /// The chat role associated with this message.\n        /// </summary>\n        public LiquidMessageRole Role { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidChatMessage\"/> class with the specified role.\n        /// </summary>\n        /// <param name=\"role\">The role associated with the chat message. This value cannot be null or empty.</param>\n        public LiquidChatMessage(LiquidMessageRole role)\n        {\n            Role = role;\n        }\n\n        /// <summary>\n        /// The contents of the message.\n        /// </summary>\n        public LiquidChatContent[] Content { get; set; } = Array.Empty<LiquidChatContent>();\n\n\n        /// <summary>\n        /// Adds a text content item to the current collection of chat contents.\n        /// </summary>\n        /// <remarks>This method appends the specified text as a new content item to the existing\n        /// collection. If the collection is initially null, it initializes the collection with the new content\n        /// item.</remarks>\n        /// <param name=\"text\">The text content to add. Cannot be null, empty, or consist solely of whitespace.</param>\n        /// <exception cref=\"ArgumentException\">Thrown if <paramref name=\"text\"/> is null, empty, or consists only of whitespace.</exception>\n        public void AddContent(string text)\n        {\n            if (string.IsNullOrWhiteSpace(text))\n            {\n                throw new ArgumentException(\"Text content cannot be null or empty.\", nameof(text));\n            }\n            var content = new LiquidChatContent\n            {\n                Kind = LiquidContentKind.Text,\n                Text = text\n            };\n            if (Content == null)\n            {\n                Content = new[] { content };\n            }\n            else\n            {\n                var contentList = new List<LiquidChatContent>(Content) { content };\n                Content = contentList.ToArray();\n            }\n        }\n\n        /// <summary>\n        /// Adds an image content to the current collection of chat contents.\n        /// </summary>\n        /// <remarks>If the content collection is initially empty, this method initializes it with the new\n        /// image content. Otherwise, it appends the image content to the existing collection.</remarks>\n        /// <param name=\"imageUri\">The URI of the image to be added. Cannot be <see langword=\"null\"/>.</param>\n        /// <exception cref=\"ArgumentNullException\">Thrown if <paramref name=\"imageUri\"/> is <see langword=\"null\"/>.</exception>\n        public void AddContent(Uri imageUri)\n        {\n            if (imageUri == null)\n            {\n                throw new ArgumentNullException(nameof(imageUri), \"Image URI cannot be null.\");\n            }\n            var content = new LiquidChatContent\n            {\n                Kind = LiquidContentKind.Image,\n                ImageUri = imageUri\n            };\n            if (Content == null)\n            {\n                Content = new[] { content };\n            }\n            else\n            {\n                var contentList = new List<LiquidChatContent>(Content) { content };\n                Content = contentList.ToArray();\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/GenAi/Entities/LiquidChatMessages.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.GenAi.Entities\n{\n    /// <summary>\n    /// The object of context messages associated with a chat completions request\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidChatMessages\n    {\n        /// <summary>\n        /// The collection of context messages associated with a chat completions request.\n        /// </summary>\n        public List<LiquidChatMessage> Messages { get; set; } = new List<LiquidChatMessage>();\n\n        /// <summary>\n        /// Adds a message to the collection of chat messages.\n        /// </summary>\n        /// <param name=\"message\">The chat message to add. Cannot be <see langword=\"null\"/>.</param>\n        /// <exception cref=\"System.ArgumentNullException\">Thrown if <paramref name=\"message\"/> is <see langword=\"null\"/>.</exception>\n        public void AddMessage(LiquidChatMessage message)\n        {\n            if (message == null)\n            {\n                throw new System.ArgumentNullException(nameof(message), \"Message cannot be null\");\n            }\n            Messages.Add(message);\n        }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/GenAi/Enums/LiquidContentKind.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.GenAi.Enums\n{\n    /// <summary>\n    /// Represents the possibles of underlying data for a chat message's <c>Content</c> property.\n    /// </summary>\n    public enum LiquidContentKind\n    {\n        /// <summary>\n        /// Text content\n        /// </summary>\n        Text,\n        /// <summary>\n        /// Image content\n        /// </summary>\n        Image\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/GenAi/Enums/LiquidMessageRole.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.GenAi.Enums\n{\n    /// <summary>\n    /// Specifies the role of a participant in a message exchange, such as a user, assistant, or system.\n    /// </summary>\n    public enum LiquidMessageRole\n    {\n        /// <summary>\n        /// The user role, typically representing the end user or client.\n        /// </summary>\n        User,\n        /// <summary>\n        /// The assistant role, typically representing the AI or system responding to the user.\n        /// </summary>\n        Assistant,\n        /// <summary>\n        /// The system role, typically used for system-level messages or instructions.\n        /// </summary>\n        System\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/GenAi/Interfaces/ILiquidGenAi.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.GenAi.Entities;\nusing Liquid.Core.GenAi.Settings;\nusing Liquid.Core.Settings;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.GenAi\n{\n    /// <summary>\n    /// This service is the hub of Liquid adapter custom completions for Generative AI.\n    /// </summary>\n    public interface ILiquidGenAi\n    {\n        /// <summary>\n        /// Get chat completions for provided content and functions.\n        /// </summary>\n        /// <param name=\"messages\">Context messages associated with chat completions request.</param>\n        /// <param name=\"functions\"> A list of functions the model may generate JSON inputs for.</param>\n        /// <param name=\"settings\">The options for chat completions request.</param>\n        Task<ChatCompletionResult> FunctionCalling(LiquidChatMessages messages, List<FunctionBody> functions, CompletionsOptions settings);\n\n        /// <summary>\n        /// Get chat completions for provided chat context messages.\n        /// </summary>\n        /// <param name=\"content\">A request chat message representing an input from the user.</param>\n        /// <param name=\"prompt\">A request chat message containing system instructions that influence how the model will generate a chat completions\n        /// response.</param>\n        /// <param name=\"settings\">The options for chat completions request.</param>\n        /// <param name=\"chatHistory\">The collection of context messages associated with this chat completions request.\n        /// Typical usage begins with a chat message for the System role that provides instructions for\n        /// the behavior of the assistant, followed by alternating messages between the User and\n        /// Assistant roles.</param>\n        Task<ChatCompletionResult> CompleteChatAsync(string content, string prompt, CompletionsOptions settings, LiquidChatMessages chatHistory = null);\n\n        /// <summary>\n        /// Get chat completions for provided chat context messages and functions.\n        /// </summary>\n        /// <param name=\"messages\">Messages associated with chat completions request.</param>\n        /// <param name=\"functions\"> A list of functions the model may generate JSON inputs for.</param>\n        /// <param name=\"chatHistory\"> The collection of context messages associated with this chat completions request. </param>\n        /// <param name=\"settings\">The options for chat completions request.</param>\n        Task<ChatCompletionResult> CompleteChatAsync(LiquidChatMessages messages, CompletionsOptions settings, List<FunctionBody> functions = null, LiquidChatMessages chatHistory = null);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/GenAi/Interfaces/ILiquidGenAiHandler.cs",
    "content": "﻿using System;\nusing System.Net.WebSockets;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.GenAi.Interfaces\n{\n    /// <summary>\n    /// This service is the hub of Liquid adapter audio stream handlers for Generative AI.\n    /// </summary>\n    public interface ILiquidGenAiHandler\n    {\n        /// <summary>\n        /// The task that manages receipt of incoming simplified protocol messages from the frontend client.\n        /// </summary>\n        /// <param name=\"socket\"> The WebSocket connection to the client.</param>\n        /// <param name=\"cancellationToken\"></param>\n        /// <returns></returns>\n        /// <exception cref=\"InvalidOperationException\"></exception>\n        Task HandleInputMessagesAsync(WebSocket socket, CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// The task that manages the incoming updates from realtime API messages and model responses.\n        /// </summary>\n        /// <param name=\"socket\"> The WebSocket connection to the client.</param>\n        /// <param name=\"cancellationToken\"></param>\n        /// <returns></returns>\n        /// <exception cref=\"InvalidOperationException\"></exception>\n        Task HandleUpdatesFromServiceAsync(WebSocket socket, CancellationToken cancellationToken = default);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/GenAi/Settings/CompletionsOptions.cs",
    "content": "﻿using Liquid.Core.Settings;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.GenAi.Settings\n{\n    /// <summary>\n    /// The options for chat completions request.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class CompletionsOptions\n    {\n        /// <summary>\n        /// Client connection alias to use for a chat completions request.\n        /// This connection must be configured in application previously <see cref=\"GenAiSettings\"/>\n        /// </summary>\n        public string ClientId { get; set; }\n        /// <summary>\n        /// The deployment name to use for a chat completions request. \n        /// </summary>\n        public string DeploymentName { get; set; }\n\n        /// <summary>\n        /// The deployment name to use for an embeddings request. \n        /// </summary>\n        public string EmbeddingModelName { get; set; }\n\n        /// <summary>\n        /// Sampling temperature to use that controls the apparent creativity of generated\n        /// completions.\n        /// </summary>\n        public float Temperature { get; set; } = (float)0.7;\n\n        /// <summary>\n        /// Gets the maximum number of tokens to generate. \n        /// </summary>\n        public int? MaxTokens { get; set; } = null;\n\n        /// <summary>\n        ///   An alternative value to <see cref=\"Temperature\"/>, called nucleus sampling, that causes\n        ///   the model to consider the results of the tokens with <see cref=\"TopP\"/> probability\n        ///   mass.\n        /// </summary>\n        public float TopP { get; set; } = (float)0.95;\n\n        /// <summary>\n        ///  Gets or sets a value that influences the probability of generated tokens appearing based on their\n        ///  cumulative frequency in generated text.\n        /// </summary>\n        public int FrequencyPenalty { get; set; } = 0;\n\n        /// <summary>\n        /// Gets or sets a value that influences the probability of generated tokens appearing based on their\n        /// existing presence in generated text.\n        /// </summary>\n        public int PresencePenalty { get; set; } = 0;\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidBackgroundService.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Implementations\n{\n    /// <summary>\n    /// Liquid BackgroundService implementation for message consumers.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">Type of message body.</typeparam>\n    public class LiquidBackgroundService<TEntity> : BackgroundService\n    {\n        private readonly ILiquidConsumer<TEntity> _consumer;\n\n        private readonly IServiceProvider _serviceProvider;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidBackgroundService{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"serviceProvider\"></param>\n        /// <param name=\"consumer\">Consumer service with message handler definition for processing messages.</param>\n        public LiquidBackgroundService(IServiceProvider serviceProvider, ILiquidConsumer<TEntity> consumer)\n        {\n            _serviceProvider = serviceProvider;\n            _consumer = consumer ?? throw new ArgumentNullException(nameof(consumer));\n        }\n\n        /// <summary>\n        /// This method is called when the Microsoft.Extensions.Hosting.IHostedService starts.\n        /// Its return a task that represents the lifetime of the long \n        /// running operation(s) being performed.\n        /// </summary>\n        /// <param name=\"stoppingToken\">Triggered when Microsoft.Extensions.Hosting.IHostedService.StopAsync(System.Threading.CancellationToken)  \n        /// is called.</param>\n        protected override async Task ExecuteAsync(CancellationToken stoppingToken)\n        {\n            _consumer.ConsumeMessageAsync += ProcessMessageAsync;\n            _consumer.RegisterMessageHandler(stoppingToken);\n\n            await Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// This method is called when message handler gets a message.\n        /// Return a task that represents the process to be executed \n        /// by the message handler.\n        /// </summary>\n        /// <param name=\"args\"></param>\n        /// <param name=\"cancellationToken\"></param>\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<TEntity> args, CancellationToken cancellationToken)\n        {\n            using (IServiceScope scope = _serviceProvider.CreateScope())\n            {\n                var worker = scope.ServiceProvider.GetRequiredService<ILiquidWorker<TEntity>>();\n                await worker.ProcessMessageAsync(args, cancellationToken);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidCache.cs",
    "content": "﻿using Liquid.Core.Extensions;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Caching.Distributed;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Implementations\n{\n    ///<inheritdoc/>\n    public class LiquidCache : ILiquidCache\n    {\n        private readonly IDistributedCache _distributedCache;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidCache\"/>\n        /// </summary>\n        /// <param name=\"distributedCache\"></param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public LiquidCache(IDistributedCache distributedCache)\n        {\n            _distributedCache = distributedCache ?? throw new ArgumentNullException(nameof(distributedCache));\n        }\n\n        ///<inheritdoc/>\n        public byte[] Get(string key)\n        {\n            return _distributedCache.Get(key);\n        }\n\n        ///<inheritdoc/>\n        public Task<byte[]> GetAsync(string key, CancellationToken token = default)\n        {\n            return _distributedCache.GetAsync(key, token);\n        }\n\n        ///<inheritdoc/>\n        public void Refresh(string key)\n        {\n            _distributedCache.Refresh(key);\n        }\n\n        ///<inheritdoc/>\n        public Task RefreshAsync(string key, CancellationToken token = default)\n        {\n            return _distributedCache.RefreshAsync(key, token);\n        }\n\n        ///<inheritdoc/>\n        public void Remove(string key)\n        {\n            _distributedCache.Remove(key);\n        }\n\n        ///<inheritdoc/>\n        public Task RemoveAsync(string key, CancellationToken token = default)\n        {\n            return _distributedCache.RemoveAsync(key, token);\n        }\n\n        ///<inheritdoc/>\n        public void Set(string key, byte[] value, DistributedCacheEntryOptions options)\n        {\n            _distributedCache.Set(key, value, options);\n        }\n\n        ///<inheritdoc/>\n        public Task SetAsync(string key, byte[] value, DistributedCacheEntryOptions options, CancellationToken token = default)\n        {\n            return _distributedCache.SetAsync(key, value, options, token);\n        }\n\n        ///<inheritdoc/>\n        public T Get<T>(string key)\n        {\n            var response = _distributedCache.Get(key);\n            return response.ParseJson<T>();\n        }\n\n        ///<inheritdoc/>\n        public async Task<T> GetAsync<T>(string key, CancellationToken token = default)\n        {\n            var response = await _distributedCache.GetAsync(key, token);\n            return response.ParseJson<T>();\n        }\n\n        ///<inheritdoc/>\n        public void Set<T>(string key, T value, DistributedCacheEntryOptions options)\n        {\n            _distributedCache.Set(key, value.ToJsonBytes(), options);\n        }\n\n        ///<inheritdoc/>\n        public async Task SetAsync<T>(string key, T value, DistributedCacheEntryOptions options, CancellationToken token = default)\n        {\n            await _distributedCache.SetAsync(key, value.ToJsonBytes(), options, token);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidContext.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing System.Collections.Generic;\n\nnamespace Liquid.Core.Implementations\n{\n    ///<inheritdoc/>\n    public class LiquidContext : ILiquidContext\n    {\n        private readonly IDictionary<string, object> _current = new Dictionary<string, object>();\n\n        ///<inheritdoc/>\n        public IDictionary<string, object> current => _current;\n\n        ///<inheritdoc/>\n        public void Upsert(string key, object value)\n        {\n            if (_current.ContainsKey(key))\n            {\n                _current[key] = value;\n            }\n            else\n            {\n                _current.TryAdd(key, value);\n            }\n        }\n\n        ///<inheritdoc/>\n        public object Get(string key)\n        {\n            try\n            {\n                return current[key];\n            }\n            catch\n            {\n                return null;\n            }\n\n        }\n\n        ///<inheritdoc/>\n        public T Get<T>(string key)\n        {\n            try\n            {\n                return (T)current[key];\n            }\n            catch\n            {\n                return default;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidContextNotifications.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing System;\nusing System.Collections.Generic;\n\nnamespace Liquid.Core.Implementations\n{\n    ///<inheritdoc/>\n    public class LiquidContextNotifications : ILiquidContextNotifications\n    {\n        private readonly string _notificationKey = \"notification_\" + Guid.NewGuid();\n        private readonly ILiquidContext _liquidContext;\n\n        /// <summary>\n        /// Initialize an instance of <seealso cref=\"LiquidContextNotifications\"/>\n        /// </summary>\n        /// <param name=\"liquidContext\"></param>\n        public LiquidContextNotifications(ILiquidContext liquidContext)\n        {\n            _liquidContext = liquidContext;\n        }\n\n        ///<inheritdoc/>\n        public void InsertNotification(string message)\n        {\n            var notifications = _liquidContext.Get<IList<string>>(_notificationKey);\n            if (notifications is null)\n                notifications = new List<string>();\n\n            notifications.Add(message);\n\n            _liquidContext.Upsert(_notificationKey, notifications);\n        }\n\n        ///<inheritdoc/>\n        public void InsertNotifications(IList<string> notifications)\n        {\n            _liquidContext.Upsert(_notificationKey, notifications);\n        }\n\n        ///<inheritdoc/>\n        public IList<string> GetNotifications()\n        {\n            try\n            {\n                return _liquidContext.Get<IList<string>>(_notificationKey);\n            }\n            catch\n            {\n                return default;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidJsonSerializer.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing System.Text.Json;\n\nnamespace Liquid.Core.Implementations\n{\n    /// <summary>\n    /// Implementation of Liquid Serializer to Json.\n    /// </summary>\n    public class LiquidJsonSerializer : ILiquidSerializer\n    {\n        /// <summary>\n        /// Serializes object to json string.\n        /// </summary>\n        /// <param name=\"content\">object that shoud be serialized.</param>\n        /// <returns></returns>\n        public string Serialize<T>(T content)\n        {\n            return JsonSerializer.Serialize(content);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidSerializerProvider.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Liquid.Core.Implementations\n{\n    ///<inheritdoc/>\n    public class LiquidSerializerProvider : ILiquidSerializerProvider\n    {\n        private readonly IEnumerable<ILiquidSerializer> _serializers;\n\n        /// <summary>\n        /// Initilize a new instance of <see cref=\"LiquidSerializerProvider\"/>\n        /// </summary>\n        /// <param name=\"serializers\"></param>\n        public LiquidSerializerProvider(IEnumerable<ILiquidSerializer> serializers)\n        {\n            _serializers = serializers ?? throw new ArgumentNullException(nameof(serializers));\n        }\n\n        ///<inheritdoc/>\n        public ILiquidSerializer GetSerializerByType(Type serializerType)\n        {\n            return _serializers.SingleOrDefault(x => x.GetType() == serializerType);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidTelemetryInterceptor.cs",
    "content": "﻿using Castle.DynamicProxy;\nusing Liquid.Core.Base;\nusing Microsoft.Extensions.Logging;\nusing System;\nusing System.Diagnostics;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Implementations\n{\n    /// <summary>\n    /// Telemetry interceptor implementation.\n    /// </summary>\n    public class LiquidTelemetryInterceptor : LiquidInterceptorBase\n    {\n        private readonly ILogger<LiquidTelemetryInterceptor> _logger;\n        private readonly Stopwatch _stopwatch;\n\n        /// <summary>\n        /// Initialize an instance of <see cref=\"LiquidTelemetryInterceptor\"/>\n        /// </summary>\n        /// <param name=\"logger\"></param>\n        public LiquidTelemetryInterceptor(ILogger<LiquidTelemetryInterceptor> logger)\n        {\n            _logger = logger;\n            _stopwatch = new Stopwatch();\n        }\n\n        /// <summary>\n        /// Generates log information from the end of method execution with metrics.\n        /// </summary>\n        /// <typeparam name=\"TResult\">Type of results object.</typeparam>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"result\">Result object.</param>\n        protected override Task AfterInvocation<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, TResult result)\n        {\n            _stopwatch.Stop();\n            var elapsedTime = _stopwatch.Elapsed;\n\n            _logger.LogInformation(\"Execution of {methodName} from {typeFullName} has ended in {milliseconds}ms.\", invocation.Method.Name, invocation.TargetType.FullName, elapsedTime.TotalMilliseconds);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Generates log information from the start of method execution with metrics.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        protected override Task BeforeInvocation(IInvocation invocation, IInvocationProceedInfo proceedInfo)\n        {\n            _stopwatch.Start();\n            _logger.LogInformation(\"Starting execution of {methodName} from {typeFullName}.\", invocation.Method.Name, invocation.TargetType.FullName);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Generates an error log of the exception thrown by the method.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"exception\">The <see cref=\"Exception\"/> object.</param>\n        protected override Task OnExceptionInvocation(IInvocation invocation, IInvocationProceedInfo proceedInfo, Exception exception)\n        {\n            _logger.LogError(exception, \"Execution of {methodName} from {typeFullName} has thrown an exception.\", invocation.Method.Name, invocation.TargetType.FullName);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidUnitOfWork.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Implementations\n{\n    /// <summary>\n    /// Controls transactions in all data contexts\n    /// </summary>\n    /// <seealso cref=\"ILiquidUnitOfWork\" />\n    public class LiquidUnitOfWork : ILiquidUnitOfWork\n    {\n        private bool _disposed = false;\n        private readonly List<ILiquidDataContext> _datacontexts = new List<ILiquidDataContext>();\n        private readonly IServiceProvider _serviceProvider;\n        private bool _transactionStarted;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidUnitOfWork\"/> class.\n        /// </summary>\n        /// <param name=\"serviceProvider\">The service provider.</param>\n        /// <exception cref=\"ArgumentNullException\">serviceProvider</exception>\n        public LiquidUnitOfWork(IServiceProvider serviceProvider)\n        {\n            _serviceProvider = serviceProvider ?? throw new ArgumentNullException(nameof(serviceProvider));\n        }\n\n        /// <summary>\n        /// Gets the repository from Service Provider and adds to UnitOfWork.\n        /// </summary>\n        /// <typeparam name=\"TRepository\">The type of the repository.</typeparam>\n        /// <typeparam name=\"TEntity\">The type of the entity.</typeparam>\n        /// <typeparam name=\"TIdentifier\">The type of the identifier.</typeparam>\n        /// <returns></returns>\n        public TRepository GetRepository<TRepository, TEntity, TIdentifier>()\n            where TRepository : ILiquidRepository<TEntity, TIdentifier>\n            where TEntity : LiquidEntity<TIdentifier>\n        {\n            var repository = _serviceProvider.GetService<TRepository>();\n\n            if (!_datacontexts.Any(dataContext => dataContext.Id == repository.DataContext.Id))\n            {\n                _datacontexts.Add(repository.DataContext);\n            }\n\n            return repository;\n        }\n\n        /// <summary>\n        /// Starts the transaction of all data contexts in repositories inside UnitOfWork.\n        /// </summary>\n        /// <exception cref=\"UnitofWorkTransactionWithoutRepositoryException\"></exception>\n        public async Task StartTransactionAsync()\n        {\n            if (!_datacontexts.Any()) throw new UnitofWorkTransactionWithoutRepositoryException();\n            if (!_transactionStarted)\n            {\n                foreach (var datacontext in _datacontexts)\n                {\n                    await datacontext.StartTransactionAsync();\n                }\n            }\n            _transactionStarted = true;\n        }\n\n        /// <summary>\n        /// Commits all commands added to the database context.\n        /// </summary>\n        /// <exception cref=\"UnitOfWorkTransactionNotStartedException\"></exception>\n        public async Task CommitAsync()\n        {\n            if (!_transactionStarted) throw new UnitOfWorkTransactionNotStartedException();\n            foreach (var datacontext in _datacontexts)\n            {\n                await datacontext.CommitAsync();\n            }\n            _transactionStarted = false;\n            _datacontexts.Clear();\n        }\n\n        /// <summary>\n        /// Rollbacks the transactions.\n        /// </summary>\n        /// <exception cref=\"UnitOfWorkTransactionNotStartedException\"></exception>\n        public async Task RollbackTransactionAsync()\n        {\n            if (!_transactionStarted) throw new UnitOfWorkTransactionNotStartedException();\n            foreach (var datacontext in _datacontexts)\n            {\n                await datacontext.RollbackTransactionAsync();\n            }\n            _transactionStarted = false;\n            _datacontexts.Clear();\n        }\n\n        ///<inheritdoc/>\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        /// <summary>\n        /// Releases the allocated resources for all contexts <see cref=\"ILiquidDataContext\"/> \n        /// in this unit of work.\n        /// </summary>\n        /// <param name=\"disposing\">Indicates if method should perform dispose.</param>\n        protected virtual void Dispose(bool disposing)\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            if (disposing)\n            {\n                foreach (var context in _datacontexts)\n                {\n                    context.Dispose();\n                }\n            }\n\n            _disposed = true;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Implementations/LiquidXmlSerializer.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.IO;\nusing System.Xml;\nusing System.Xml.Serialization;\n\nnamespace Liquid.Core.Implementations\n{\n    /// <summary>\n    /// Implementation of Liquid Serializer to XML.\n    /// </summary>\n    public class LiquidXmlSerializer : ILiquidSerializer\n    {\n        /// <summary>\n        /// Serializes object to xml string.\n        /// </summary>\n        /// <param name=\"content\">object that shoud be serialized.</param>\n        public string Serialize<T>(T content)\n        {\n            try\n            {\n                var serializer = new XmlSerializer(content.GetType());\n\n                using var stringWriter = new StringWriter();\n\n                using XmlWriter writer = XmlWriter.Create(stringWriter);\n\n                serializer.Serialize(writer, content);\n\n                return stringWriter.ToString();\n            }\n            catch (Exception ex)\n            {\n                throw new SerializerFailException(nameof(content), ex);\n            }\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidCache.cs",
    "content": "﻿using Microsoft.Extensions.Caching.Distributed;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Represents a distributed cache of serialized values.\n    /// </summary>\n    public interface ILiquidCache : IDistributedCache\n    {\n        /// <summary>\n        /// Gets a value with the given key.\n        /// </summary>\n        /// <param name=\"key\">A string identifying the requested value.</param>\n        /// <typeparam name=\"T\"></typeparam>\n        /// <returns>The located value or null.</returns>\n        T Get<T>(string key);\n\n        /// <summary>\n        /// Gets a value with the given key.\n        /// </summary>\n        /// <param name=\"key\">A string identifying the requested value.</param>\n        /// <param name=\"token\">Optional. The System.Threading.CancellationToken used to propagate notifications\n        /// that the operation should be canceled.</param>\n        /// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation, containing\n        /// the located value or null.</returns>\n        Task<T> GetAsync<T>(string key, CancellationToken token = default);\n\n\n        /// <summary>\n        /// Sets a value with the given key.\n        /// </summary>\n        /// <param name=\"key\">A string identifying the requested value.</param>\n        /// <param name=\"value\"> The value to set in the cache.</param>\n        /// <param name=\"options\">The cache options for the value.</param>\n        void Set<T>(string key, T value, DistributedCacheEntryOptions options);\n\n        /// <summary>\n        /// Sets the value with the given key.\n        /// </summary>\n        /// <param name=\"key\">A string identifying the requested value.</param>\n        /// <param name=\"value\">The value to set in the cache.</param>\n        /// <param name=\"options\">The cache options for the value.</param>\n        /// <param name=\"token\">Optional. The System.Threading.CancellationToken used to propagate notifications\n        /// that the operation should be canceled.</param>\n        /// <returns>The System.Threading.Tasks.Task that represents the asynchronous operation.</returns>\n        Task SetAsync<T>(string key, T value, DistributedCacheEntryOptions options, CancellationToken token = default);\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidConsumer.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Handles message consuming process.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">Type of message body.</typeparam>\n    public interface ILiquidConsumer<TEntity>\n    {\n        /// <summary>\n        /// Initialize handler for consume <typeparamref name=\"TEntity\"/> messages from topic or queue.\n        /// </summary>\n        Task RegisterMessageHandler(CancellationToken cancellationToken = default);\n\n        /// <summary>\n        /// Defining the message processing function.\n        /// </summary>\n        event Func<ConsumerMessageEventArgs<TEntity>, CancellationToken, Task> ConsumeMessageAsync;\n\n        /// <summary>\n        /// Definition of the error handling process.\n        /// </summary>\n        event Func<ConsumerErrorEventArgs, Task> ProcessErrorAsync;\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidContext.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Global context service.\n    /// </summary>\n    public interface ILiquidContext\n    {\n        /// <summary>\n        /// Context itens.\n        /// </summary>\n        IDictionary<string, object> current { get; }\n\n        /// <summary>\n        /// Return context item value.\n        /// </summary>\n        /// <param name=\"key\">key of the item to be obtained.</param>\n        /// <returns></returns>\n        object Get(string key);\n\n        /// <summary>\n        /// Return context item value.\n        /// </summary>\n        /// <param name=\"key\">key of the item to be obtained.</param>\n        /// <typeparam name=\"T\">Type of return object.</typeparam>\n        T Get<T>(string key);\n\n        /// <summary>\n        /// Insert or update itens in context.\n        /// </summary>\n        /// <param name=\"key\">Key of the item.</param>\n        /// <param name=\"value\">Value of the item.</param>\n        void Upsert(string key, object value);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidContextNotifications.cs",
    "content": "﻿using System.Collections.Generic;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Manages notifications in the global context.\n    /// </summary>\n    public interface ILiquidContextNotifications\n    {\n        /// <summary>\n        /// Add or update a notification message.\n        /// </summary>\n        /// <param name=\"message\">Message text.</param>\n        void InsertNotification(string message);\n\n        /// <summary>\n        /// Add or update notifications list on context.\n        /// </summary>\n        /// <param name=\"notifications\">Notification messages list.</param>\n        void InsertNotifications(IList<string> notifications);\n\n        /// <summary>\n        /// Gets notification messages that exist in the global context.\n        /// </summary>\n        IList<string> GetNotifications();\n    }\n\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidDataContext.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Represents the database context\n    /// </summary>\n    public interface ILiquidDataContext : IDisposable\n    {\n        /// <summary>\n        /// Gets the identifier of data context.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        string Id { get; }\n\n        /// <summary>\n        /// Starts the transaction of all data contexts in repositories inside UnitOfWork.\n        /// </summary>\n        /// <returns></returns>\n        Task StartTransactionAsync();\n\n        /// <summary>\n        /// Commits all commands added to the database context.\n        /// </summary>\n        /// <returns></returns>\n        Task CommitAsync();\n\n        /// <summary>\n        /// Rollbacks the transactions.\n        /// </summary>\n        /// <returns></returns>\n        Task RollbackTransactionAsync();\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidMapper.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Defines object that map data between two instance types.\n    /// </summary>\n    /// <typeparam name=\"TFrom\">type of data source object.</typeparam>\n    /// <typeparam name=\"TTo\">results object type.</typeparam>\n    public interface ILiquidMapper<TFrom, TTo>\n    {\n        /// <summary>\n        /// Create a new instance of <see cref=\"TTo\"/>\n        /// with values obtained from <see cref=\"TFrom\"/>.\n        /// </summary>\n        /// <param name=\"dataObject\">data source object instance.</param>\n        /// <param name=\"entityName\"> optional entity name.</param>\n        Task<TTo> Map(TFrom dataObject, string entityName = null);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidOcr.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System.IO;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Ai.Core.Interfaces\n{\n    /// <summary>\n    /// Service to analyze information from documents and images and extract it into structured data. \n    /// It provides the ability to use prebuilt models to analyze receipts,\n    /// business cards, invoices, to extract document content, and more.\n    /// </summary>\n    public interface ILiquidRecognition\n    {\n        /// <summary>\n        /// Analyzes pages from one or more documents, using a model built with custom documents or one of the prebuilt\n        /// models provided by the Form Recognizer service.\n        /// </summary>\n        /// <param name=\"doc\">The stream containing one or more documents to analyze.</param>\n        /// <param name=\"modelId\">\n        /// The ID of the model to use for analyzing the input documents. When using a custom built model\n        /// for analysis, this parameter must be the ID attributed to the model during its creation. When\n        /// using one of the service's prebuilt models, one of the supported prebuilt model IDs must be passed.\n        /// </param>\n        /// <param name=\"clientId\">The ID of the client configuration to use for analyzing the input documents.\n        /// When using a default instace of client, this parameter don't need to be passed, but it's default value\n        /// must be configured on application settings.</param>\n        Task<OcrResult> AnalyzeDocumentAsync(Stream doc, string clientId = \"default\" , string? modelId = \"prebuilt-layout\");\n\n        /// <summary>\n        /// Analyzes pages from one or more documents, using a model built with custom documents or one of the prebuilt\n        /// models provided by the Form Recognizer service. \n        /// </summary>\n        /// <param name=\"uri\">The absolute URI of the remote file to analyze documents from.</param>\n        /// <param name=\"modelId\">\n        /// The ID of the model to use for analyzing the input documents. When using a custom built model\n        /// for analysis, this parameter must be the ID attributed to the model during its creation. When\n        /// using one of the service's prebuilt models, one of the supported prebuilt model IDs must be passed.\n        /// </param>\n        /// <param name=\"clientId\">The ID of the client configuration to use for analyzing the input documents.\n        /// When using a default instace of client, this parameter don't need to be passed, but it's default value\n        /// must be configured on application settings.</param>\n        Task<OcrResult> AnalyzeDocumentFromUriAsync(string uri, string clientId = \"default\", string? modelId = \"prebuilt-layout\");\n\n        /// <summary>\n        /// Classifies one or more documents using a document classifier built with custom documents.\n        /// </summary>\n        /// <param name=\"doc\">The ID of the document classifier to use.</param>\n        /// <param name=\"modelId\">The stream containing one or more documents to classify.</param>\n        /// <param name=\"clientId\">The ID of the client configuration to use for analyzing the input documents.\n        /// When using a default instace of client, this parameter don't need to be passed, but it's default value\n        /// must be configured on application settings.</param>\n        Task<OcrResult> ClassifyDocumenAsync(Stream doc, string clientId = \"default\", string? modelId = \"prebuilt-layout\");\n\n        /// <summary>\n        /// Classifies one or more documents using a document classifier built with custom documents.\n        /// </summary>\n        /// <param name=\"uri\">The absolute URI of the remote file to classify documents from.</param>\n        /// <param name=\"modelId\">The stream containing one or more documents to classify.</param>\n        /// <param name=\"clientId\">The ID of the client configuration to use for analyzing the input documents.\n        /// When using a default instace of client, this parameter don't need to be passed, but it's default value\n        /// must be configured on application settings.</param>\n        Task<OcrResult> ClassifyDocumenFromUriAsync(string uri, string clientId = \"default\", string? modelId = \"prebuilt-layout\");\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidProducer.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Handle send messages process.\n    /// </summary>\n    /// <typeparam name=\"TEntity\"></typeparam>\n    public interface ILiquidProducer<TEntity>\n    {\n        /// <summary>\n        /// Structures and processes sending a list of <typeparamref name=\"TEntity\"/> of messages.\n        /// </summary>\n        /// <param name=\"messageBodies\">Body of messages to be sent.</param>\n        Task SendMessagesAsync(IEnumerable<TEntity> messageBodies);\n\n        /// <summary>\n        /// Structures and processes sending a <typeparamref name=\"TEntity\"/> message with\n        /// its headers <paramref name=\"customProperties\"/>.\n        /// </summary>\n        /// <param name=\"messageBody\">Body of message to be sent.</param>\n        /// <param name=\"customProperties\">Message header properties.</param>\n        Task SendMessageAsync(TEntity messageBody, IDictionary<string, object> customProperties = null);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidRepository.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq.Expressions;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// This interface represents a single repository for the specific <typeparamref name=\"TEntity\"/> entity.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of the entity.</typeparam>\n    /// <typeparam name=\"TIdentifier\">The type of the identifier.</typeparam>\n    public interface ILiquidRepository<TEntity, TIdentifier> where TEntity : LiquidEntity<TIdentifier>\n    {\n        /// <summary>\n        /// Gets the data context associated to repository.\n        /// </summary>\n        /// <value>\n        /// The data context.\n        /// </value>\n        ILiquidDataContext DataContext { get; }\n\n        /// <summary>\n        /// Adds the specified entity item in repository.\n        /// </summary>\n        /// <param name=\"entity\">The entity.</param>\n        Task AddAsync(TEntity entity);\n\n        /// <summary>\n        /// Removes the specified entity item from repository by informed Id.\n        /// </summary>\n        /// <param name=\"id\">Identifier of entity that should be removed.</param>\n        /// <returns></returns>\n        Task RemoveByIdAsync(TIdentifier id);\n\n        /// <summary>\n        /// Updates the specified entity item in repository.\n        /// </summary>\n        /// <param name=\"entity\">The entity.</param>\n        /// <returns></returns>\n        Task UpdateAsync(TEntity entity);\n\n        /// <summary>\n        /// Finds the entity by identifier.\n        /// </summary>\n        /// <param name=\"id\">The entity identifier.</param>\n        /// <returns>The entity</returns>\n        Task<TEntity> FindByIdAsync(TIdentifier id);\n\n        /// <summary>\n        /// Finds the specified entity by the search predicate.\n        /// </summary>\n        /// <param name=\"whereClause\">The search predicate.</param>\n        /// <returns>\n        /// List of entities.\n        /// </returns>\n        Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> whereClause);\n\n        /// <summary>\n        /// Retrieve all entities.\n        /// </summary>\n        /// <returns>List of all entities.</returns>\n        Task<IEnumerable<TEntity>> FindAllAsync();\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidSerializer.cs",
    "content": "﻿namespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Serialization\n    /// </summary>\n    public interface ILiquidSerializer\n    {\n        /// <summary>\n        /// Serialize an object to string.\n        /// </summary>\n        /// <param name=\"content\">object that shoud be serialized.</param>\n        string Serialize<T>(T content);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidSerializerProvider.cs",
    "content": "﻿using System;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Generates a new instance of Serializer Services <see cref=\"ILiquidSerializer\"/>\n    /// </summary>\n    public interface ILiquidSerializerProvider\n    {\n        /// <summary>\n        /// Gets instance of validation service by the type entered in <paramref name=\"serializerType\"/>.\n        /// </summary>\n        /// <param name=\"serializerType\">Type of serializer to get.</param>\n        /// <returns></returns>\n        ILiquidSerializer GetSerializerByType(Type serializerType);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidStorage.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Definition of BlobStorage integration service.\n    /// </summary>\n    public interface ILiquidStorage\n    {\n        /// <summary>\n        /// Upload a specific blob.\n        /// </summary>\n        /// <param name=\"data\">Blob content.</param>\n        /// <param name=\"name\">Blob path.</param>\n        /// <param name=\"containerName\">Blob container name.</param>\n        /// <param name=\"tags\">Blob list of tags.</param>\n        Task<string> UploadBlob(byte[] data, string name, string containerName, IDictionary<string, string> tags = null);\n\n        /// <summary>\n        /// Remove blob by id.\n        /// </summary>\n        /// <param name=\"id\">blob name.</param>\n        /// <param name=\"containerName\">Blob container name.</param>\n        Task Delete(string id, string containerName);\n\n        /// <summary>\n        /// Filter blob by tags and remove them.\n        /// </summary>\n        /// <param name=\"tags\">Tags for filter.</param>\n        /// <param name=\"containerName\">Blob container name.</param>\n        Task DeleteByTags(IDictionary<string, string> tags, string containerName);\n\n        /// <summary>\n        /// Get all blobs from a container.\n        /// </summary>\n        /// <param name=\"containerName\">Blob container name.</param>\n        /// <returns>List of <see cref=\"LiquidBlob\"/>.</returns>\n        Task<List<LiquidBlob>> GetAllBlobs(string containerName);\n\n        /// <summary>\n        /// Filter blobs by tags.\n        /// </summary>\n        /// <param name=\"tags\">Tags for filter.</param>\n        /// <param name=\"containerName\">Blob container name.</param>\n        /// <returns>List of <see cref=\"LiquidBlob\"/>.</returns>\n        Task<List<LiquidBlob>> ReadBlobsByTags(IDictionary<string, string> tags, string containerName);\n\n        /// <summary>\n        /// Dowload a specific blob.\n        /// </summary>\n        /// <param name=\"blobName\">Blob Id.</param>\n        /// <param name=\"containerName\">Blob container name.</param>\n        /// <returns><see cref=\"LiquidBlob\"/>.</returns>\n        Task<LiquidBlob> ReadBlobsByName(string blobName, string containerName);\n\n        /// <summary>\n        /// generates a Blob Shared Access Signature (SAS) Uri\n        /// based on the parameters passed. The SAS is signed by the shared key \n        /// credential of the client.\n        /// </summary>\n        /// <param name=\"blobName\">The id of the blob.</param>\n        /// <param name=\"containerName\">Name of the container where the blob is stored.</param>\n        /// <param name=\"expiresOn\">The time at which the shared access signature becomes invalid.\n        /// This field must be omitted if it has been specified in an\n        /// associated stored access policy.</param>\n        /// <param name=\"permissions\">The permissions associated with the shared access signature. The\n        /// user is restricted to operations allowed by the permissions.</param>\n        /// <returns>Blob sas uri absolute path.</returns>\n        string GetBlobSasUri(string blobName, string containerName, DateTimeOffset expiresOn, string permissions);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidUnitOfWork.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Interface responsible for Managing the repositories transactions.\n    /// </summary>\n    public interface ILiquidUnitOfWork : IDisposable\n    {\n        /// <summary>\n        /// Gets the repository from Service Provider and adds to UnitOfWork.\n        /// </summary>\n        /// <typeparam name=\"TRepository\">The type of the repository.</typeparam>\n        /// <typeparam name=\"TEntity\">The type of the entity.</typeparam>\n        /// <typeparam name=\"TIdentifier\">The type of the identifier.</typeparam>\n        /// <returns></returns>\n        TRepository GetRepository<TRepository, TEntity, TIdentifier>()\n            where TRepository : ILiquidRepository<TEntity, TIdentifier>\n            where TEntity : LiquidEntity<TIdentifier>;\n\n        /// <summary>\n        /// Starts the transaction of all data contexts in repositories inside UnitOfWork.\n        /// </summary>\n        /// <returns></returns>\n        Task StartTransactionAsync();\n\n        /// <summary>\n        /// Commits all commands added to the database context.\n        /// </summary>\n        /// <returns></returns>\n        Task CommitAsync();\n\n        /// <summary>\n        /// Rollbacks the transactions.\n        /// </summary>\n        /// <returns></returns>\n        Task RollbackTransactionAsync();\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Interfaces/ILiquidWorker.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Interfaces\n{\n    /// <summary>\n    /// Liquid Worker Service interface.\n    /// The implementation should be message handling process.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">Type of message body.</typeparam>\n    public interface ILiquidWorker<TEntity>\n    {\n        /// <summary>\n        /// This method is called when message handler gets a message.\n        /// The implementation should return a task that represents \n        /// the process to be executed by the message handler.\n        /// </summary>\n        /// <param name=\"args\"></param>\n        /// <param name=\"cancellationToken\"></param>\n        Task ProcessMessageAsync(ConsumerMessageEventArgs<TEntity> args, CancellationToken cancellationToken);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Liquid.Core.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.Core</PackageId>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2019</Copyright>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Version>8.1.0</Version>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <ProjectGuid>{C33A89FC-4F4D-4274-8D0F-29456BA8F76B}</ProjectGuid>\n    <IsPackable>true</IsPackable>\n    <DebugType>Full</DebugType>\n    <Description>The Liquid Base component contains main functions to be used on all Liquid Framework components.</Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AutoMapper\" Version=\"14.0.0\" />\n    <PackageReference Include=\"Castle.Core.AsyncInterceptor\" Version=\"2.1.0\" />\n    <PackageReference Include=\"FluentValidation\" Version=\"11.9.2\" />\n    <PackageReference Include=\"FluentValidation.DependencyInjectionExtensions\" Version=\"11.9.2\" />\n    <PackageReference Include=\"MediatR\" Version=\"12.3.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.DependencyInjection\" Version=\"8.0.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Abstractions\" Version=\"8.0.3\" />\n    <PackageReference Include=\"System.Memory.Data\" Version=\"8.0.1\" />\n    <PackageReference Include=\"System.Net.Http\" Version=\"4.3.4\" />\n    <PackageReference Include=\"System.Text.Json\" Version=\"8.0.5\" />\n\t<PackageReference Include=\"Microsoft.Extensions.Caching.Abstractions\" Version=\"8.0.0\" />\n\t  <PackageReference Include=\"Microsoft.Extensions.Hosting.Abstractions\" Version=\"8.0.1\" />\n\t  <PackageReference Include=\"System.Text.RegularExpressions\" Version=\"4.3.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"client.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Core/Localization/Entities/LocalizationCollection.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json.Serialization;\n\nnamespace Liquid.Core.Localization.Entities\n{\n    /// <summary>\n    /// Resource collection class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    internal class LocalizationCollection\n    {\n        /// <summary>\n        /// Gets or sets the resources.\n        /// </summary>\n        /// <value>\n        /// The resources.\n        /// </value>\n        [JsonPropertyName(\"items\")]\n        public IEnumerable<LocalizationItem> Items { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LocalizationCollection\"/> class.\n        /// </summary>\n        public LocalizationCollection()\n        {\n            Items = new List<LocalizationItem>();\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/Entities/LocalizationItem.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json.Serialization;\n\nnamespace Liquid.Core.Localization.Entities\n{\n    /// <summary>\n    /// Resource item class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    internal class LocalizationItem\n    {\n        /// <summary>\n        /// Gets or sets the key.\n        /// </summary>\n        /// <value>\n        /// The key.\n        /// </value>\n        [JsonPropertyName(\"key\")]\n        public string Key { get; set; }\n\n        /// <summary>\n        /// Gets or sets the value.\n        /// </summary>\n        /// <value>\n        /// The value.\n        /// </value>\n        [JsonPropertyName(\"values\")]\n        public IEnumerable<LocalizationValue> Values { get; set; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LocalizationItem\"/> class.\n        /// </summary>\n        public LocalizationItem()\n        {\n            Values = new List<LocalizationValue>();\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/Entities/LocalizationValue.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json.Serialization;\n\nnamespace Liquid.Core.Localization.Entities\n{\n    /// <summary>\n    /// Resource value class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    internal class LocalizationValue\n    {\n        /// <summary>\n        /// Gets or sets the resource value.\n        /// </summary>\n        /// <value>\n        /// The object value.\n        /// </value>\n        [JsonPropertyName(\"value\")]\n        public string Value { get; set; }\n\n        /// <summary>\n        /// Gets or sets the channels.\n        /// </summary>\n        /// <value>\n        /// The channels.\n        /// </value>\n        [JsonPropertyName(\"channels\")]\n        public string Channels { get; set; }\n\n        /// <summary>\n        /// Gets the channels as enumerable.\n        /// </summary>\n        /// <value>\n        /// The channels list.\n        /// </value>\n        [JsonIgnore]\n        public IEnumerable<string> ChannelsList\n        {\n            get\n            {\n                if (string.IsNullOrEmpty(Channels)) { return new List<string>(); }\n                return Channels.ToLower().Split(';');\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/ILocalization.cs",
    "content": "﻿using System;\nusing System.Globalization;\n\nnamespace Liquid.Core.Localization\n{\n    /// <summary>\n    /// Resource catalog interface.\n    /// </summary>\n    [Obsolete(\"This class will be removed or refactored in the next release.\")]\n    public interface ILocalization\n    {\n        /// <summary>\n        /// Gets the specified string according to culture.\n        /// </summary>\n        /// <param name=\"key\">The resource key.</param>\n        /// <returns>\n        /// The string associated with resource key.\n        /// </returns>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        string Get(string key);\n\n        /// <summary>\n        /// Gets the specified string according to culture.\n        /// </summary>\n        /// <param name=\"key\">The resource key.</param>\n        /// <param name=\"channel\">The channel.</param>\n        /// <returns>\n        /// The string associated with resource key.\n        /// </returns>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        string Get(string key, string channel);\n\n        /// <summary>\n        /// Gets the specified string according to culture.\n        /// </summary>\n        /// <param name=\"key\">The resource key.</param>\n        /// <param name=\"culture\">The culture.</param>\n        /// <param name=\"channel\">The channel.</param>\n        /// <returns>\n        /// The string associated with resource key.\n        /// </returns>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        string Get(string key, CultureInfo culture, string channel = null);\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/JsonFileLocalization.cs",
    "content": "﻿using Liquid.Core.Extensions;\nusing Liquid.Core.Localization.Entities;\nusing Liquid.Core.Settings;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Collections.Concurrent;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.IO;\nusing System.Threading;\n\nnamespace Liquid.Core.Localization\n{\n    /// <summary>\n    /// Resource file catalog class.\n    /// </summary>\n    /// <seealso cref=\"ILocalization\" />\n    [Obsolete(\"This class will be removed or refactored in the next release.\")]\n    [ExcludeFromCodeCoverage]\n    public class JsonFileLocalization : ILocalization\n    {\n        private readonly IDictionary<CultureInfo, LocalizationCollection> _localizationItems;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"JsonFileLocalization\" /> class.\n        /// </summary>\n        /// <param name=\"configuration\">The configuration.</param>\n        public JsonFileLocalization(IOptions<CultureSettings> configuration)\n        {\n            _localizationItems = ReadLocalizationFiles(configuration);\n        }\n\n        /// <summary>\n        /// Gets the specified string according to culture.\n        /// </summary>\n        /// <param name=\"key\">The resource key.</param>\n        /// <returns>\n        /// The string associated with resource key.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">key</exception>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        public string Get(string key)\n        {\n            return Get(key, Thread.CurrentThread.CurrentCulture);\n        }\n\n        /// <summary>\n        /// Gets the specified string according to culture.\n        /// </summary>\n        /// <param name=\"key\">The resource key.</param>\n        /// <param name=\"channel\">The channel.</param>\n        /// <returns>\n        /// The string associated with resource key.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">key</exception>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        public string Get(string key, string channel)\n        {\n            return Get(key, Thread.CurrentThread.CurrentCulture, channel);\n        }\n\n        /// <summary>\n        /// Gets the specified string according to culture.\n        /// </summary>\n        /// <param name=\"key\">The resource key.</param>\n        /// <param name=\"culture\">The culture.</param>\n        /// <param name=\"channel\">The channel.</param>\n        /// <returns>\n        /// The string associated with resource key.\n        /// </returns>\n        /// <exception cref=\"ArgumentNullException\">\n        /// key\n        /// or\n        /// culture\n        /// </exception>\n        /// <exception cref=\"LocalizationException\"></exception>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        public string Get(string key, CultureInfo culture, string channel = null)\n        {\n            if (string.IsNullOrEmpty(key)) throw new ArgumentNullException(nameof(key));\n            if (culture == null) throw new ArgumentNullException(nameof(culture));\n\n            try\n            {\n                if (_localizationItems.TryGetValue(culture, out var localizationItem))\n                {\n                    var item = localizationItem.Items.GetResourceItem(key);\n                    var itemValue = item?.GetResourceValue(channel);\n                    if (itemValue != null) { return itemValue.Value; }\n                }\n                return key;\n            }\n            catch (Exception ex)\n            {\n                throw new LocalizationException(key, ex);\n            }\n        }\n\n        /// <summary>\n        /// Reads the resource collection from file.\n        /// </summary>\n        /// <param name=\"configuration\">The configuration.</param>\n        /// <exception cref=\"LocalizationReaderException\"></exception>\n        private static IDictionary<CultureInfo, LocalizationCollection> ReadLocalizationFiles(IOptions<CultureSettings> configuration)\n        {\n            var items = new ConcurrentDictionary<CultureInfo, LocalizationCollection>();\n            try\n            {\n                var path = AppDomain.CurrentDomain.BaseDirectory;\n                var files = Directory.EnumerateFiles(path, \"localization*.json\", SearchOption.AllDirectories);\n\n                foreach (var fileName in files)\n                {\n                    var fileInfo = new FileInfo(fileName);\n                    var filenameParts = fileInfo.Name.Split('.');\n                    var culture = filenameParts.Length == 2 ? configuration.Value.DefaultCulture : filenameParts[1];\n\n                    using var fileReader = new StreamReader(fileName);\n                    var json = fileReader.ReadToEnd();\n                    var localizationItems = json.ParseJson<LocalizationCollection>();\n                    items.TryAdd(new CultureInfo(culture), localizationItems);\n                }\n            }\n            catch (Exception exception)\n            {\n                throw new LocalizationReaderException(exception);\n            }\n            return items;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/LocalizationException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Localization\n{\n    /// <summary>\n    /// Occurs when it's not possible to read a resource.\n    /// </summary>\n    /// <seealso cref=\"System.Exception\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class LocalizationException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LocalizationException\"/> class.\n        /// </summary>\n        /// <param name=\"key\">The key.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public LocalizationException(string key, Exception innerException) : base($\"Unable to read resource from key: {key}, please see inner exception.\", innerException)\n        {\n        }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/LocalizationExtensions.cs",
    "content": "﻿using Liquid.Core.Localization.Entities;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\n\nnamespace Liquid.Core.Localization\n{\n    /// <summary>\n    /// Resource extensions class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class LocalizationExtensions\n    {\n        /// <summary>\n        /// Gets the resource item from collection.\n        /// </summary>\n        /// <param name=\"resources\">The resources.</param>\n        /// <param name=\"key\">The key.</param>\n        /// <returns></returns>\n        internal static LocalizationItem GetResourceItem(this IEnumerable<LocalizationItem> resources, string key)\n        {\n            var result = resources.FirstOrDefault(r => r.Key.Equals(key, StringComparison.InvariantCultureIgnoreCase));\n            return result;\n        }\n\n        /// <summary>\n        /// Gets the resource value.\n        /// </summary>\n        /// <param name=\"resourceItem\">The resource item.</param>\n        /// <param name=\"channel\">The channel.</param>\n        /// <returns></returns>\n        /// <exception cref=\"ArgumentNullException\">cultureCode</exception>\n        internal static LocalizationValue GetResourceValue(this LocalizationItem resourceItem, string channel = null)\n        {\n            var values = resourceItem.Values;\n            if (channel == null) { return values.FirstOrDefault(); }\n            var resourceValues = values as LocalizationValue[] ?? values.ToArray();\n            var returnValue = resourceValues.FirstOrDefault(v => v.ChannelsList.Contains(channel.ToLower()));\n            return returnValue ?? resourceValues.FirstOrDefault();\n        }\n\n        /// <summary>\n        /// Adds the localization using the default filename localization.json\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        [Obsolete(\"This method will be removed or refactored in the next release.\")]\n        public static void AddLocalizationService(this IServiceCollection services)\n        {\n            services.AddSingleton<ILocalization, JsonFileLocalization>();\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Localization/LocalizationReaderException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Core.Localization\n{\n    /// <summary>\n    /// Occurs when it's not possible to read the resources collection from data source.\n    /// </summary>\n    /// <seealso cref=\"Exception\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class LocalizationReaderException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LocalizationReaderException\"/> class.\n        /// </summary>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public LocalizationReaderException(Exception innerException) : base(\"An error occurred while reading the resource collection from datasource.\", innerException)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/PipelineBehaviors/LiquidTelemetryBehavior.cs",
    "content": "﻿using MediatR;\nusing Microsoft.Extensions.Logging;\nusing System;\nusing System.Diagnostics;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.PipelineBehaviors\n{\n    /// <summary>\n    /// Telemetry Behavior implementation for Mediator pipelines.\n    /// </summary>\n    /// <typeparam name=\"TRequest\"></typeparam>\n    /// <typeparam name=\"TResponse\"></typeparam>\n    public class LiquidTelemetryBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>\n    {\n        private readonly ILogger<LiquidTelemetryBehavior<TRequest, TResponse>> _logger;\n        private readonly Stopwatch _stopwatch;\n\n        /// <summary>\n        /// Initialize an instance of <see cref=\"LiquidTelemetryBehavior{TRequest, TResponse}\"/>\n        /// </summary>\n        /// <param name=\"logger\">Logging object.</param>\n        public LiquidTelemetryBehavior(ILogger<LiquidTelemetryBehavior<TRequest, TResponse>> logger)\n        {\n            _logger = logger;\n            _stopwatch = new Stopwatch();\n        }\n\n        /// <summary>\n        /// Pipeline handler. Generates telemetry logs before, after and on exception case during request execution.\n        /// </summary>\n        /// <param name=\"request\">Incoming request.</param>\n        /// <param name=\"cancellationToken\">Cancellation token.</param>\n        /// <param name=\"next\"> Awaitable delegate for the next action in the pipeline. Eventually this delegate \n        /// represents the handler.</param>\n        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)\n        {\n            var methodInfo = next.GetMethodInfo();\n\n            TResponse response = default;\n\n            try\n            {\n                await BeforeRequest(methodInfo);\n                response = await next();\n            }\n            catch (Exception ex)\n            {\n                await OnExceptionResponse(methodInfo, ex);\n                throw;\n            }\n            finally\n            {\n                await AfterResponse(methodInfo);\n            }\n\n            return response;\n        }\n\n        private Task AfterResponse(MethodInfo methodInfo)\n        {\n            _stopwatch.Stop();\n            var elapsedTime = _stopwatch.Elapsed;\n\n            _logger.LogInformation(\"Execution of {methodName} from {typeFullName} has ended in {milliseconds}ms.\"\n                , methodInfo.Name, nameof(methodInfo.ReflectedType), elapsedTime.TotalMilliseconds);\n\n            return Task.CompletedTask;\n        }\n\n        private Task OnExceptionResponse(MethodInfo methodInfo, Exception exception)\n        {\n            _logger.LogError(exception, \"Execution of {methodName} from {typeFullName} has thrown an exception.\", methodInfo.Name, nameof(methodInfo.ReflectedType));\n            return Task.CompletedTask;\n        }\n\n        private Task BeforeRequest(MethodInfo methodInfo)\n        {\n            _stopwatch.Start();\n            _logger.LogInformation(\"Starting execution of {methodName} from {typeFullName}.\", methodInfo.Name, methodInfo.ReflectedType);\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/PipelineBehaviors/LiquidValidationBehavior.cs",
    "content": "﻿using FluentValidation;\nusing MediatR;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.PipelineBehaviors\n{\n    /// <summary>\n    /// Validation Request Behavior implementation for Mediator pipelines.\n    /// </summary>\n    /// <typeparam name=\"TRequest\"></typeparam>\n    /// <typeparam name=\"TResponse\"></typeparam>\n    public class LiquidValidationBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>\n    {\n        private readonly IEnumerable<IValidator<TRequest>> _validators;\n\n        /// <summary>\n        /// Initialize an instance of <see cref=\"LiquidValidationBehavior{TRequest, TResponse}\"/>\n        /// </summary>\n        /// <param name=\"validators\">Validator for a <typeparamref name=\"TRequest\"/> type. </param>\n        public LiquidValidationBehavior(IEnumerable<IValidator<TRequest>> validators)\n        {\n            _validators = validators;\n        }\n\n        /// <summary>\n        ///  Pipeline handler. Perform validation and await the next delegate.\n        /// </summary>\n        /// <param name=\"request\">Incoming request.</param>\n        /// <param name=\"cancellationToken\">Cancellation token.</param>\n        /// <param name=\"next\"> Awaitable delegate for the next action in the pipeline. Eventually this delegate \n        /// represents the handler.</param>\n        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)\n        {\n            if (_validators.Any())\n            {\n                var context = new ValidationContext<TRequest>(request);\n\n                var results = await Task.WhenAll(_validators.Select(v => v.ValidateAsync(context, cancellationToken)));\n\n                var errors = results.SelectMany(r => r.Errors).Where(f => f != null).ToList();\n\n                if (errors.Count != 0)\n                    throw new ValidationException(errors);\n            }\n            return await next();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Settings/CultureSettings.cs",
    "content": "﻿using Liquid.Core.Attributes;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// Represents the Culture Configuration inside appsettings.json.\n    /// </summary>\n    [LiquidSectionName(\"liquid:culture\")]\n    [ExcludeFromCodeCoverage]\n    public class CultureSettings\n    {\n        /// <summary>\n        /// Gets the default culture.\n        /// </summary>\n        /// <value>\n        /// The default culture.\n        /// </value>\n        public string DefaultCulture { get; set; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Settings/DatabaseSettings.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// Database configuration properties.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class DatabaseSettings\n    {\n        /// <summary>\n        /// Gets or sets the database connection string.\n        /// </summary>\n        /// <value>\n        /// The database connection string.\n        /// </value>\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the database.\n        /// </summary>\n        /// <value>\n        /// The name of the database.\n        /// </value>\n        public string DatabaseName { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Settings/GenAiOptions.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// The options for chat completions request.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class GenAiOptions\n    {\n        public List<GenAiSettings> Settings { get; set; }\n    }\n\n    /// <summary>\n    /// The settings for chat completions request.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class GenAiSettings\n    {\n        /// <summary>\n        /// Client connection alias.\n        /// </summary>\n        public string ClientId { get; set; }\n        /// <summary>\n        /// The URI for an GenAI resource as retrieved from, for example, Azure Portal.\n        ///This should include protocol and hostname.\n        /// </summary>\n        public string Url { get; set; }\n\n        /// <summary>\n        /// Key to use to authenticate with the service.\n        /// </summary>\n        public string Key { get; set; }\n\n        /// <summary>\n        /// The maximum number of retries to allow.\n        /// </summary>\n        public int MaxRetries { get; set; } = 0;\n\n        /// <summary>\n        /// the maximum delay in milliseconds between retries.\n        /// </summary>\n        public int RetryMinDelay { get; set; } = 1000;\n\n        /// <summary>\n        /// the maximum delay in milliseconds between retries.\n        /// </summary>\n        public int RetryMaxDelay { get; set; } = 10000;\n\n        /// <summary>\n        /// if set to true, the delay between retries will grow exponentially,\n        /// limited by the values of <see cref=\"RetryMinDelay\"/> and <see cref=\"RetryMaxDelay\"/>. \n        /// Otherwise, the delay will be fixed by the value of <see cref=\"RetryMinDelay\"/>.\n        /// </summary>\n        public bool ExponentialBackoff { get; set; } = false;\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Settings/OcrOptions.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// Set of OCR service settings.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class OcrOptions\n    {\n        /// <summary>\n        /// Collection of OCR service connection settings.\n        /// </summary>\n        public List<OcrSettings> Settings { get; set; }\n    }\n\n    /// <summary>\n    /// OCR service connection settings.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class OcrSettings\n    {\n        /// <summary>\n        /// OCR service connection alias.\n        /// </summary>\n        public string ClientId { get; set; }\n        /// <summary>\n        /// OCR service absolute Uri.\n        /// </summary>\n        public string Url { get; set; }\n\n        /// <summary>\n        /// OCR service access key.\n        /// </summary>\n        public string Key { get; set; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Settings/ScopedContextSettings.cs",
    "content": "﻿using Liquid.Core.Attributes;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// Context key settings.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    [LiquidSectionName(\"Liquid:ScopedContext\")]\n    public class ScopedContextSettings\n    {\n        /// <summary>\n        /// List of keys that should be created on context.\n        /// </summary>\n        public List<ScopedKey> Keys { get; set; } = new List<ScopedKey>();\n\n        /// <summary>\n        /// Indicates if the current culture must be included on context keys.\n        /// </summary>\n        public bool Culture { get; set; } = false;\n\n    }\n}"
  },
  {
    "path": "src/Liquid.Core/Settings/ScopedKey.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// Definition of scoped key type.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class ScopedKey\n    {\n        /// <summary>\n        /// Name of the scoped key.\n        /// </summary>\n        public string KeyName { get; set; }\n\n        /// <summary>\n        /// Indicates if this key is mandatory.\n        /// </summary>\n        public bool Required { get; set; } = false;\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Settings/ScopedLoggingSettings.cs",
    "content": "﻿using Liquid.Core.Attributes;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Settings\n{\n    /// <summary>\n    /// Scoped logging setting properties.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    [LiquidSectionName(\"Liquid:ScopedLogging\")]\n    public class ScopedLoggingSettings\n    {\n        /// <summary>\n        /// List of keys that should be created on logger scope.\n        /// </summary>\n        public List<ScopedKey> Keys { get; set; } = new List<ScopedKey>();\n    }\n\n}\n"
  },
  {
    "path": "src/Liquid.Core/Utils/TypeUtils.cs",
    "content": "﻿using Liquid.Core.Extensions;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Liquid.Core.Utils\n{\n    /// <summary>\n    /// Type Helper Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class TypeUtils\n    {\n        /// <summary>\n        /// Gets the types to register.\n        /// </summary>\n        /// <param name=\"serviceType\">Type of the service.</param>\n        /// <param name=\"assemblies\">The assemblies.</param>\n        /// <returns></returns>\n        public static Type[] GetTypesToRegister(Type serviceType, IEnumerable<Assembly> assemblies)\n        {\n            var typesToRegister = assemblies\n                .Distinct()\n                .Where(assembly => !assembly.IsDynamic)\n                .SelectMany(assembly => assembly.GetTypes())\n                .Where(type => type.IsConcreteType() && !type.GetTypeInfo().IsGenericTypeDefinition && ServiceIsAssignableFromImplementation(serviceType, type));\n\n            return typesToRegister.ToArray();\n        }\n\n        /// <summary>\n        /// Services the is assignable from implementation.\n        /// </summary>\n        /// <param name=\"service\">The service.</param>\n        /// <param name=\"implementation\">The implementation.</param>\n        /// <returns></returns>\n        private static bool ServiceIsAssignableFromImplementation(Type service, Type implementation)\n        {\n            if (service.IsAssignableFrom(implementation) || service.IsGenericTypeDefinitionOf(implementation)) return true;\n            if (implementation.GetInterfaces().Any(type => type.IsGenericImplementationOf(service))) return true;\n\n            var type1 = implementation.GetBaseType() ?? (implementation != typeof(object) ? typeof(object) : null);\n\n            for (var type2 = type1; type2 != null as Type; type2 = type2.GetBaseType())\n            {\n                if (type2.IsGenericImplementationOf(service))\n                    return true;\n            }\n            return false;\n        }\n\n        /// <summary>\n        /// Gets the field information.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"fieldName\">Name of the field.</param>\n        /// <returns></returns>\n        public static FieldInfo GetFieldInfo(Type type, string fieldName)\n        {\n            FieldInfo fieldInfo;\n            do\n            {\n                fieldInfo = type.GetField(fieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n                type = type.BaseType;\n            } while (fieldInfo == null && type != null);\n\n            return fieldInfo;\n        }\n\n        /// <summary>\n        /// Gets the property information.\n        /// </summary>\n        /// <param name=\"type\">The type.</param>\n        /// <param name=\"propertyName\">Name of the property.</param>\n        /// <returns></returns>\n        public static PropertyInfo GetPropertyInfo(Type type, string propertyName)\n        {\n            PropertyInfo propertyInfo;\n            do\n            {\n                propertyInfo = type.GetProperty(propertyName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);\n                type = type.BaseType;\n            } while (propertyInfo == null && type != null);\n\n            return propertyInfo;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core/Utils/ZipUtils.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.IO.Compression;\nusing System.Text;\n\nnamespace Liquid.Core.Utils\n{\n    /// <summary>\n    /// Compression and Decompression library.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class ZipUtils\n    {\n        #region Gzip\n\n        /// <summary>\n        /// Compress a string using Gzip format and UTF8 encoding.\n        /// </summary>\n        /// <param name=\"inputString\">The input string.</param>\n        /// <returns>The compressed string.</returns>\n        public static byte[] GzipCompress(this string inputString)\n        {\n            return inputString.GzipCompress(Encoding.UTF8);\n        }\n\n        /// <summary>\n        /// Compress a string using Gzip format.\n        /// </summary>\n        /// <param name=\"inputString\">The input string.</param>\n        /// <param name=\"encoding\">The encoding.</param>\n        /// <returns>\n        /// The compressed string.\n        /// </returns>\n        public static byte[] GzipCompress(this string inputString, Encoding encoding)\n        {\n            var inputBytes = encoding.GetBytes(inputString);\n            byte[] output;\n\n            using (var outputStream = new MemoryStream())\n            {\n                using (var gZipStream = new GZipStream(outputStream, CompressionMode.Compress))\n                {\n                    gZipStream.Write(inputBytes, 0, inputBytes.Length);\n                }\n                output = outputStream.ToArray();\n            }\n\n            return output;\n        }\n\n        /// <summary>\n        /// Decompress a compressed string using Gzip format and UTF8 encoding.\n        /// </summary>\n        /// <param name=\"inputBytes\">The compressed bytes.</param>\n        /// <returns>The decompressed string.</returns>\n        public static string GzipDecompress(this byte[] inputBytes)\n        {\n            return inputBytes.GzipDecompress(Encoding.UTF8);\n        }\n\n        /// <summary>\n        /// Decompress a compressed string using Gzip format.\n        /// </summary>\n        /// <param name=\"inputBytes\">The compressed bytes.</param>\n        /// <param name=\"encoding\">The encoding.</param>\n        /// <returns>\n        /// The decompressed string.\n        /// </returns>\n        public static string GzipDecompress(this byte[] inputBytes, Encoding encoding)\n        {\n            string decompressed;\n            using (var inputStream = new MemoryStream(inputBytes))\n            using (var gZipStream = new GZipStream(inputStream, CompressionMode.Decompress))\n            using (var outputStream = new MemoryStream())\n            {\n                gZipStream.CopyTo(outputStream);\n                var outputBytes = outputStream.ToArray();\n\n                decompressed = encoding.GetString(outputBytes);\n            }\n\n            return decompressed;\n        }\n\n        #endregion\n\n        #region Deflate\n\n        /// <summary>\n        /// Compress a string using Deflate format.\n        /// </summary>\n        /// <param name=\"inputString\">The input string.</param>\n        /// <returns>The compressed string.</returns>\n        public static byte[] DeflateCompress(this string inputString)\n        {\n            return inputString.DeflateCompress(Encoding.UTF8);\n        }\n\n        /// <summary>\n        /// Compress a string using Deflate format.\n        /// </summary>\n        /// <param name=\"inputString\">The input string.</param>\n        /// <param name=\"encoding\">The encoding.</param>\n        /// <returns>\n        /// The compressed string.\n        /// </returns>\n        public static byte[] DeflateCompress(this string inputString, Encoding encoding)\n        {\n            var inputBytes = encoding.GetBytes(inputString);\n            byte[] output;\n\n            using (var outputStream = new MemoryStream())\n            {\n                using (var deflateStream = new DeflateStream(outputStream, CompressionMode.Compress))\n                {\n                    deflateStream.Write(inputBytes, 0, inputBytes.Length);\n                }\n                output = outputStream.ToArray();\n            }\n\n            return output;\n        }\n\n        /// <summary>\n        /// Decompress a compressed string using Deflate format.\n        /// </summary>\n        /// <param name=\"inputBytes\">The compressed bytes.</param>\n        /// <returns>The decompressed string.</returns>\n        public static string DeflateDecompress(this byte[] inputBytes)\n        {\n            return inputBytes.DeflateDecompress(Encoding.UTF8);\n        }\n\n        /// <summary>\n        /// Decompress a compressed string using Deflate format.\n        /// </summary>\n        /// <param name=\"inputBytes\">The compressed bytes.</param>\n        /// <param name=\"encoding\">The encoding.</param>\n        /// <returns>\n        /// The decompressed string.\n        /// </returns>\n        public static string DeflateDecompress(this byte[] inputBytes, Encoding encoding)\n        {\n            string decompressed;\n            using (var inputStream = new MemoryStream(inputBytes))\n            using (var deflateStream = new DeflateStream(inputStream, CompressionMode.Decompress))\n            using (var outputStream = new MemoryStream())\n            {\n                deflateStream.CopyTo(outputStream);\n                var outputBytes = outputStream.ToArray();\n\n                decompressed = encoding.GetString(outputBytes);\n            }\n\n            return decompressed;\n        }\n\n        #endregion\n    }\n}"
  },
  {
    "path": "src/Liquid.Core.Telemetry.ElasticApm/Extensions/DependencyInjection/IApplicationBuilderExtensions.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Elastic.Apm.NetCoreAll;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Extends <see cref=\"IApplicationBuilder\"/> interface.\n    /// </summary>\n    public static class IApplicationBuilderExtensions\n    {\n        /// <summary>\n        /// Adds <see cref=\"HostBuilderExtensions.UseAllElasticApm(Microsoft.Extensions.Hosting.IHostBuilder)\"/> to the application builder.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        /// <param name=\"configuration\"><see cref=\"IConfiguration\"/> implementation.</param>\n        public static IApplicationBuilder UseLiquidElasticApm(this IApplicationBuilder builder, IConfiguration configuration)\n        {\n            if (configuration.HasElasticApmEnabled())\n            {\n                builder.UseAllElasticApm(configuration);\n            }\n\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core.Telemetry.ElasticApm/Extensions/DependencyInjection/IServiceCollectionExtensions.cs",
    "content": "﻿using Elastic.Apm;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Telemetry.ElasticApm.Implementations;\nusing Liquid.Core.Telemetry.ElasticApm.MediatR;\nusing MediatR;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Extends <see cref=\"IServiceCollection\"/> interface.\n    /// </summary>\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Register telemetry interceptor <see cref=\"LiquidElasticApmInterceptor\"/> and behaviour <see cref=\"LiquidElasticApmTelemetryBehavior{TRequest, TResponse}\"/> for Elastic APM. \n        /// </summary>\n        /// <param name=\"services\">Extended <see cref=\"IServiceCollection\"/> instance.</param>\n        /// <param name=\"configuration\"><see cref=\"IConfiguration\"/> implementation.</param>\n        public static IServiceCollection AddLiquidElasticApmTelemetry(this IServiceCollection services, IConfiguration configuration)\n        {\n            if (configuration.HasElasticApmEnabled())\n            {\n                services.AddSingleton(s => Agent.Tracer);\n\n                services.AddInterceptor<LiquidElasticApmInterceptor>();\n\n                services.AddTransient(typeof(IPipelineBehavior<,>), typeof(LiquidElasticApmTelemetryBehavior<,>));\n            }\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core.Telemetry.ElasticApm/Extensions/IConfigurationExtension.cs",
    "content": "﻿using System;\nusing Microsoft.Extensions.Configuration;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Extensions\n{\n    /// <summary>\n    /// Extends <see cref=\"IConfiguration\"/> interface.\n    /// </summary>\n    internal static class IConfigurationExtension\n    {\n        /// <summary>\n        /// Checks if Elastic APM is enabled.\n        /// </summary>\n        /// <param name=\"config\">Extended <see cref=\"IConfiguration\"/> instance.</param>\n        /// <returns>True if Elastic APM is enabled, otherwise False.</returns>\n        internal static bool HasElasticApmEnabled(this IConfiguration config)\n        {\n            var apmConfigured = config.GetSection(\"ElasticApm:ServerUrl\").Value != null;\n            if (apmConfigured)\n            {\n                var isEnabled = false;\n                var apmEnvironment = (Environment.GetEnvironmentVariable(\"ELASTIC_APM_ENABLED\") != null && bool.TryParse(Environment.GetEnvironmentVariable(\"ELASTIC_APM_ENABLED\"), out isEnabled));\n                if (!apmEnvironment)\n                {\n                    return bool.TryParse(config[\"ElasticApm:Enabled\"], out isEnabled) ? isEnabled : apmConfigured;\n                }\n                return isEnabled;\n            }\n\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Core.Telemetry.ElasticApm/Implementations/LiquidElasticApmInterceptor.cs",
    "content": "﻿using System;\nusing System.Threading.Tasks;\nusing Castle.DynamicProxy;\nusing Elastic.Apm.Api;\nusing Liquid.Core.Base;\nusing Microsoft.Extensions.Logging;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Implementations\n{\n    /// <summary>\n    /// Implement interceptors for Elastic APM with actions after, before and on exception.\n    /// </summary>\n    public sealed class LiquidElasticApmInterceptor : LiquidInterceptorBase\n    {\n        private readonly ILogger<LiquidElasticApmInterceptor> _logger;\n\n        private readonly ITracer _tracer;\n\n        private ISpan span;\n\n        /// <summary>\n        /// Initialize an instance of <see cref=\"LiquidElasticApmInterceptor\"/>\n        /// </summary>\n        /// <param name=\"logger\"><see cref=\"ILogger{LiquidElasticApmInterceptor}\"/> implementation.</param>\n        /// <param name=\"tracer\">Elastic APM <see cref=\"ITracer\"/> implementation.</param>\n        public LiquidElasticApmInterceptor(ILogger<LiquidElasticApmInterceptor> logger, ITracer tracer)\n        {\n            _logger = logger;\n            _tracer = tracer;\n        }\n\n        /// <summary>\n        /// Generates log information from the end of method execution with metrics.\n        /// </summary>\n        /// <typeparam name=\"TResult\">Type of results object.</typeparam>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"result\">Result object.</param>\n        protected override Task AfterInvocation<TResult>(IInvocation invocation, IInvocationProceedInfo proceedInfo, TResult result)\n        {\n            span?.End();\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Generates log information from the start of method execution with metrics.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        protected override Task BeforeInvocation(IInvocation invocation, IInvocationProceedInfo proceedInfo)\n        {\n            span = _tracer?.CurrentTransaction?.StartSpan(invocation.TargetType.Name, invocation.Method.Name);\n            return Task.CompletedTask;\n        }\n\n        /// <summary>\n        /// Generates an error log of the exception thrown by the method.\n        /// </summary>\n        /// <param name=\"invocation\"> The method invocation.</param>\n        /// <param name=\"proceedInfo\"> The Castle.DynamicProxy.IInvocationProceedInfo.</param>\n        /// <param name=\"exception\">The <see cref=\"Exception\"/> object.</param>\n        protected override Task OnExceptionInvocation(IInvocation invocation, IInvocationProceedInfo proceedInfo, Exception exception)\n        {\n            span?.End();\n\n            _logger?.LogError(exception, $\"Execution of {invocation.Method.Name} from {invocation.TargetType.Name} has thrown an exception.\");\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core.Telemetry.ElasticApm/Implementations/LiquidElasticApmTelemetryBehavior.cs",
    "content": "﻿using System;\nusing System.Reflection;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Elastic.Apm.Api;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.MediatR\n{\n    /// <summary>\n    /// Implements <see cref=\"IPipelineBehavior{TRequest, TResponse}\"/> for Elastic APM.\n    /// </summary>\n    /// <typeparam name=\"TRequest\">The type of request.</typeparam>\n    /// <typeparam name=\"TResponse\">Type of response object obtained upon return of request.</typeparam>\n    public sealed class LiquidElasticApmTelemetryBehavior<TRequest, TResponse> : IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>\r\n    {\n        private readonly ILogger<LiquidElasticApmTelemetryBehavior<TRequest, TResponse>> _logger;\n\n        private readonly ITransaction _transaction;\n\n        /// <summary>\n        /// Initialize an instance of <see cref=\"LiquidElasticApmTelemetryBehavior{TRequest, TResponse}\"/>\n        /// </summary>\n        /// <param name=\"logger\"><see cref=\"ILogger{TCategoryName}\"/> implementation where TCategoryName is a <see cref=\"LiquidElasticApmTelemetryBehavior{TRequest, TResponse}\"/> instance.</param>\n        /// <param name=\"tracer\">Elastic APM <see cref=\"ITracer\"/> implementation.</param>\n        public LiquidElasticApmTelemetryBehavior(ILogger<LiquidElasticApmTelemetryBehavior<TRequest, TResponse>> logger, ITracer tracer)\n        {\n            _logger = logger;\n            _transaction = tracer?.CurrentTransaction;\n        }\n\n        /// <summary>\n        /// Handles MediatR pipeline operation.\n        /// </summary>\n        /// <param name=\"request\">The request command or query.</param>\n        /// <param name=\"cancellationToken\">Notification about operation to be cancelled.</param>\n        /// <param name=\"next\">Mext operation to be performed.</param>\n        /// <returns></returns>\n        public async Task<TResponse> Handle(TRequest request, RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)\n        {\n            var methodInfo = next.GetMethodInfo();\n\n            TResponse response = default;\n\n            var span = _transaction?.StartSpan(methodInfo.Name, methodInfo.ReflectedType.Name);\n            try\n            {\n                await BeforeRequest(methodInfo);\n                response = await next();\n            }\n            catch (Exception ex)\n            {\n                await OnExceptionResponse(methodInfo, ex);\n                throw;\n            }\n            finally\n            {\n                await AfterResponse(methodInfo);\n                span?.End();\n            }\n\n            return response;\n        }\n\n        private Task AfterResponse(MethodInfo methodInfo)\n        {\n            _logger?.LogInformation($\"Execution of {methodInfo.Name} from {methodInfo.ReflectedType.Name} has ended.\");\n            return Task.CompletedTask;\n        }\n\n        private Task OnExceptionResponse(MethodInfo methodInfo, Exception exception)\n        {\n            _logger?.LogError(exception, $\"Execution of {methodInfo.Name} from {methodInfo.ReflectedType.Name} has thrown an exception.\");\n            return Task.CompletedTask;\n        }\n\n        private Task BeforeRequest(MethodInfo methodInfo)\n        {\n            _logger?.LogInformation($\"Starting execution of {methodInfo.Name} from {methodInfo.ReflectedType.Name}.\");\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Core.Telemetry.ElasticApm/Liquid.Core.Telemetry.ElasticApm.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.Core.Telemetry.ElasticApm</PackageId>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2021</Copyright>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Version>8.0.0</Version>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <ProjectGuid>{AD354CF6-C132-4B5D-944D-0DFE21509781}</ProjectGuid>\n    <IsPackable>true</IsPackable>\n    <DebugType>Full</DebugType>\n    <Description>This is the Liquid component to collect telemetry and send it to ElasticAPM.</Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Elastic.Apm.NetCoreAll\" Version=\"1.31.0\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"MediatR\" Version=\"12.3.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Liquid.Dataverse/DataverseClientFactory.cs",
    "content": "﻿using Microsoft.Extensions.Options;\nusing Microsoft.PowerPlatform.Dataverse.Client;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Dataverse\n{\n    ///<inheritdoc/>\n    public class DataverseClientFactory : IDataverseClientFactory\n    {\n        private readonly IOptions<DataverseSettings> _options;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"DataverseClientFactory\"/>\n        /// </summary>\n        /// <param name=\"options\">Configuration settigs.</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public DataverseClientFactory(IOptions<DataverseSettings> options)\n        {\n            ArgumentNullException.ThrowIfNull(options);\n\n            _options = options;\n        }\n\n        ///<inheritdoc/>   \n        [ExcludeFromCodeCoverage]\n        public IOrganizationServiceAsync GetClient()\n        {\n            var settings = _options.Value;\n\n            var connectionString = string.Format(\"AuthType=ClientSecret;url={0};ClientId={1};ClientSecret={2};\", settings.Url, settings.ClientId, settings.ClientSecret);\n\n            var service = new ServiceClient(connectionString);\n\n            return service;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Dataverse/DataverseEntityMapper.cs",
    "content": "﻿using Liquid.Core.AbstractMappers;\nusing Microsoft.Xrm.Sdk;\nusing Microsoft.Xrm.Sdk.Metadata;\nusing Newtonsoft.Json;\nusing Newtonsoft.Json.Linq;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Dataverse\n{\n    /// <summary>\n    /// Implementation of <see cref=\"LiquidMapper{TFrom, TTo}\"/> that\n    /// maps json string data to a new instance of <see cref=\"Entity\"/>.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class DataverseEntityMapper : LiquidMapper<string, Entity>\n    {\n        private readonly ILiquidDataverse _dataverseAdapter;\n        private Dictionary<string, EntityMetadata> _entitiesMetadata = new Dictionary<string, EntityMetadata>();\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"DataverseEntityMapper\"/>\n        /// </summary>\n        /// <param name=\"adapter\"></param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public DataverseEntityMapper(ILiquidDataverse adapter) : base(nameof(DataverseEntityMapper))\n        {\n            _dataverseAdapter = adapter ?? throw new ArgumentNullException(nameof(adapter));\n        }\n\n        ///<inheritdoc/>\n        protected override async Task<Entity> MapImpl(string jsonString, string? entityName = null)\n        {\n            ArgumentNullException.ThrowIfNull(entityName);\n\n            var entityAttributes = await GetEntityAttributes(entityName);\n\n            if (entityAttributes == null)\n                throw new ArgumentNullException(nameof(entityAttributes), $\"Entity {entityName} not found.\");\n\n            var entity = JsonToEntity(entityAttributes, jsonString);\n\n            return entity;\n        }\n\n        private async Task<List<AttributeMetadata>?> GetEntityAttributes(string entityName, List<string>? noMappingFields = null)\n        {\n            var entityMetadata = _entitiesMetadata.FirstOrDefault(x => x.Key == entityName).Value;\n\n            if (entityMetadata == null)\n            {\n                entityMetadata = await _dataverseAdapter.GetMetadata(entityName);\n                _entitiesMetadata.TryAdd(entityName, entityMetadata);\n            }\n\n            var attributes = entityMetadata.Attributes?.ToList();\n\n            if (attributes != null)\n            {\n                attributes = attributes.Where(p => p.IsLogical != null).ToList();\n            }\n            if (noMappingFields != null)\n            {\n                foreach (var noMappingField in noMappingFields)\n                {\n                    attributes = attributes?.Where(p => p.LogicalName != noMappingField)?.ToList();\n                }\n            }\n\n            var listAttributes = attributes?.ToList();\n\n            return listAttributes;\n        }\n        private static Entity JsonToEntity(List<AttributeMetadata> attributes, string values)\n        {\n            var entidade = new Entity();\n            var valuesObject = JsonConvert.DeserializeObject<JObject>(values);\n            if (valuesObject == null)\n                return entidade;\n\n            foreach (var atrribute in attributes)\n            {\n                var logicalName = atrribute.LogicalName.ToUpper();\n\n                if (valuesObject[logicalName] == null)\n                    continue;\n\n                if (valuesObject[logicalName].ToString() != \"\")\n                {\n\n                    switch (atrribute.AttributeType.ToString())\n                    {\n                        case \"String\":\n                        case \"Memo\":\n                            entidade[atrribute.LogicalName] = (string)valuesObject[logicalName];\n                            break;\n                        case \"Virtual\":\n                            var options = valuesObject[logicalName].ToList();\n                            OptionSetValueCollection collectionOptionSetValues = new OptionSetValueCollection();\n                            foreach (var option in options)\n                            {\n                                collectionOptionSetValues.Add(new OptionSetValue(int.Parse(option[\"Value\"].ToString())));\n                            }\n                            entidade[atrribute.LogicalName] = collectionOptionSetValues;\n                            break;\n                        case \"Integer\":\n                            entidade[atrribute.LogicalName] = (int)valuesObject[logicalName];\n                            break;\n                        case \"Decimal\":\n                            entidade[atrribute.LogicalName] = (decimal)valuesObject[logicalName];\n                            break;\n                        case \"Boolean\":\n                            entidade[atrribute.LogicalName] = (bool)valuesObject[logicalName];\n                            break;\n                        case \"Picklist\":\n                            entidade[atrribute.LogicalName] = new OptionSetValue((int)valuesObject[logicalName]);\n                            break;\n                        case \"DateTime\":\n                            entidade[atrribute.LogicalName] = Convert.ToDateTime((string)valuesObject[logicalName]);\n                            break;\n                        case \"Money\":\n                            if ((int)valuesObject[logicalName] > 0)\n                                entidade[atrribute.LogicalName] = new Money((int)valuesObject[logicalName]);\n                            break;\n                        case \"Double\":\n                            entidade[atrribute.LogicalName] = (double)valuesObject[logicalName];\n                            break;\n                        case \"Lookup\":\n                        case \"Customer\":\n                        case \"Owner\":\n                            entidade[atrribute.LogicalName] = new EntityReference(valuesObject[logicalName][\"LogicalName\"].ToString()\n                               , new Guid(valuesObject[logicalName][\"Id\"].ToString()));\n                            break;\n                    }\n\n                }\n            }\n            return entidade;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Dataverse/DataverseSettings.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Dataverse\n{\n    /// <summary>\n    /// Set of dataverse connection configs.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class DataverseSettings\n    {\n        /// <summary>\n        /// User Id to use.\n        /// </summary>\n        public string ClientId { get; set; }\n\n        /// <summary>\n        /// User secret to use.\n        /// </summary>\n        public string ClientSecret { get; set; }\n\n        /// <summary>\n        /// Dataverse Instance to connect too.\n        /// </summary>\n        public string Url { get; set; }\n    }\n\n}\n"
  },
  {
    "path": "src/Liquid.Dataverse/Extensions/DependencyInjection/IServiceCollectionExtensions.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Xrm.Sdk;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Dataverse.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Extension methods of <see cref=\"IServiceCollection\"/>\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Registers <see cref=\"LiquidDataverse\"/> service, it's dependency\n        /// <see cref=\"DataverseClientFactory\"/>, and also set configuration\n        /// option <see cref=\"DataverseSettings\"/>.\n        /// Also register <see cref=\"DataverseEntityMapper\"/> service.\n        /// </summary>\n        /// <param name=\"services\"></param>\n        /// <param name=\"dataverseSection\">configuration section of dataverse settings.</param>\n        public static IServiceCollection AddLiquidDataverseAdapter(this IServiceCollection services, string dataverseSection)\n        {\n            services.AddOptions<DataverseSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(dataverseSection).Bind(settings);\n            });\n\n            services.AddTransient<IDataverseClientFactory, DataverseClientFactory>();\n\n            services.AddSingleton<ILiquidDataverse, LiquidDataverse>();\n\n            services.AddSingleton<ILiquidMapper<string, Entity>, DataverseEntityMapper>();\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Dataverse/Extensions/EntityExtensions.cs",
    "content": "﻿using Microsoft.Xrm.Sdk;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text.Json;\n\nnamespace Liquid.Dataverse.Extensions\n{\n    /// <summary>\n    /// Extension methods of <see cref=\"Entity\"/>.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class EntityExtensions\n    {\n\n        /// <summary>\n        /// Converte os <see cref=\"AttributeCollection\"/>\n        /// para JsonString.\n        /// </summary>\n        /// <param name=\"entity\">Entidade origem.</param>\n        /// <returns></returns>\n        public static string ToJsonString(this Entity entity)\n        {\n            var resultSet = new Dictionary<string, object>();\n\n            foreach (var attribute in entity.Attributes)\n            {\n                resultSet.Add(attribute.Key, attribute.Value);\n            }\n\n            return JsonSerializer.Serialize(resultSet);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Dataverse/IDataverseClientFactory.cs",
    "content": "﻿using Microsoft.PowerPlatform.Dataverse.Client;\n\nnamespace Liquid.Dataverse\n{\n    /// <summary>\n    /// Defines Dataverse <see cref=\"ServiceClient\"/> provider.\n    /// </summary>\n    public interface IDataverseClientFactory\n    {\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"ServiceClient\"/>\n        /// connected too <see cref=\"DataverseSettings\"/> .\n        /// </summary>\n        IOrganizationServiceAsync GetClient();\n    }\n}"
  },
  {
    "path": "src/Liquid.Dataverse/ILiquidDataverse.cs",
    "content": "﻿using Microsoft.Xrm.Sdk;\nusing Microsoft.Xrm.Sdk.Metadata;\nusing Microsoft.Xrm.Sdk.Query;\n\nnamespace Liquid.Dataverse\n{\n    /// <summary>\n    /// Dataverse integration service definition.\n    /// </summary>\n    public interface ILiquidDataverse\n    {\n        /// <summary>\n        /// Insert an <see cref=\"Entity\"/> using additional parameters to optionally prevent custom synchronous logic execution, suppress Power Automate trigger and enforce duplicate detection rules evaluation.\n        /// </summary>\n        /// <param name=\"targetEntity\">entity definition.</param>\n        /// <param name=\"bypassSynchronousCustomLogic\"></param>\n        /// <param name=\"suppressPowerAutomateTrigger\"></param>\n        /// <param name=\"suppressDuplicateDetectionRules\"></param>\n        /// <returns>created entity Id.</returns>\n        Task<Guid> Create(Entity targetEntity, bool bypassSynchronousCustomLogic = false, bool suppressPowerAutomateTrigger = false, bool suppressDuplicateDetectionRules = true);\n\n        /// <summary>\n        /// Update an <see cref=\"Entity\"/> record using parameters to enforce optimistic concurrency, prevent custom synchronous logic execution, suppress Power Automate trigger, and enforce duplicate detection rules evaluation.\n        /// </summary>\n        /// <param name=\"entity\">entity definition.</param>\n        /// <param name=\"useOptimisticConcurrency\"></param>\n        /// <param name=\"bypassSynchronousCustomLogic\"></param>\n        /// <param name=\"suppressPowerAutomateTrigger\"></param>\n        /// <param name=\"suppressDuplicateDetectionRules\"></param>\n        Task Update(Entity entity, bool useOptimisticConcurrency = false, bool bypassSynchronousCustomLogic = false, bool suppressPowerAutomateTrigger = false, bool suppressDuplicateDetectionRules = true);\n\n        /// <summary>\n        /// Read <paramref name=\"entityName\"/> by <paramref name=\"id\"/>.\n        /// </summary>\n        /// <param name=\"id\">primarykey value.</param>\n        /// <param name=\"entityName\">table name.</param>\n        /// <param name=\"columns\"> column set should return.</param>\n        Task<Entity> GetById(Guid id, string entityName, ColumnSet? columns = null);\n\n        /// <summary>\n        /// Read table <paramref name=\"entityName\"/> according filter conditions.\n        /// </summary>\n        /// <param name=\"entityName\">table name.</param>\n        /// <param name=\"filter\">query conditions.</param>\n        /// <param name=\"columns\">conlumn se should return.</param>\n        Task<List<Entity>> ListByFilter(string entityName, FilterExpression filter, ColumnSet? columns = null);\n\n        /// <summary>\n        /// Exclude an item from <paramref name=\"entityName\"/> table by primarykey optionally using parameters to prevent custom synchronous logic execution and enforce optimistic concurrency.\n        /// </summary>\n        /// <param name=\"id\">primarykey value</param>\n        /// <param name=\"entityName\">table name.</param>\n        /// <param name=\"bypassSynchronousLogic\"></param>\n        /// <param name=\"useOptimisticConcurrency\"></param>\n        Task Delete(Guid id, string entityName, bool bypassSynchronousLogic = false, bool useOptimisticConcurrency = false);\n\n        /// <summary>\n        /// Read table <paramref name=\"entityName\"/> according query conditions.\n        /// </summary>\n        /// <param name=\"entityName\">table name.</param>\n        /// <param name=\"query\">query conditions</param>\n        Task<List<Entity>> ListByFilter(string entityName, QueryExpression query);\n\n        /// <summary>\n        /// Read table <paramref name=\"entityName\"/> properties.\n        /// </summary>\n        /// <param name=\"entityName\">table name.</param>\n        /// <returns><see cref=\"EntityMetadata\"/> set.</returns>\n        Task<EntityMetadata> GetMetadata(string entityName);\n\n        /// <summary>\n        /// Update state and status from an <see cref=\"Entity\"/>.\n        /// </summary>\n        /// <param name=\"entity\">entity reference.</param>\n        /// <param name=\"state\">new state value.</param>\n        /// <param name=\"status\">new status value.</param>\n        Task SetState(EntityReference entity, string state, string status);\n\n        /// <summary>\n        /// Insert or update an <see cref=\"Entity\"/>.\n        /// </summary>\n        /// <param name=\"entity\">entity definition.</param>\n        Task Upsert(Entity entity);\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Dataverse/Liquid.Dataverse.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid - Modern Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <Description>Adapter for Microsoft Dataverse integrations.\nThis component is part of Liquid Application Framework.</Description>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Identity.Client\" Version=\"4.72.0\" />\n    <PackageReference Include=\"Microsoft.PowerPlatform.Dataverse.Client\" Version=\"1.2.7\" />\n    <PackageReference Include=\"System.Security.Cryptography.Pkcs\" Version=\"8.0.1\" />\n    <PackageReference Include=\"System.Text.RegularExpressions\" Version=\"4.3.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"logo.png\">\n      <Pack>True</Pack>\n      <PackagePath>\\</PackagePath>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Dataverse/LiquidDataverse.cs",
    "content": "﻿using Microsoft.Crm.Sdk.Messages;\nusing Microsoft.PowerPlatform.Dataverse.Client;\nusing Microsoft.Xrm.Sdk;\nusing Microsoft.Xrm.Sdk.Messages;\nusing Microsoft.Xrm.Sdk.Metadata;\nusing Microsoft.Xrm.Sdk.Query;\n\nnamespace Liquid.Dataverse\n{\n    ///<inheritdoc/>\n    public class LiquidDataverse : ILiquidDataverse\n    {\n        private readonly IDataverseClientFactory _serviceFactory;\n        private readonly IOrganizationServiceAsync _client;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidDataverse\"/>\n        /// </summary>\n        /// <param name=\"serviceFactory\"></param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public LiquidDataverse(IDataverseClientFactory serviceFactory)\n        {\n            _serviceFactory = serviceFactory ?? throw new ArgumentNullException(nameof(serviceFactory));\n            _client = _serviceFactory.GetClient();\n        }\n\n        public async Task<Entity> GetById(Guid id, string entityName, ColumnSet? columns = null)\n        {\n            if (columns == null)\n                columns = new ColumnSet(true);\n\n            var result = await _client.RetrieveAsync(entityName, id, columns);\n\n            return result;\n        }\n\n        ///<inheritdoc/>\n        public async Task<List<Entity>> ListByFilter(string entityName, FilterExpression? filter = null, ColumnSet? columns = null)\n        {\n            List<Entity> results = new List<Entity>();\n\n            QueryExpression queryData = new QueryExpression(entityName);\n\n            if (filter != null)\n                queryData.Criteria = filter;\n\n            if (columns != null)\n                queryData.ColumnSet = columns;\n\n            var result = await _client.RetrieveMultipleAsync(queryData);\n            if (result?.Entities != null)\n            {\n                foreach (var item in result.Entities)\n                {\n                    results.Add(item);\n                }\n            }\n\n            return results;\n        }\n\n        ///<inheritdoc/>\n        public async Task<List<Entity>> ListByFilter(string entityName, QueryExpression query)\n        {\n            if (query is null)\n            {\n                throw new ArgumentNullException(nameof(query));\n            }\n\n            List<Entity> results = new List<Entity>();\n\n            var result = await _client.RetrieveMultipleAsync(query);\n\n            if (result?.Entities != null)\n            {\n                foreach (var item in result.Entities)\n                {\n                    results.Add(item);\n                }\n            }\n\n            return results;\n        }\n\n        ///<inheritdoc/>\n        public async Task<EntityMetadata> GetMetadata(string entityName)\n        {\n            var retrieveEntityRequest = new RetrieveEntityRequest\n            {\n                EntityFilters = EntityFilters.All,\n                LogicalName = entityName\n            };\n            var response = await _client.ExecuteAsync(retrieveEntityRequest);\n            var metadata = (RetrieveEntityResponse)response;\n            return metadata.EntityMetadata;\n        }\n\n        ///<inheritdoc/>\n        public async Task SetState(EntityReference entity, string state, string status)\n        {\n            var setStateRequest = new SetStateRequest()\n            {\n                EntityMoniker = new EntityReference\n                {\n                    Id = entity.Id,\n                    LogicalName = entity.LogicalName,\n                },\n                State = new OptionSetValue(int.Parse(state)),\n                Status = new OptionSetValue(int.Parse(status))\n            };\n\n            await _client.ExecuteAsync(setStateRequest);\n        }\n\n        ///<inheritdoc/>\n        public async Task Upsert(Entity entity)\n        {\n            var request = new UpsertRequest()\n            {\n                Target = entity\n            };\n\n            await _client.ExecuteAsync(request);\n        }\n\n        ///<inheritdoc/>\n        public Task<Guid> Create(Entity targetEntity, bool bypassSynchronousCustomLogic = false, bool suppressPowerAutomateTrigger = false, bool suppressDuplicateDetectionRules = true)\n        {\n            var createRequest = new CreateRequest\n            {\n                Target = targetEntity\n            };\n\n            createRequest.Parameters.Add(\"BypassCustomPluginExecution\", bypassSynchronousCustomLogic);\n            createRequest.Parameters.Add(\"SuppressCallbackRegistrationExpanderJob\", suppressPowerAutomateTrigger);\n            createRequest.Parameters.Add(\"SuppressDuplicateDetection\", suppressDuplicateDetectionRules);\n\n            var resultCreate = (CreateResponse)_client.Execute(createRequest);\n\n            return Task.FromResult(resultCreate.id);\n        }\n\n        ///<inheritdoc/>\n        public async Task Update(Entity entity, bool useOptimisticConcurrency = false, bool bypassSynchronousCustomLogic = false, bool suppressPowerAutomateTrigger = false, bool suppressDuplicateDetectionRules = true)\n        {\n            var updateRequest = new UpdateRequest\n            {\n                Target = entity\n            };\n\n            if (useOptimisticConcurrency)\n            {\n                updateRequest.ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches;\n            }\n            updateRequest.Parameters.Add(\"BypassCustomPluginExecution\", bypassSynchronousCustomLogic);\n            updateRequest.Parameters.Add(\"SuppressCallbackRegistrationExpanderJob\", suppressPowerAutomateTrigger);\n            updateRequest.Parameters.Add(\"SuppressDuplicateDetection\", suppressDuplicateDetectionRules);\n\n            await _client.ExecuteAsync(updateRequest);\n        }\n\n        ///<inheritdoc/>\n        public async Task Delete(Guid id, string entityName, bool bypassSynchronousLogic = false, bool useOptimisticConcurrency = false)\n        {\n            var deleteRequest = new DeleteRequest\n            {\n                Target = new EntityReference(entityName, id)\n            };\n\n            if (useOptimisticConcurrency)\n            {\n                deleteRequest.ConcurrencyBehavior = ConcurrencyBehavior.IfRowVersionMatches;\n            }\n\n            deleteRequest.Parameters.Add(\"BypassCustomPluginExecution\", bypassSynchronousLogic);\n\n            await _client.ExecuteAsync(deleteRequest);\n        }\n\n    }\n}"
  },
  {
    "path": "src/Liquid.GenAi.OpenAi/Extensions/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.GenAi;\nusing Liquid.GenAi.OpenAi.Settings;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.GenAi.OpenAi.Extensions\n{\n    /// <summary>\n    /// Extension methods to register Liquid OpenAi Completions services.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionExtension\n    {\n        /// <summary>\n        /// extension method to register Liquid OpenAi Completions service,\n        /// factory and binding settings from configuration.\n        /// </summary>\n        /// <param name=\"services\">extension method reference</param>\n        /// <param name=\"sectionName\">configuration section name</param> \n        public static IServiceCollection AddLiquidOpenAiCompletions(this IServiceCollection services, string sectionName)\n        {\n            services.AddOptions<OpenAiOptions>()\n               .Configure<IConfiguration>((settings, configuration) =>\n               {\n                   configuration.GetSection(sectionName).Bind(settings);\n               });\n\n            services.AddSingleton<IOpenAiClientFactory, OpenAiClientFactory>();\n            services.AddTransient<ILiquidGenAi, OpenAiAdapter>();\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.GenAi.OpenAi/IOpenAiClientFactory.cs",
    "content": "﻿using OpenAI.Chat;\n\nnamespace Liquid.GenAi.OpenAi\n{\n    /// <summary>\n    /// Provide <see cref=\"ChatClient\"/> generator methods.\n    /// </summary>\n    public interface IOpenAiClientFactory\n    {\n        /// <summary>\n        /// Provide a instance of <see cref=\"ChatClient\"/> with conection started.\n        /// </summary>\n        /// <param name=\"clientId\">OpenAI connections alias.</param>\n        ChatClient GetOpenAIClient(string clientId);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.GenAi.OpenAi/Liquid.GenAi.OpenAi.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\t  <PackageId>Liquid.GenAi.OpenAi</PackageId>\n\t  <Nullable>enable</Nullable>\n\t  <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.1.1</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <DebugType>Full</DebugType>\n\t  <Description>\n\t\t  Liquid adapter for Azure OpenAi completions.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n\t<ItemGroup>\n\t\t<None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n\t\t\t<PackagePath></PackagePath>\n\t\t\t<Pack>True</Pack>\n\t\t</None>\n\t</ItemGroup>\n\t\n  <ItemGroup>\n\t  <PackageReference Include=\"Azure.AI.OpenAI\" Version=\"2.1.0-beta.2\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.1.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.GenAi.OpenAi/OpenAiAdapter.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.GenAi;\nusing Liquid.Core.GenAi.Entities;\nusing Liquid.Core.GenAi.Enums;\nusing Liquid.Core.GenAi.Settings;\nusing OpenAI.Chat;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.GenAi.OpenAi\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    public class OpenAiAdapter : ILiquidGenAi\n    {\n\n        private readonly IOpenAiClientFactory _factory;\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"OpenAiAdapter\"/>\n        /// </summary>\n        /// <param name=\"factory\">Open IA client Factory.</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public OpenAiAdapter(IOpenAiClientFactory factory)\n        {\n            _factory = factory ?? throw new ArgumentNullException(nameof(factory));\n        }\n\n        ///<inheritdoc/>\n        public async Task<ChatCompletionResult> FunctionCalling(LiquidChatMessages messages, List<FunctionBody> functions, CompletionsOptions settings)\n        {\n            var client = _factory.GetOpenAIClient(settings.ClientId);\n\n            var requestMessages = new List<ChatMessage>();\n\n            messages.Messages.ForEach(m => requestMessages.Add(MapChatRequestMessage(m)));\n\n            var option = MapChatCompletionOptions(settings);\n\n            functions.ForEach(f => option.Tools.Add(ChatTool.CreateFunctionTool(f.Name, f.Description, f.Parameters)));\n\n            var responseWithoutStream = await client.CompleteChatAsync(requestMessages, option);\n            var response = responseWithoutStream.Value.Content[0].Text;\n\n            var result = new ChatCompletionResult()\n            {\n                FinishReason = responseWithoutStream.Value.FinishReason.ToString(),\n                Content = response,\n                Usage = responseWithoutStream.Value.Usage.TotalTokenCount,\n                PromptUsage = responseWithoutStream.Value.Usage.InputTokenCount,\n                CompletionUsage = responseWithoutStream.Value.Usage.OutputTokenCount,\n            };\n\n            return result;\n        }\n\n        ///<inheritdoc/>\n        public async Task<ChatCompletionResult> CompleteChatAsync(string content, string prompt, CompletionsOptions settings, LiquidChatMessages chatHistory = null)\n        {\n            var client = _factory.GetOpenAIClient(settings.ClientId);\n\n            var messages = GetChatMessagesAsync(content, prompt, chatHistory);\n\n            var option = MapChatCompletionOptions(settings);\n\n            var responseWithoutStream = await client.CompleteChatAsync(messages, option);\n            var response = responseWithoutStream.Value.Content[0].Text;\n\n            var result = new ChatCompletionResult()\n            {\n                FinishReason = responseWithoutStream.Value.FinishReason.ToString(),\n                Content = response,\n                Usage = responseWithoutStream.Value.Usage.TotalTokenCount,\n                PromptUsage = responseWithoutStream.Value.Usage.InputTokenCount,\n                CompletionUsage = responseWithoutStream.Value.Usage.OutputTokenCount,\n            };\n\n            return result;\n        }\n\n        ///<inheritdoc/>\n        public async Task<ChatCompletionResult> CompleteChatAsync(LiquidChatMessages messages, CompletionsOptions settings, List<FunctionBody> functions = null, LiquidChatMessages chatHistory = null)\n        {\n            var client = _factory.GetOpenAIClient(settings.ClientId);\n\n            var requestMessages = new List<ChatMessage>();\n\n            messages.Messages.ForEach(m => requestMessages.Add(MapChatRequestMessage(m)));\n\n            var option = MapChatCompletionOptions(settings);           \n\n            if (functions != null)\n            {\n                functions.ForEach(f => option.Tools.Add(ChatTool.CreateFunctionTool(f.Name, f.Description, f.Parameters)));\n            }\n\n            if (chatHistory?.Messages != null && chatHistory.Messages.Count > 0)\n            {\n                foreach (var message in chatHistory.Messages)\n                {\n                    requestMessages.Add(MapChatRequestMessage(message));\n                }\n            }\n\n            var responseWithoutStream = await client.CompleteChatAsync(requestMessages, option);\n\n\n            var response = responseWithoutStream.Value.FinishReason != ChatFinishReason.ToolCalls ?\n                responseWithoutStream.Value.Content[0].Text :\n                responseWithoutStream.Value.ToolCalls[0].FunctionArguments.ToString();\n\n            var result = new ChatCompletionResult()\n            {\n                FinishReason = responseWithoutStream.Value.FinishReason.ToString(),\n                Content = response,\n                Usage = responseWithoutStream.Value.Usage.TotalTokenCount,\n                PromptUsage = responseWithoutStream.Value.Usage.InputTokenCount,\n                CompletionUsage = responseWithoutStream.Value.Usage.OutputTokenCount,\n            };\n\n            return result;\n        }\n\n        /// <summary>\n        /// get chat messages for a chat completions request.\n        /// </summary>\n        /// <param name=\"content\">content of the user message</param>\n        /// <param name=\"prompt\">prompt message</param>\n        /// <param name=\"chatHistory\">chat context messages</param>\n        private static List<ChatMessage> GetChatMessagesAsync(string content, string prompt, LiquidChatMessages? chatHistory = null)\n        {\n            var messages = new List<ChatMessage>\n            {\n                new SystemChatMessage(prompt)\n            };\n\n            if (chatHistory?.Messages != null && chatHistory.Messages.Count > 0)\n            {\n                foreach (var message in chatHistory.Messages)\n                {\n                    messages.Add(MapChatRequestMessage(message));\n                }\n            }\n\n            messages.Add(new UserChatMessage(content));\n\n            return messages;\n        }\n\n        /// <summary>\n        /// Return a chat request message based on the role of the message.\n        /// </summary>\n        /// <param name=\"message\">chat message</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        private static ChatMessage MapChatRequestMessage(LiquidChatMessage message)\n        {\n            ChatMessage? chatRequestMessage = null;\n            switch (message.Role)\n            {\n                case LiquidMessageRole.System:\n                    chatRequestMessage = new SystemChatMessage(CreateContent(message));\n                    break;\n                case LiquidMessageRole.Assistant:\n                    chatRequestMessage = new AssistantChatMessage(CreateContent(message));\n                    break;\n                case LiquidMessageRole.User:\n                    chatRequestMessage = new UserChatMessage(CreateContent(message));\n                    break;\n                default:\n                    break;\n            }\n\n            if (chatRequestMessage == null)\n            {\n                throw new ApplicationException($\"The folowing message is invalid: {message}\");\n            }\n\n            return chatRequestMessage;\n        }\n\n        private static IEnumerable<ChatMessageContentPart> CreateContent(LiquidChatMessage message)\n        {\n            var messageList = message.Content.ToList();\n\n            var content = new List<ChatMessageContentPart>();\n\n            messageList.ForEach(x => content.Add(x.Kind == LiquidContentKind.Text ?\n                ChatMessageContentPart.CreateTextPart(x.Text) :\n                ChatMessageContentPart.CreateImagePart(x.ImageUri)));\n\n            return content;\n        }\n\n        /// <summary>\n        /// Return a chat completions options based on the chat completions settings.\n        /// </summary>\n        /// <param name=\"settings\">Chat completions settings</param>\n        /// <returns></returns>\n        private static ChatCompletionOptions MapChatCompletionOptions(CompletionsOptions settings)\n        {\n            return new ChatCompletionOptions()\n            {\n                Temperature = settings.Temperature,\n                MaxOutputTokenCount = settings.MaxTokens,\n                TopP = settings.TopP,\n                FrequencyPenalty = settings.FrequencyPenalty,\n                PresencePenalty = settings.PresencePenalty\n\n            };\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.GenAi.OpenAi/OpenAiClientFactory.cs",
    "content": "﻿using Azure;\nusing Azure.AI.OpenAI;\nusing Liquid.Core.Entities;\nusing Liquid.GenAi.OpenAi.Settings;\nusing Microsoft.Extensions.Options;\nusing OpenAI.Chat;\nusing System.ClientModel.Primitives;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.GenAi.OpenAi\n{\n    ///<inheritdoc/>\n    public class OpenAiClientFactory : IOpenAiClientFactory\n    {\n        private readonly IOptions<OpenAiOptions> _settings;\n        private readonly List<ClientDictionary<ChatClient>> _openAiClients;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"OpenAiClientFactory\"/>\n        /// </summary>\n        /// <param name=\"settings\">Connection options.</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public OpenAiClientFactory(IOptions<OpenAiOptions> settings)\n        {\n            _settings = settings ?? throw new ArgumentNullException(nameof(settings));\n            _openAiClients = new List<ClientDictionary<ChatClient>>();\n        }\n\n        ///<inheritdoc/>\n        public ChatClient GetOpenAIClient(string clientId)\n        {\n            var settings = _settings.Value.Settings.Where(x => x.ClientId == clientId).ToList();\n\n            if (settings.Count == 0)\n            {\n                throw new KeyNotFoundException($\"No settings found for client ID: {clientId}\");\n            }\n\n            var clientDefinition = _openAiClients.Where(x => x.ClientId == clientId)?.MinBy(x => x.Executions);\n\n            if (clientDefinition != null)\n            {\n                clientDefinition.Executions++;\n                return clientDefinition.Client;\n            }\n\n            var response = CreateClient(settings, clientId);\n\n            if (response == null)\n            {\n                throw new KeyNotFoundException($\"No settings found for client ID: {clientId}\");\n            }\n\n            return response;\n        }\n\n        private ChatClient? CreateClient(List<OpenAiSettings>? settings, string clientId)\n        {\n            if (settings == null || settings.Count == 0)\n            {\n                throw new ArgumentNullException(nameof(settings));\n            }\n\n            ChatClient? client = null;\n\n            foreach (var setting in settings)\n            {\n                var options = new AzureOpenAIClientOptions();\n\n                options.RetryPolicy = new ClientRetryPolicy(setting.MaxRetries);\n\n                AzureOpenAIClient azureClient = new(new Uri(setting.Url), new AzureKeyCredential(setting.Key), options);\n\n                client = azureClient.GetChatClient(setting.DeploymentName);\n\n                _openAiClients.Add(new ClientDictionary<ChatClient>(setting.ClientId, client));\n            }\n\n            var result = _openAiClients.Where(x => x.ClientId == clientId).MinBy(x => x.Executions);\n\n            return result?.Client;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.GenAi.OpenAi/Settings/OpenAiOptions.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.GenAi.OpenAi.Settings\n{\n    /// <summary>\n    /// The options for chat completions request.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class OpenAiOptions\n    {\n        /// <summary>\n        /// Client connection list to use for create OpenAi clients.\n        /// </summary>\n        public List<OpenAiSettings> Settings { get; set; }\n    }\n\n    /// <summary>\n    /// The settings for chat completions request.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class OpenAiSettings\n    {\n        /// <summary>\n        /// Client connection alias.\n        /// </summary>\n        public string ClientId { get; set; }\n        /// <summary>\n        /// The URI for an GenAI resource as retrieved from, for example, Azure Portal.\n        ///This should include protocol and hostname.\n        /// </summary>\n        public string Url { get; set; }\n\n        /// <summary>\n        /// Key to use to authenticate with the service.\n        /// </summary>\n        public string Key { get; set; }\n\n        /// <summary>\n        /// The deployment name to use for a chat completions request.\n        /// </summary>\n        public string DeploymentName { get; set; }\n\n        /// <summary>\n        /// The maximum number of retries to allow.\n        /// </summary>\n        public int MaxRetries { get; set; } = 0;        \n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/Extensions/DependencyInjection/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.Kafka.Settings;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System.Reflection;\n\nnamespace Liquid.Messaging.Kafka.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Startup extension methods. Used to configure the startup application.\n    /// </summary>\n    public static class IServiceCollectionExtension\n    {\n\n        /// <summary>\n        /// Register a <see cref=\"KafkaConsumer{TEntity}\"/> with its dependency, and with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddSingletonLiquidTelemetry{TInterface, TService}(IServiceCollection)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service instance.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        public static IServiceCollection AddLiquidKafkaProducer<TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n        {\n            services.TryAddTransient<IKafkaFactory, KafkaFactory>();\n            services.AddOptions<KafkaSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(sectionName).Bind(settings);\n            });\n            if (activateTelemetry)\n            {\n                services.AddSingleton<KafkaProducer<TEntity>>();\n                services.AddSingletonLiquidTelemetry<ILiquidProducer<TEntity>, KafkaProducer<TEntity>>();\n            }\n            else\n            {\n                services.AddSingleton<ILiquidProducer<TEntity>, KafkaProducer<TEntity>>();\n            }\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register Liquid resources for consumers \n        /// <see cref=\"IServiceCollectionCoreExtensions.AddLiquidMessageConsumer{TService, TEntity}(IServiceCollection, Assembly[])\"/>\n        /// and a <see cref=\"KafkaConsumer{TEntity}\"/> service with its dependency, with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddLiquidTelemetryInterceptor{TInterface, TService}(IServiceCollection)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service instance.</typeparam>\n        /// <typeparam name=\"TWorker\">Type of implementation from <see cref=\"ILiquidWorker{TEntity}\"/></typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        /// <param name=\"assemblies\">Array of assemblies that contains domain handlers implementation.</param>\n        public static IServiceCollection AddLiquidKafkaConsumer<TWorker, TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true, params Assembly[] assemblies)\n             where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddLiquidMessageConsumer<TWorker, TEntity>(assemblies);\n\n            services.AddConsumer<TEntity>(sectionName, activateTelemetry);\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register a <see cref=\"KafkaConsumer{TEntity}\"/> service with its dependency, and with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddLiquidTelemetryInterceptor{TInterface, TService}(IServiceCollection)\"/>.\n        /// In order for consumers injected by this method to work correctly and \n        /// domain handlers/services in your build configurator.\n        /// </summary>\n        /// <typeparam name=\"TWorker\">Type of implementation from <see cref=\"ILiquidWorker{TEntity}\"/></typeparam>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by the service instance.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        public static IServiceCollection AddLiquidKafkaConsumer<TWorker, TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n            where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddLiquidWorkerService<TWorker, TEntity>();\n\n            services.AddConsumer<TEntity>(sectionName, activateTelemetry);\n\n            return services;\n        }\n\n        private static IServiceCollection AddConsumer<TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n        {\n            services.AddTransient<IKafkaFactory, KafkaFactory>();\n\n            services.AddOptions<KafkaSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(sectionName).Bind(settings);\n            });\n\n            if (activateTelemetry)\n            {\n                services.AddSingleton<KafkaConsumer<TEntity>>();\n\n\n                services.AddSingletonLiquidTelemetry<ILiquidConsumer<TEntity>, KafkaConsumer<TEntity>>();\n            }\n            else\n            {\n                services.AddSingleton<ILiquidConsumer<TEntity>, KafkaConsumer<TEntity>>();\n            }\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/Extensions/HeadersExtension.cs",
    "content": "﻿using Confluent.Kafka;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text;\n\nnamespace Liquid.Messaging.Kafka.Extensions\n{\n    /// <summary>\n    /// Kafka Extensions Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    internal static class HeadersExtension\n    {\n        /// <summary>\n        /// Adds the custom headers.\n        /// </summary>\n        /// <param name=\"messageAttributes\">The message attributes.</param>\n        /// <param name=\"customHeaders\">The custom headers.</param>\n        public static Headers AddCustomHeaders(this Headers messageAttributes, IDictionary<string, object> customHeaders)\n        {\n            foreach (var (key, value) in customHeaders)\n            {\n                if (value != null)\n                {\n                    messageAttributes.Add(key, Encoding.UTF8.GetBytes(value.ToString()));\n                }\n            }\n\n            return messageAttributes;\n        }\n\n        /// <summary>\n        /// Gets the custom headers.\n        /// </summary>\n        /// <param name=\"messageAttributes\">The message attributes.</param>\n        /// <returns></returns>\n        public static Dictionary<string, object> GetCustomHeaders(this Headers messageAttributes)\n        {\n            var returnValue = new Dictionary<string, object>();\n\n            foreach (var header in messageAttributes)\n            {\n                returnValue.TryAdd(header.Key, Encoding.UTF8.GetString(header.GetValueBytes()));\n            }\n\n            return returnValue;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/IKafkaFactory.cs",
    "content": "﻿using Confluent.Kafka;\nusing Liquid.Messaging.Kafka.Settings;\nusing System;\n\nnamespace Liquid.Messaging.Kafka\n{\n    /// <summary>\n    /// Provides new instances if Kafka <see cref=\"IConsumer{TKey, TValue}\"/> and <see cref=\"IProducer{TKey, TValue}\"/>.\n    /// </summary>\n    public interface IKafkaFactory\n    {\n        /// <summary>\n        /// Create a new instance of a high-level Apache Kafka consumer with deserialization capability.\n        /// </summary>\n        /// <param name=\"settings\">Consumer configuration set.</param>\n        IConsumer<Ignore, string> GetConsumer(KafkaSettings settings);\n\n        /// <summary>\n        /// Create a neu instance of a high level producer with serialization capability.\n        /// </summary>\n        /// <param name=\"settings\">Consumer configuration set.</param>\n        IProducer<Null, string> GetProducer(KafkaSettings settings);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/KafkaConsumer.cs",
    "content": "﻿using Confluent.Kafka;\nusing Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.Kafka.Extensions;\nusing Liquid.Messaging.Kafka.Settings;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.Kafka\n{\n    ///<inheritdoc/>\n    public class KafkaConsumer<TEntity> : ILiquidConsumer<TEntity>\n    {\n        private readonly IKafkaFactory _factory;\n        private readonly KafkaSettings _settings;\n        private IConsumer<Ignore, string> _client;\n\n\n        ///<inheritdoc/>\n        public event Func<ConsumerMessageEventArgs<TEntity>, CancellationToken, Task> ConsumeMessageAsync;\n\n        ///<inheritdoc/>\n        public event Func<ConsumerErrorEventArgs, Task> ProcessErrorAsync;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"KafkaConsumer{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"kafkaFactory\">Kafka client provider service.</param>\n        /// <param name=\"kafkaSettings\">Configuration properties set.</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public KafkaConsumer(IKafkaFactory kafkaFactory, IOptions<KafkaSettings> kafkaSettings)\n        {\n            _factory = kafkaFactory ?? throw new ArgumentNullException(nameof(kafkaFactory));\n            _settings = kafkaSettings?.Value ?? throw new ArgumentNullException(nameof(kafkaSettings));\n        }\n\n        ///<inheritdoc/>\n        public Task RegisterMessageHandler(CancellationToken cancellationToken = default)\n        {\n            if (ConsumeMessageAsync is null)\n            {\n                throw new NotImplementedException($\"The {nameof(ProcessErrorAsync)} action must be added to class.\");\n            }\n\n            ProcessErrorAsync += ProcessError;\n\n            _client = _factory.GetConsumer(_settings);\n\n\n            var task = Task.Run( async () =>\n            {\n                using (_client)\n                {\n                    _client.Subscribe(_settings.Topic);\n\n                    await MessageHandler(cancellationToken);                    \n                }\n            });\n\n            return task;\n        }\n\n        /// <summary>\n        /// Process incoming messages.\n        /// </summary>\n        /// <param name=\"cancellationToken\"> Propagates notification that operations should be canceled.</param>\n        protected async Task MessageHandler(CancellationToken cancellationToken)\n        {\n            try\n            {\n                while (!cancellationToken.IsCancellationRequested)\n                {\n                    var deliverEvent = _client.Consume(cancellationToken);\n\n                    _ = Task.Run(async () =>\n                    {\n                        try\n                        {\n                            await ConsumeMessageAsync(GetEventArgs(deliverEvent), cancellationToken);\n\n                            if (!_settings.EnableAutoCommit)\n                            {\n                                _client.Commit(deliverEvent);\n                            }\n                        }\n                        catch (Exception ex)\n                        {    \n                            var errorArgs = new ConsumerErrorEventArgs\n                            {\n                                Exception = ex,\n                            };\n\n                            await ProcessErrorAsync(errorArgs);\n                        }\n                    });                    \n                }\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingConsumerException(ex);\n            }\n        }\n\n        private ConsumerMessageEventArgs<TEntity> GetEventArgs(ConsumeResult<Ignore, string> deliverEvent)\n        {\n            var headers = deliverEvent.Message.Headers.GetCustomHeaders();\n\n            var options = new JsonSerializerOptions\n            {\n                PropertyNameCaseInsensitive = true\n            };\n\n            var data = JsonSerializer.Deserialize<TEntity>(deliverEvent.Message.Value, options);\n\n            return new ConsumerMessageEventArgs<TEntity> { Data = data, Headers = headers };\n        }\n\n        private Task ProcessError(ConsumerErrorEventArgs args)\n        {\n            _client.Close();\n            throw args.Exception;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/KafkaFactory.cs",
    "content": "﻿using Confluent.Kafka;\nusing Liquid.Core.Exceptions;\nusing Liquid.Messaging.Kafka.Settings;\nusing System;\n\nnamespace Liquid.Messaging.Kafka\n{\n    ///<inheritdoc/>\n    public class KafkaFactory : IKafkaFactory\n    {\n        ///<inheritdoc/>\n        public IConsumer<Ignore, string> GetConsumer(KafkaSettings settings)\n        {  \n            try\n            {\n                var config = MapConsumerSettings(settings);\n\n                var client = new ConsumerBuilder<Ignore, string>(config).Build();\n\n                return client;\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, \"for topic '\" + settings?.Topic + \"'\");\n            }\n        }\n\n        ///<inheritdoc/>\n        public IProducer<Null, string> GetProducer(KafkaSettings settings)\n        {\n            try\n            {\n                var config = MapProducerSettings(settings);\n\n                return new ProducerBuilder<Null, string>(config).Build();\n            }\n            catch(Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, \"for topic '\" + settings?.Topic + \"'\");\n            }\n        }\n\n        private static ConsumerConfig MapConsumerSettings(KafkaSettings settings)\n        {\n            if(settings == null)\n                throw new ArgumentNullException(nameof(settings));\n\n            return new ConsumerConfig\n            {\n                SocketKeepaliveEnable = settings.SocketKeepAlive,\n                SocketTimeoutMs = settings.Timeout,\n                BootstrapServers = settings.ConnectionString,\n                ClientId = settings.ConnectionId,\n                EnableAutoCommit = settings.EnableAutoCommit,\n                GroupId = settings.GroupId\n            };\n        }\n\n        private static ProducerConfig MapProducerSettings(KafkaSettings settings)\n        {\n            if (settings == null)\n                throw new ArgumentNullException(nameof(settings));\n\n            return new ProducerConfig\n            {\n                SocketKeepaliveEnable = settings.SocketKeepAlive,\n                SocketTimeoutMs = settings.Timeout,\n                BootstrapServers = settings.ConnectionString,\n                ClientId = settings.ConnectionId,\n            };\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/KafkaProducer.cs",
    "content": "﻿using Confluent.Kafka;\nusing Liquid.Core.Utils;\nusing Liquid.Core.Extensions;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.Kafka.Extensions;\nusing Liquid.Messaging.Kafka.Settings;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\n\nnamespace Liquid.Messaging.Kafka\n{\n    ///<inheritdoc/>\n    public class KafkaProducer<TEntity> : ILiquidProducer<TEntity>\n    {\n        private readonly IProducer<Null, string> _client;\n        private readonly KafkaSettings _settings;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"KafkaProducer{TEntity}\"/> class.\n        /// </summary>\n        /// <param name=\"settings\"></param>\n        /// <param name=\"factory\"></param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public KafkaProducer(IOptions<KafkaSettings> settings, IKafkaFactory factory)\n        {\n            if (factory is null)\n            {\n                throw new ArgumentNullException(nameof(factory));\n            }\n\n            _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));\n\n            _client = factory.GetProducer(_settings);\n        }\n\n        ///<inheritdoc/>\n        public async Task SendMessagesAsync(IEnumerable<TEntity> messageBodies)\n        {\n            try\n            {\n                foreach (var message in messageBodies)\n                {\n                    await SendMessageAsync(message);\n                }\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingProducerException(ex);\n            }\n        }\n\n        ///<inheritdoc/>\n        public async Task SendMessageAsync(TEntity messageBody, IDictionary<string, object> customProperties = null)\n        {            \n            try\n            {\n                var message = GetMessage(messageBody, customProperties);\n\n                await _client.ProduceAsync(_settings.Topic, message);\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingProducerException(ex);\n            }\n        }\n\n        private Message<Null, string> GetMessage(TEntity messageBody, IDictionary<string, object> customProperties)\n        {\n            var message = !_settings.CompressMessage ? messageBody.ToJsonString() : Encoding.UTF8.GetString(messageBody.ToJsonString().GzipCompress());\n\n            var request = new Message<Null, string>\n            {\n                Value = message,\n                Headers = customProperties is null ? null : new Headers().AddCustomHeaders(customProperties)\n            };\n            return request;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/Liquid.Messaging.Kafka.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t  <PackageId>Liquid.Messaging.Kafka</PackageId>\n\t  <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid - Modern Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <Description>\n\t\t  The Liquid.Messaging.Kafka provides producer and consumer patterns to allow the send and consumption of Messaging inside your microservice.\n\t\t  This component allows send and consuming messages from Kafka.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n      <PackagePath></PackagePath>\n      <Pack>True</Pack>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Confluent.Kafka\" Version=\"2.10.0\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Liquid.Messaging.Kafka/Settings/KafkaSettings.cs",
    "content": "﻿using Liquid.Core.Attributes;\n\nnamespace Liquid.Messaging.Kafka.Settings\n{\n    /// <summary>\n    /// Kafka configuration properties set.\n    /// </summary>\n    [LiquidSectionName(\"liquid:messaging:kafka:\")]\n    public class KafkaSettings\n    {\n        /// <summary>\n        /// Bootstrap server connection string.\n        /// </summary>\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// Socket keep alive flag.\n        /// </summary>\n        public bool SocketKeepAlive { get; set; }\n                \n        /// <summary>\n        /// Client identifier.\n        /// </summary>\n        public string ConnectionId { get; set; }\n\n        /// <summary>\n        /// Topic to consumer subscribe to. A regex can be specified to subscribe to the set of\n        /// all matching topics.\n        /// </summary>\n        public string Topic { get; set; }\n\n        /// <summary>\n        /// Default timeout for network requests.Producer: ProduceRequests will use the \n        /// lesser value of `socket.timeout.ms` and remaining `message.timeout.ms` for the \n        /// first message in the batch. Consumer: FetchRequests will use `fetch.wait.max.ms` \n        /// + `socket.timeout.ms`. Admin: Admin requests will use `socket.timeout.ms` or \n        /// explicitly set `rd_kafka_AdminOptions_set_operation_timeout()` value. default: 60000\n        /// </summary>\n        public int Timeout { get; set; } = 6000;\n\n        /// <summary>\n        /// Automatically and periodically commit offsets in the background. Note: setting\n        /// this to false does not prevent the consumer from fetching previously committed\n        /// start offsets. default: true \n        /// </summary>\n        public bool EnableAutoCommit { get; set; } = true;\n\n        /// <summary>\n        /// Indicates whether to be a compressed message.\n        /// </summary>\n        public bool CompressMessage { get; set; }\n\n        /// <summary>\n        /// Client group id string. All clients sharing the same group.id belong to the same group.\n        /// </summary>\n        public string GroupId { get; set; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Extensions/DependencyInjection/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.RabbitMq.Settings;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System.Reflection;\n\nnamespace Liquid.Messaging.RabbitMq.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Startup extension methods. Used to configure the startup application.\n    /// </summary>\n    public static class IServiceCollectionExtension\n    {\n\n        /// <summary>\n        /// Register a <see cref=\"RabbitMqConsumer{TEntity}\"/> with its dependency, and with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddSingletonLiquidTelemetry{TInterface, TService}(IServiceCollection)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service instance.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        public static IServiceCollection AddLiquidRabbitMqProducer<TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n        {\n            services.TryAddTransient<IRabbitMqFactory, RabbitMqFactory>();\n\n            services.AddOptions<RabbitMqProducerSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(sectionName).Bind(settings);\n            });\n\n            if (activateTelemetry)\n            {\n                services.AddSingleton<RabbitMqProducer<TEntity>>();\n                services.AddSingletonLiquidTelemetry<ILiquidProducer<TEntity>, RabbitMqProducer<TEntity>>();\n            }\n            else\n            {\n                services.AddSingleton<ILiquidProducer<TEntity>, RabbitMqProducer<TEntity>>();\n            }\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register Liquid resources for consumers \n        /// <see cref=\"IServiceCollectionCoreExtensions.AddLiquidMessageConsumer{TService, TEntity}(IServiceCollection, Assembly[])\"/>\n        /// and a <see cref=\"RabbitMqConsumer{TEntity}\"/> service with its dependency, with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddLiquidTelemetryInterceptor{TInterface, TService}(IServiceCollection)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service instance.</typeparam>\n        /// <typeparam name=\"TWorker\">Type of implementation from <see cref=\"ILiquidWorker{TEntity}\"/></typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        /// <param name=\"assemblies\">Array of assemblies that contains domain handlers implementation.</param>\n        public static IServiceCollection AddLiquidRabbitMqConsumer<TWorker, TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true, params Assembly[] assemblies)\n             where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddLiquidMessageConsumer<TWorker, TEntity>(assemblies);\n\n            services.AddConsumer<TEntity>(sectionName, activateTelemetry);\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register a <see cref=\"RabbitMqConsumer{TEntity}\"/> service with its dependency, and with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddLiquidTelemetryInterceptor{TInterface, TService}(IServiceCollection)\"/>.\n        /// In order for consumers injected by this method to work correctly, you will need to register the Liquid settings and \n        /// domain handlers/services in your build configurator.\n        /// </summary>\n        /// <typeparam name=\"TWorker\">Type of implementation from <see cref=\"ILiquidWorker{TEntity}\"/></typeparam>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by the service instance.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        public static IServiceCollection AddLiquidRabbitMqConsumer<TWorker, TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n            where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddLiquidWorkerService<TWorker, TEntity>();\n\n            services.AddConsumer<TEntity>(sectionName, activateTelemetry);\n\n            return services;\n        }\n\n        private static IServiceCollection AddConsumer<TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n        {\n            services.AddSingleton<IRabbitMqFactory, RabbitMqFactory>();\n\n            services.AddOptions<RabbitMqConsumerSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(sectionName).Bind(settings);\n            });\n\n            if (activateTelemetry)\n            {\n                services.AddSingleton<RabbitMqConsumer<TEntity>>();\n\n                services.AddSingletonLiquidTelemetry<ILiquidConsumer<TEntity>, RabbitMqConsumer<TEntity>>();\n            }\n            else\n            {\n                services.AddSingleton<ILiquidConsumer<TEntity>, RabbitMqConsumer<TEntity>>();\n            }\n\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/IRabbitMqFactory.cs",
    "content": "﻿using Liquid.Messaging.RabbitMq.Settings;\nusing RabbitMQ.Client;\n\nnamespace Liquid.Messaging.RabbitMq\n{\n    /// <summary>\n    /// RabbitMq <see cref=\"IModel\"/> provider.\n    /// </summary>\n    public interface IRabbitMqFactory\n    {\n        /// <summary>\n        /// Initialize and return a new instance of <see cref=\"IModel\"/>\n        /// </summary>\n        /// <param name=\"settings\">RabbitMq producer configuration properties set.</param>\n        IModel GetSender(RabbitMqProducerSettings settings);\n\n        /// <summary>\n        /// Initialize and return a new instance of <see cref=\"IModel\"/>\n        /// </summary>\n        /// <param name=\"settings\">RabbitMq consumer configuration properties set.</param>\n        IModel GetReceiver(RabbitMqConsumerSettings settings);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Liquid.Messaging.RabbitMq.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.Messaging.RabbitMq</PackageId>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2019</Copyright>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Version>8.0.1</Version>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <Description>\n      The Liquid.Messaging.RabbitMq provides producer and consumer patterns to allow the send and consumption of Messaging inside your microservice.\n      The main components are ILightProducer and ILightConsumer. This component allows send and consuming messages from RabbitMq.\n      This component is part of Liquid Application Framework.\n    </Description>\n    <ProjectGuid>{6CFF2DEC-50E9-417C-A6E1-A0EFCD1EB94C}</ProjectGuid>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n    <PackageReference Include=\"RabbitMQ.Client\" Version=\"6.8.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/RabbitMqConsumer.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Extensions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Utils;\nusing Liquid.Messaging.RabbitMq.Settings;\nusing Microsoft.Extensions.Options;\nusing RabbitMQ.Client;\nusing RabbitMQ.Client.Events;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.RabbitMq\n{\n    /// <summary>\n    /// RabbitMq Consumer Adapter Class.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of the message object.</typeparam>\n    /// <seealso cref=\"ILiquidConsumer{TEntity}\" />\n    /// <seealso cref=\"IDisposable\" />\n    public class RabbitMqConsumer<TEntity> : ILiquidConsumer<TEntity>\n    {\n\n        private readonly bool _autoAck;\n        private IModel _channelModel;\n        private readonly IRabbitMqFactory _factory;\n        private readonly IOptions<RabbitMqConsumerSettings> _settings;\n\n        ///<inheritdoc/>\n        public event Func<ConsumerMessageEventArgs<TEntity>, CancellationToken, Task> ConsumeMessageAsync;\n\n        ///<inheritdoc/>\n        public event Func<ConsumerErrorEventArgs, Task> ProcessErrorAsync;\n\n        /// <summary>\n        /// Initilize an instance of <see cref=\"RabbitMqConsumer{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"factory\">RabbitMq client factory.</param>\n        /// <param name=\"settings\">Configuration properties set.</param>\n        public RabbitMqConsumer(IRabbitMqFactory factory, IOptions<RabbitMqConsumerSettings> settings)\n        {\n            _factory = factory ?? throw new ArgumentNullException(nameof(factory));\n            _settings = settings ?? throw new ArgumentNullException(nameof(settings));\n\n            if (_settings.Value == null)\n            {\n                throw new ArgumentNullException(nameof(_settings.Value), \"The settings value must be set.\");\n            }\n\n            _autoAck = _settings.Value.AdvancedSettings?.AutoAck ?? true;\n        }\n\n        ///<inheritdoc/>\n        public async Task RegisterMessageHandler(CancellationToken cancellationToken = default)\n        {\n            if (ConsumeMessageAsync is null)\n            {\n                throw new NotImplementedException($\"The {nameof(ConsumeMessageAsync)} action must be added to class.\");\n            }\n\n            _channelModel = _factory.GetReceiver(_settings.Value);\n\n            var consumer = new EventingBasicConsumer(_channelModel);\n\n\n            consumer.Received += async (model, deliverEvent) => { await MessageHandler(deliverEvent, cancellationToken); };\n\n            _channelModel.BasicConsume(_settings.Value.Queue, _autoAck, consumer);\n        }\n\n        /// <summary>\n        /// Process incoming messages.\n        /// </summary>\n        /// <param name=\"deliverEvent\">Message to be processed.</param>\n        /// <param name=\"cancellationToken\"> Propagates notification that operations should be canceled.</param>\n        protected async Task MessageHandler(BasicDeliverEventArgs deliverEvent, CancellationToken cancellationToken)\n        {\n            try\n            {\n                await ConsumeMessageAsync(GetEventArgs(deliverEvent), cancellationToken);\n\n                if (!_autoAck)\n                {\n                    _channelModel.BasicAck(deliverEvent.DeliveryTag, false);\n                }\n            }\n            catch (Exception)\n            {\n                if (!_autoAck)\n                {\n                    var queueAckMode = _settings.Value.AdvancedSettings.QueueAckModeSettings ?? new QueueAckModeSettings() { QueueAckMode = QueueAckModeEnum.BasicAck, Requeue = true };\n\n                    switch (queueAckMode.QueueAckMode)\n                    {\n                        case QueueAckModeEnum.BasicAck:\n                            _channelModel.BasicNack(deliverEvent.DeliveryTag, false, queueAckMode.Requeue);\n                            break;\n                        case QueueAckModeEnum.BasicReject:\n                            _channelModel.BasicReject(deliverEvent.DeliveryTag, queueAckMode.Requeue);\n                            break;\n                        default:\n                            _channelModel.BasicNack(deliverEvent.DeliveryTag, false, true);\n                            break;\n                    }\n\n                }\n            }\n        }\n\n        private ConsumerMessageEventArgs<TEntity> GetEventArgs(BasicDeliverEventArgs deliverEvent)\n        {\n            var data = deliverEvent.BasicProperties?.ContentType == CommonExtensions.GZipContentType\n                   ? deliverEvent.Body.ToArray().GzipDecompress().ParseJson<TEntity>()\n                   : deliverEvent.Body.ToArray().ParseJson<TEntity>();\n\n            var headers = deliverEvent.BasicProperties?.Headers;\n\n            return new ConsumerMessageEventArgs<TEntity> { Data = data, Headers = headers };\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/RabbitMqFactory.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Messaging.RabbitMq.Settings;\nusing RabbitMQ.Client;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    public class RabbitMqFactory : IRabbitMqFactory, IDisposable\n    {\n\n        private IConnection _connection;\n        private IModel _model;\n        private bool _disposed;\n\n        /// <summary>\n        /// Initialize a new instace of <see cref=\"RabbitMqFactory\"/>\n        /// </summary>\n        public RabbitMqFactory()\n        {\n        }\n\n        ///<inheritdoc/>\n        public IModel GetReceiver(RabbitMqConsumerSettings settings)\n        {\n            try\n            {\n                if (_connection == null && _model == null)\n                {\n                    var connectionFactory = new ConnectionFactory\n                    {\n                        Uri = new Uri(settings.QueueSettings.ConnectionString),\n                        RequestedHeartbeat = TimeSpan.FromSeconds(settings.QueueSettings?.RequestHeartBeatInSeconds ?? 60),\n                        AutomaticRecoveryEnabled = settings.QueueSettings?.AutoRecovery ?? true\n                    };\n\n                    _connection = connectionFactory.CreateConnection(settings.QueueSettings.ConnectionName);\n                    _model = _connection.CreateModel();\n                }\n\n                if (settings.QueueSettings.Prefetch.HasValue &&\n                    settings.QueueSettings.PrefetchCount.HasValue &&\n                    settings.QueueSettings.Global.HasValue)\n                {\n                    _model.BasicQos(settings.QueueSettings.Prefetch.Value,\n                        settings.QueueSettings.PrefetchCount.Value,\n                        settings.QueueSettings.Global.Value);\n                }\n\n                _model.QueueBind(settings.Queue, settings.Exchange, string.Empty);\n\n                return _model;\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, \"for queue '\" + settings?.Queue + \"'\");\n            }\n\n        }\n\n        ///<inheritdoc/>\n        public IModel GetSender(RabbitMqProducerSettings settings)\n        {\n            try\n            {\n                if (_connection == null && _model == null)\n                {\n                    var connectionFactory = new ConnectionFactory\n                    {\n                        Uri = new Uri(settings.QueueSettings.ConnectionString),\n                        RequestedHeartbeat = TimeSpan.FromSeconds(settings.QueueSettings?.RequestHeartBeatInSeconds ?? 60),\n                        AutomaticRecoveryEnabled = settings.QueueSettings?.AutoRecovery ?? true\n                    };\n\n                    _connection = connectionFactory.CreateConnection(settings.QueueSettings.ConnectionName);\n                    _model = _connection.CreateModel();\n                }\n\n                return _model;\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, \"for exange '\" + settings?.Exchange + \"'\");\n            }\n        }\n\n        /// <summary>\n        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n        /// </summary>\n        /// <param name=\"disposing\">Indicates if method should perform dispose.</param>\n        protected virtual void Dispose(bool disposing)\n        {\n            if (!_disposed)\n            {\n                if (disposing)\n                {\n                    _connection?.Dispose();\n                    _model?.Dispose();\n                }\n\n                _disposed = true;\n            }\n        }\n\n        /// <summary>\n        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.\n        /// </summary>\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/RabbitMqProducer.cs",
    "content": "﻿using Liquid.Core.Extensions;\nusing Liquid.Core.Utils;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.RabbitMq.Settings;\nusing RabbitMQ.Client;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Microsoft.Extensions.Options;\n\nnamespace Liquid.Messaging.RabbitMq\n{\n    ///<inheritdoc/>\n    public class RabbitMqProducer<TEntity> : ILiquidProducer<TEntity>\n    {\n        private readonly RabbitMqProducerSettings _settings;\n        private readonly IModel _channelModel;\n\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"RabbitMqProducer{TMessage}\"/> class.\n        /// </summary>\n        /// <param name=\"factory\"></param>\n        /// <param name=\"settings\"></param>\n        /// <exception cref=\"MessagingMissingConfigurationException\"></exception>\n        public RabbitMqProducer(IRabbitMqFactory factory, IOptions<RabbitMqProducerSettings> settings)\n        {\n            if (factory is null)\n            {\n                throw new ArgumentNullException(nameof(factory));\n            }\n\n            _settings = settings?.Value ?? throw new ArgumentNullException(nameof(settings));\n\n\n            _channelModel = factory.GetSender(_settings);\n        }\n\n\n        ///<inheritdoc/>\n        public async Task SendMessageAsync(TEntity messageBody, IDictionary<string, object> customProperties = null)\n        {\n            if (customProperties == null) customProperties = new Dictionary<string, object>();\n            try\n            {\n                await Task.Run(() =>\n                {\n                    var messageProperties = GetProperties(customProperties);\n\n                    var messageBytes = !_settings.CompressMessage ? messageBody.ToJsonBytes() : messageBody.ToJsonString().GzipCompress();\n\n                    _channelModel.BasicPublish(_settings.Exchange, string.Empty, messageProperties, messageBytes);\n\n                });\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingProducerException(ex);\n            }\n        }\n\n        ///<inheritdoc/>\n        public async Task SendMessagesAsync(IEnumerable<TEntity> messageBodies)\n        {\n            try\n            {\n                foreach (var message in messageBodies)\n                {\n                    await SendMessageAsync(message);\n                }\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingProducerException(ex);\n            }\n        }\n\n        private IBasicProperties GetProperties(IDictionary<string, object> customProperties)\n        {\n            var messageProperties = _channelModel.CreateBasicProperties();\n\n            var messageId = Guid.NewGuid().ToString();\n\n            messageProperties.Persistent = _settings.AdvancedSettings?.Persistent ?? false;\n            messageProperties.Expiration = _settings.AdvancedSettings?.Expiration ?? \"30000\";\n            messageProperties.Headers = customProperties;\n            messageProperties.MessageId = messageId;\n\n            if (_settings.CompressMessage)\n            {\n                messageProperties.ContentType = CommonExtensions.GZipContentType;\n            }\n\n            return messageProperties;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Settings/AdvancedSettings.cs",
    "content": "﻿using System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq.Settings\n{\n    /// <summary>\n    /// RabbitMq Custom Settings Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class AdvancedSettings\n    {\n        /// <summary>\n        /// Gets or sets the type of the exchange.\n        /// </summary>\n        /// <value>\n        /// The type of the exchange.\n        /// </value>\n        public string ExchangeType { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether Exchange/Queue[automatic delete].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [automatic delete]; otherwise, <c>false</c>.\n        /// </value>\n        public bool AutoDelete { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether Exchange/Queue is durable.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if durable; otherwise, <c>false</c>.\n        /// </value>\n        public bool Durable { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether [automatic ack].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [automatic ack]; otherwise, <c>false</c>.\n        /// </value>\n        public bool AutoAck { get; set; }\n\n        /// <summary>\n        /// Gets or sets the expiration.\n        /// </summary>\n        /// <value>\n        /// The expiration.\n        /// </value>\n        public string Expiration { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the message is persistent.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if persistent; otherwise, <c>false</c>.\n        /// </value>\n        public bool Persistent { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this Queue is exclusive.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if exclusive; otherwise, <c>false</c>.\n        /// </value>\n        public bool Exclusive { get; set; }\n\n        /// <summary>\n        /// Gets or sets the exchange arguments.\n        /// </summary>\n        /// <value>\n        /// The exchange arguments.\n        /// </value>\n        public IDictionary<string, object> ExchangeArguments { get; set; }\n\n        /// <summary>\n        /// Gets or sets the queue arguments.\n        /// </summary>\n        /// <value>\n        /// The queue arguments.\n        /// </value>\n        public IDictionary<string, object> QueueArguments { get; set; }\n\n        /// <summary>\n        /// Queue Ack Mode Settings\n        /// </summary>\n        public QueueAckModeSettings QueueAckModeSettings { get; set; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Settings/QueueAckModeEnum.cs",
    "content": "﻿namespace Liquid.Messaging.RabbitMq.Settings\n{\n    /// <summary>\n    /// Defines the AckMode\n    /// </summary>\n    public enum QueueAckModeEnum\n    {\n        /// <summary>\n        /// Basic Ack\n        /// </summary>\n        BasicAck = 0,\n\n        /// <summary>\n        /// Reject Ack\n        /// </summary>\n        BasicReject = 1\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Settings/QueueAckModeSettings.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq.Settings\n{\n\n    /// <summary>\n    /// Queue Ack Mode Settings\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class QueueAckModeSettings\n    {\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the message should requeued.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [requeue]; otherwise, <c>false</c>.\n        /// </value>\n        public bool Requeue { get; set; }\n\n        /// <summary>\n        /// Defines the AckMode\n        /// </summary>\n        public QueueAckModeEnum QueueAckMode { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Settings/RabbitMqConsumerSettings.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq.Settings\n{\n    /// <summary>\n    /// RabbitMq Consumer configurations set.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class RabbitMqConsumerSettings\n    {\n        /// <summary>\n        /// Gets a value indicating whether [compress message].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [compress message]; otherwise, <c>false</c>.\n        /// </value>\n        public bool CompressMessage { get; set; }\n\n        /// <summary>\n        /// Gets the topic exchange.\n        /// </summary>\n        /// <value>\n        /// The topic.\n        /// </value>\n        public string Exchange { get; set; }\n\n        /// <summary>\n        /// Gets the subscription queue.\n        /// </summary>\n        /// <value>\n        /// The subscription.\n        /// </value>\n        public string Queue { get; set; }\n\n        /// <summary>\n        /// Gets or sets the advanced settings.\n        /// </summary>\n        /// <value>\n        /// The advanced settings.\n        /// </value>\n        public AdvancedSettings AdvancedSettings { get; set; }\n\n        /// <summary>\n        /// Infra basic settings.\n        /// </summary>\n        public RabbitMqSettings QueueSettings { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Settings/RabbitMqProducerSettings.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq.Settings\n{\n    /// <summary>\n    /// RabbitMq Producer configurations set.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class RabbitMqProducerSettings\n    {\n        /// <summary>\n        /// Gets a value indicating whether [compress message].\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if [compress message]; otherwise, <c>false</c>.\n        /// </value>\n        public bool CompressMessage { get; set; }\n        /// <summary>\n        /// Gets the topic exchange.\n        /// </summary>\n        /// <value>\n        /// The topic.\n        /// </value>\n        public string Exchange { get; set; }\n\n        /// <summary>\n        /// Gets or sets the advanced settings.\n        /// </summary>\n        /// <value>\n        /// The advanced settings.\n        /// </value>\n        public AdvancedSettings AdvancedSettings { get; set; }\n\n        /// <summary>\n        /// Infra basic settings.\n        /// </summary>\n        public RabbitMqSettings QueueSettings { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.RabbitMq/Settings/RabbitMqSettings.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq.Settings\n{\n\n    /// <summary>\n    /// RabbitMq configurations set.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class RabbitMqSettings\n    {\n        /// <summary>\n        /// Gets or sets the connection string.\n        /// </summary>\n        /// <value>\n        /// The connection string.\n        /// </value>\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the connection.\n        /// </summary>\n        /// <value>\n        /// The connection string.\n        /// </value>\n        public string ConnectionName { get; set; }\n\n        /// <summary>\n        /// Gets or sets the request heart beat in seconds.\n        /// </summary>\n        /// <value>\n        /// The request heart beat in seconds.\n        /// </value>\n        public ushort? RequestHeartBeatInSeconds { get; set; }\n\n        /// <summary>\n        /// Gets or sets the prefetch count.\n        /// </summary>\n        /// <value>\n        /// The prefetch count.\n        /// </value>\n        public ushort? PrefetchCount { get; set; }\n\n        /// <summary>\n        /// Gets or sets the prefetch.\n        /// </summary>\n        /// <value>\n        /// The prefetch.\n        /// </value>\n        public uint? Prefetch { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether the Qos is global.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if global; otherwise, <c>false</c>.\n        /// </value>\n        public bool? Global { get; set; }\n\n        /// <summary>\n        /// Gets or sets the auto recovery property of Rabbit to recover exchanges and queue bindings.\n        /// </summary>\n        /// <value>\n        /// The auto recovery value.\n        /// </value>\n        public bool? AutoRecovery { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/Extensions/DependencyInjection/IServiceCollectionExtensions.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.ServiceBus.Settings;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Reflection;\nusing Microsoft.Extensions.Configuration;\n\nnamespace Liquid.Messaging.ServiceBus.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Startup extension methods. Used to configure the startup application.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Register a <see cref=\"ServiceBusConsumer{TEntity}\"/> with its dependency, and with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddSingletonLiquidTelemetry{TInterface, TService}(IServiceCollection)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service instance.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"entityPath\">Entity path to configure this producer.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        public static IServiceCollection AddLiquidServiceBusProducer<TEntity>(this IServiceCollection services, \n            string sectionName, string entityPath, bool activateTelemetry = true)\n        {\n            services.AddOptions<ServiceBusSettings>()\n             .Configure<IConfiguration>((settings, configuration) =>\n             {\n                 configuration.GetSection(sectionName).Bind(settings);\n             });\n\n            services.TryAddTransient<IServiceBusFactory, ServiceBusFactory>();\n\n            if (activateTelemetry)\n            {\n                services.AddSingleton((provider) =>\n                {\n                    return ActivatorUtilities.CreateInstance<ServiceBusProducer<TEntity>>(provider, entityPath);\n                });\n\n                services.AddSingletonLiquidTelemetry<ILiquidProducer<TEntity>, ServiceBusProducer<TEntity>>();\n            }\n            else\n            {\n                services.AddSingleton<ILiquidProducer<TEntity>>((provider) =>\n                {\n                    return ActivatorUtilities.CreateInstance<ServiceBusProducer<TEntity>>(provider, entityPath);\n                });\n            }\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register Liquid resources for consumers \n        /// <see cref=\"IServiceCollectionCoreExtensions.AddLiquidMessageConsumer{TService, TEntity}(IServiceCollection, Assembly[])\"/>\n        /// and a <see cref=\"ServiceBusConsumer{TEntity}\"/> service with its dependency, with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddLiquidTelemetryInterceptor{TInterface, TService}(IServiceCollection)\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by this service instance.</typeparam>\n        /// <typeparam name=\"TWorker\">Type of implementation from <see cref=\"ILiquidWorker{TEntity}\"/></typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"entityPath\">Entity name to configure for this worker.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        /// <param name=\"assemblies\">Array of assemblies that contains domain handlers implementation.</param>\n        public static IServiceCollection AddLiquidServiceBusConsumer<TWorker, TEntity>(this IServiceCollection services\n            , string sectionName\n            , string entityPath\n            , bool activateTelemetry = true\n            , params Assembly[] assemblies)\n             where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddOptions<ServiceBusSettings>()\n             .Configure<IConfiguration>((settings, configuration) =>\n             {\n                 configuration.GetSection(sectionName).Bind(settings);\n             });\n            services.AddLiquidMessageConsumer<TWorker, TEntity>(assemblies);\n\n            services.AddConsumer<TEntity>(entityPath, activateTelemetry);\n\n            return services;\n        }\n\n        /// <summary>\n        /// Register a <see cref=\"ServiceBusConsumer{TEntity}\"/> service with its dependency, and with \n        /// <see cref=\"IServiceCollectionLiquidExtension.AddLiquidTelemetryInterceptor{TInterface, TService}(IServiceCollection)\"/>.\n        /// In order for consumers injected by this method to work correctly and \n        /// domain handlers/services in your build configurator.\n        /// </summary>\n        /// <typeparam name=\"TWorker\">Type of implementation from <see cref=\"ILiquidWorker{TEntity}\"/></typeparam>\n        /// <typeparam name=\"TEntity\">Type of entity that will be consumed by the service instance.</typeparam>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"sectionName\">Configuration section name.</param>\n        /// <param name=\"activateTelemetry\">Indicates if telemetry interceptor must be registered.</param>\n        public static IServiceCollection AddLiquidServiceBusConsumer<TWorker, TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n            where TWorker : class, ILiquidWorker<TEntity>\n        {\n            services.AddLiquidWorkerService<TWorker, TEntity>();\n\n            services.AddConsumer<TEntity>(sectionName, activateTelemetry);\n\n            return services;\n        }\n\n        private static IServiceCollection AddConsumer<TEntity>(this IServiceCollection services, string sectionName, bool activateTelemetry = true)\n        {\n            services.AddTransient<IServiceBusFactory, ServiceBusFactory>();\n\n            if (activateTelemetry)\n            {\n                services.AddSingleton((provider) =>\n                {\n                    return ActivatorUtilities.CreateInstance<ServiceBusConsumer<TEntity>>(provider, sectionName);\n                });\n\n                services.AddSingletonLiquidTelemetry<ILiquidConsumer<TEntity>, ServiceBusConsumer<TEntity>>();\n            }\n            else\n            {\n                services.AddSingleton<ILiquidConsumer<TEntity>>((provider) =>\n                {\n                    return ActivatorUtilities.CreateInstance<ServiceBusConsumer<TEntity>>(provider, sectionName);\n                });\n            }\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/IServiceBusFactory.cs",
    "content": "﻿using Azure.Messaging.ServiceBus;\n\nnamespace Liquid.Messaging.ServiceBus\n{\n    /// <summary>\n    /// Service Bus client Provider.\n    /// </summary>\n    public interface IServiceBusFactory\n    {\n        /// <summary>\n        /// Initialize and return a new instance of <see cref=\"ServiceBusSender\"/>.\n        /// </summary>\n        ServiceBusSender GetSender(string entityPath);\n\n        /// <summary>\n        /// Initialize and return a new instance of <see cref=\"ServiceBusProcessor\"/>\n        /// </summary>\n        ServiceBusProcessor GetProcessor(string entityPath);\n\n        /// <summary>\n        /// Initialize and return a new instance of <see cref=\"ServiceBusReceiver\"/>\n        /// </summary>\n        ServiceBusReceiver GetReceiver(string entityPath);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/Liquid.Messaging.ServiceBus.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.Messaging.ServiceBus</PackageId>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2019</Copyright>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Version>8.0.1</Version>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <Description>\n      The Liquid.Messaging.ServiceBus provides producer and consumer patterns to allow the send and consumption of Messaging inside your microservice.\n      The main components are ILiquidProducer and ILiquidConsumer. This component allows send and consuming messages from Azure Service Bus.\n      This component is part of Liquid Application Framework.\n    </Description>\n    <PackageIconUrl />\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Messaging.ServiceBus\" Version=\"7.19.0\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/ServiceBusConsumer.cs",
    "content": "﻿using Azure.Messaging.ServiceBus;\nusing Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.Text;\nusing System.Text.Json;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.ServiceBus\n{\n    ///<inheritdoc/>\n    public class ServiceBusConsumer<TEntity> : ILiquidConsumer<TEntity>\n    {\n        private ServiceBusProcessor _messageProcessor;\n\n        private readonly IServiceBusFactory _factory;\n\n        private readonly string _settingsName;\n\n        ///<inheritdoc/>\n        public event Func<ConsumerMessageEventArgs<TEntity>, CancellationToken, Task> ConsumeMessageAsync;\n\n        ///<inheritdoc/>\n        public event Func<ConsumerErrorEventArgs, Task> ProcessErrorAsync;\n\n        /// <summary>\n        /// Initilize an instance of <see cref=\"ServiceBusConsumer{TEntity}\"/>\n        /// </summary>\n        /// <param name=\"factory\">Service Bus client factory.</param>\n        /// <param name=\"settingsName\">Configuration section name for this service instance.</param>\n        public ServiceBusConsumer(IServiceBusFactory factory, string settingsName)\n        {\n            _factory = factory ?? throw new ArgumentNullException(nameof(factory));\n            _settingsName = settingsName ?? throw new ArgumentNullException(nameof(settingsName));\n        }\n\n        ///<inheritdoc/>\n        public async Task RegisterMessageHandler(CancellationToken cancellationToken = default)\n        {\n            if (ConsumeMessageAsync is null)\n            {\n                throw new NotImplementedException($\"The {nameof(ProcessErrorAsync)} action must be added to class.\");\n            }\n\n            _messageProcessor = _factory.GetProcessor(_settingsName);\n\n            ProcessErrorAsync += ProcessError;\n\n            _messageProcessor.ProcessMessageAsync += MessageHandler;\n            _messageProcessor.ProcessErrorAsync += ErrorHandler;\n\n            await _messageProcessor.StartProcessingAsync(cancellationToken);\n        }\n\n        /// <summary>\n        /// Process incoming messages.\n        /// </summary>\n        /// <param name=\"message\">Message to be processed.</param>\n        protected async Task MessageHandler(ProcessMessageEventArgs message)\n        {\n            await ConsumeMessageAsync(GetEventArgs(message.Message), new CancellationToken());\n        }\n\n        /// <summary>\n        /// Process exception from message handler.\n        /// </summary>\n        /// <param name=\"args\"></param>\n        protected async Task ErrorHandler(ProcessErrorEventArgs args)\n        {\n            await ProcessErrorAsync(new ConsumerErrorEventArgs()\n            {\n                Exception = args.Exception \n            });\n        }\n\n        private ConsumerMessageEventArgs<TEntity> GetEventArgs(ServiceBusReceivedMessage message)\n        {\n            var data = JsonSerializer.Deserialize<TEntity>(Encoding.UTF8.GetString(message.Body));\n\n            var headers = (IDictionary<string,object>)message.ApplicationProperties;\n\n            return new ConsumerMessageEventArgs<TEntity> { Data = data, Headers = headers };\n        }\n        /// <summary>\n        /// Process error from message handler.\n        /// </summary>\n        /// <param name=\"args\"><see cref=\"ConsumerErrorEventArgs\"/></param>\n        /// <exception cref=\"MessagingConsumerException\"></exception>\n        protected static Task ProcessError(ConsumerErrorEventArgs args)\n        {\n            throw new MessagingConsumerException(args.Exception);\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/ServiceBusFactory.cs",
    "content": "﻿using Azure.Messaging.ServiceBus;\nusing Liquid.Core.Exceptions;\nusing Liquid.Messaging.ServiceBus.Settings;\nusing Microsoft.Extensions.Options;\nusing System;\nusing System.Linq;\n\nnamespace Liquid.Messaging.ServiceBus\n{\n    ///<inheritdoc/>\n    public class ServiceBusFactory : IServiceBusFactory\n    {\n        private readonly ServiceBusSettings _options;\n\n        /// <summary>\n        /// Initialize a new instace of <see cref=\"ServiceBusFactory\"/>\n        /// </summary>\n        /// <param name=\"settings\">Configuration Providers</param>\n        public ServiceBusFactory(IOptions<ServiceBusSettings> settings)\n        {\n            _options = settings.Value ?? throw new ArgumentNullException(nameof(settings));\n        }\n\n        ///<inheritdoc/>\n        public ServiceBusProcessor GetProcessor(string settingsName)\n        {\n            try\n            {\n                var config = _options.Settings.FirstOrDefault(x => x.EntityPath == settingsName);\n\n                if (config == null)\n                {\n                    throw new ArgumentOutOfRangeException(nameof(settingsName), $\"The settings name '{settingsName}' is not found in the configuration.\");\n                }\n\n                var options = new ServiceBusProcessorOptions();\n\n                options.ReceiveMode = config.PeekLockMode ? ServiceBusReceiveMode.PeekLock : ServiceBusReceiveMode.ReceiveAndDelete;\n\n                options.MaxConcurrentCalls = config.MaxConcurrentCalls;\n\n                var serviceBusClient = new ServiceBusClient(config.ConnectionString);\n\n                ServiceBusProcessor processor;\n                if (config.Subscription is null)\n                {\n                    processor = serviceBusClient.CreateProcessor(config.EntityPath, options);\n                }\n                else\n                {\n                    processor = serviceBusClient.CreateProcessor(config.EntityPath, config.Subscription, options);\n                }\n\n                return processor;\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, settingsName);\n            }\n        }\n\n        ///<inheritdoc/>\n        public ServiceBusSender GetSender(string settingsName)\n        {\n            var config = _options.Settings.FirstOrDefault(x => x.EntityPath == settingsName);\n\n            if (config == null)\n            {\n                throw new ArgumentOutOfRangeException(nameof(settingsName), $\"The settings name '{settingsName}' is not found in the configuration.\");\n            }\n\n            try\n            {\n                var serviceBusClient = new ServiceBusClient(config.ConnectionString);\n                var sender = serviceBusClient.CreateSender(config.EntityPath);\n\n                return sender;\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, settingsName);\n            }\n        }\n\n        ///<inheritdoc/>\n        public ServiceBusReceiver GetReceiver(string settingsName)\n        {\n            var config = _options.Settings.FirstOrDefault(x => x.EntityPath == settingsName);\n\n            if (config == null)\n            {\n                throw new ArgumentOutOfRangeException(nameof(settingsName), $\"The settings name '{settingsName}' is not found in the configuration.\");\n            }\n\n            try\n            {\n                var options = new ServiceBusReceiverOptions();\n\n                options.ReceiveMode = config.PeekLockMode ? ServiceBusReceiveMode.PeekLock : ServiceBusReceiveMode.ReceiveAndDelete;\n\n                var serviceBusClient = new ServiceBusClient(config.ConnectionString);\n\n                var receiver = serviceBusClient.CreateReceiver(config.EntityPath, options);\n\n                return receiver;\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingMissingConfigurationException(ex, settingsName);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/ServiceBusProducer.cs",
    "content": "﻿using Azure.Messaging.ServiceBus;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text.Json;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.ServiceBus\n{\n    ///<inheritdoc/>\n    public class ServiceBusProducer<TEntity> : ILiquidProducer<TEntity>\n    {\n        private readonly ServiceBusSender _messageSender;\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"ServiceBusConsumer{TEntity}\"/>.\n        /// </summary>\n        /// <param name=\"factory\">Service Bus client factory.</param>\n        /// <param name=\"settingsName\">Configuration section name for this service instance.</param>\n        public ServiceBusProducer(IServiceBusFactory factory, string settingsName)\n        {\n            if (settingsName is null) throw new ArgumentNullException(nameof(settingsName));\n            _messageSender = factory?.GetSender(settingsName) ?? throw new ArgumentNullException(nameof(factory));\n        }\n\n        ///<inheritdoc/>\n        public async Task SendMessagesAsync(IEnumerable<TEntity> messageBodies)\n        {\n            try\n            {\n                await _messageSender.SendMessagesAsync(messageBodies.Select(e => ToMessage(e)).ToList());\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingProducerException(ex);\n            }\n        }\n\n        ///<inheritdoc/>\n        public async Task SendMessageAsync(TEntity messageBody, IDictionary<string, object> customProperties = null)\n        {\n            try\n            {\n                await _messageSender.SendMessageAsync(ToMessage(messageBody, customProperties));\n            }\n            catch (Exception ex)\n            {\n                throw new MessagingProducerException(ex);\n            }\n        }\n\n        private ServiceBusMessage ToMessage(TEntity messageBody, IDictionary<string, object> customProperties = null)\n        {\n            var message = new ServiceBusMessage(JsonSerializer.SerializeToUtf8Bytes(messageBody));\n\n            if (customProperties != null)\n            {\n                foreach (var property in customProperties)\n                {\n                    message.ApplicationProperties.Add(property);\n                }\n            }\n\n            return message;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Messaging.ServiceBus/Settings/ServiceBusSettings.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\n\nnamespace Liquid.Messaging.ServiceBus.Settings\n{\n    /// <summary>\n    /// Service bus configuration properties set.\n    /// </summary>\n    \n    public class ServiceBusSettings\n    {\n        /// <summary>\n        /// Properties set list of service bus configurations.\n        /// </summary>\n        public List<ServiceBusEntitySettings> Settings { get; set; }\n    }\n    /// <summary>\n    /// Properties set of Service Bus entity configuration.\n    /// </summary>\n    public class ServiceBusEntitySettings\n    {\n        /// <summary>\n        /// Connection string of Service Bus resource.\n        /// </summary>\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// Topic or Queue path.\n        /// </summary>\n        public string EntityPath { get; set; }\n\n        /// <summary>\n        /// Topic subscription path.\n        /// </summary>\n        public string Subscription { get; set; }\n\n        /// <summary>\n        /// Indicates max number of concurrent consumer calls.\n        /// The default value is 1.\n        /// </summary>\n        public int MaxConcurrentCalls { get; set; } = 1;\n\n        /// <summary>\n        ///Indicates whether the consumer must lock the message during execution and complete,\n        ///abort or move to DLQ according to processing result, \n        ///otherwise it deletes message from queue/topic immediately after reading, \n        ///regardless of processing result.\n        /// The default value is true.\n        /// </summary>\n        public bool PeekLockMode { get; set; } = true;\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/EntityFrameworkDataContext.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.EntityFramework\n{\n    /// <summary>\n    /// Implements the EntityFramework data context for repositories.\n    /// </summary>\n    /// <seealso cref=\"EntityFrameworkDataContext{TContext}\" />\n    /// <typeparam name=\"TContext\">The type of the <see cref=\"DbContext\"/>.</typeparam>\n    public class EntityFrameworkDataContext<TContext> : IEntityFrameworkDataContext<TContext> where TContext : DbContext\n    {\n        private bool _disposed = false;\n        private readonly TContext _databaseContext;\n\n        /// <summary>\n        /// Gets the identifier of data context.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        public string Id { get; }\n\n        ///<inheritdoc/>\n        public TContext DbClient => _databaseContext;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EntityFrameworkDataContext{TContext}\" /> class.\n        /// </summary>\n        /// <param name=\"dbContext\">Data base context object <see cref=\"DbContext\"/>.</param>\n        public EntityFrameworkDataContext(TContext dbContext)\n        {\n            _databaseContext = dbContext ?? throw new ArgumentNullException(nameof(dbContext));\n        }\n\n        ///<inheritdoc/>\n        public async Task StartTransactionAsync()\n        {\n\n            await _databaseContext.Database.BeginTransactionAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task CommitAsync()\n        {\n            await _databaseContext.Database.CommitTransactionAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task RollbackTransactionAsync()\n        {\n            await _databaseContext.Database.RollbackTransactionAsync();\n        }\n\n        ///<inheritdoc/>\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        /// <summary>\n        /// Releases the allocated resources <see cref=\"DbContext\"/> for this context.\n        /// </summary>\n        /// <param name=\"disposing\">Indicates if method should perform dispose.</param>\n        protected virtual void Dispose(bool disposing)\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            if (disposing)\n            {\n                _databaseContext.Dispose();\n            }\n\n            _disposed = true;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/EntityFrameworkRepository.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Microsoft.EntityFrameworkCore;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.EntityFramework\n{\n    /// <summary>\n    /// Implements the EntityFramework repository.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of the entity.</typeparam>\n    /// <typeparam name=\"TIdentifier\">The type of the identifier.</typeparam>\n    /// <typeparam name=\"TContext\">The type of the <see cref=\"DbContext\"/>.</typeparam>\n    /// <seealso cref=\"ILiquidRepository{TEntity, TIdentifier}\" />\n#pragma warning disable S2436 // Types and methods should not have too many generic parameters\n    public class EntityFrameworkRepository<TEntity, TIdentifier, TContext> : ILiquidRepository<TEntity, TIdentifier> where TEntity : LiquidEntity<TIdentifier>, new() where TContext : DbContext\n#pragma warning restore S2436 // Types and methods should not have too many generic parameters\n    {\n        ///<inheritdoc/>\n        public IEntityFrameworkDataContext<TContext> EntityDataContext { get; }\n\n        ///<inheritdoc/>\n        public ILiquidDataContext DataContext => EntityDataContext;\n\n        private readonly TContext _dbClient;\n        private readonly DbSet<TEntity> _dbSet;\n        private readonly IQueryable<TEntity> _queryableReadOnly;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"EntityFrameworkRepository{TEntity, TIdentifier, TContext}\" /> class.\n        /// </summary>\n        /// <param name=\"dataContext\">The data context.</param>\n        /// <exception cref=\"ArgumentNullException\">\n        /// telemetryFactory\n        /// or\n        /// dataContext\n        /// </exception>\n        public EntityFrameworkRepository(IEntityFrameworkDataContext<TContext> dataContext)\n        {\n            EntityDataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));\n\n            _dbClient = dataContext.DbClient;\n            _dbSet = _dbClient.Set<TEntity>();\n            _queryableReadOnly = _dbSet.AsNoTracking();\n\n        }\n\n        ///<inheritdoc/>\n        public async Task AddAsync(TEntity entity)\n        {\n            await _dbSet.AddAsync(entity);\n            await _dbClient.SaveChangesAsync();\n        }\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        ///<inheritdoc/>\n        public async Task<IEnumerable<TEntity>> FindAllAsync()\n        {\n            IEnumerable<TEntity> returnValue = _queryableReadOnly;\n\n            return returnValue;\n        }\n\n        ///<inheritdoc/>\n        public async Task<TEntity> FindByIdAsync(TIdentifier id)\n        {\n            var returnValue = _queryableReadOnly.FirstOrDefault(o => o.Id.Equals(id));\n\n            return returnValue;\n        }\n\n        ///<inheritdoc/>\n        public async Task RemoveByIdAsync(TIdentifier id)\n        {\n            var obj = await _dbSet.FirstOrDefaultAsync(o => o.Id.Equals(id));\n\n            if (obj == null) return;\n\n            _dbSet.Remove(obj);\n            await _dbClient.SaveChangesAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task UpdateAsync(TEntity entity)\n        {\n            _dbClient.Detach<TEntity>(o => o.Id.Equals(entity.Id));\n            _dbClient.Update(entity);\n            await _dbClient.SaveChangesAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> whereClause)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            var result = _queryableReadOnly.Where(whereClause);\n            var returnValue = result.AsEnumerable();\n\n            return returnValue;\n        }\n\n        /// <summary>\n        /// Gets the list of entities that matches the where clause,\n        /// including the related entities.\n        /// </summary>\n        /// <param name=\"whereClause\"> The where clause.</param>\n        /// <param name=\"include\"> The include clause.</param>\n        /// <returns></returns>\n        public IEnumerable<TEntity> WhereInclude(Expression<Func<TEntity, bool>> whereClause, Expression<Func<TEntity, object>> include = null)\n        {\n            var result = _queryableReadOnly.Where(whereClause).Include(include);\n            return result.AsEnumerable();\n        }\n\n        /// <summary>\n        /// Gets the list of entities that matches the where clause,\n        /// including the related entities.\n        /// </summary>\n        /// <param name=\"whereClause\">where clause.</param>\n        /// <param name=\"includes\">Entities to include.</param>\n        /// <returns></returns>\n        public IEnumerable<TEntity> WhereInclude(Expression<Func<TEntity, bool>> whereClause, string[] includes)\n        {\n            var query = _queryableReadOnly.Where(whereClause);\n\n            if (includes != null)\n            {\n                foreach (var include in includes)\n                {\n                    query = query.Include(include);\n                }\n            }\n\n            return query.AsEnumerable();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/Exceptions/DatabaseDoesNotExistException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.EntityFramework.Exceptions\n{\n    /// <summary>\n    /// Occurs when the database is not found in Sql Server.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [Serializable]\n    [ExcludeFromCodeCoverage]\n    public class DatabaseDoesNotExistException : LiquidException\n    {\n        ///<inheritdoc/>\n        public DatabaseDoesNotExistException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"DatabaseDoesNotExistException\"/> class.\n        /// </summary>\n        /// <param name=\"databaseName\">Name of the database.</param>\n        public DatabaseDoesNotExistException(string databaseName) : base($\"Database {databaseName} does not exist. Please check name or create a new database.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public DatabaseDoesNotExistException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/Extensions/DbContextExtensions.cs",
    "content": "﻿using System;\nusing System.Linq;\n\nnamespace Microsoft.EntityFrameworkCore\n{\n    /// <summary>\n    /// Entity Framework <see cref=\"DbContext\"/> extension methods.\n    /// </summary>\n    public static class DbContextExtensions\n    {\n        /// <summary>\n        /// Untrack entities onto <see cref=\"DbContext\"/>.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">type of entity.</typeparam>\n        /// <param name=\"dbContext\">The database context.</param>\n        /// <param name=\"predicate\">Entities filter.</param>\n        public static void Detach<TEntity>(this DbContext dbContext, Func<TEntity, bool> predicate) where TEntity : class\n        {\n            var entities = dbContext.Set<TEntity>().Local.Where(predicate);\n            foreach (var entity in entities)\n            {\n                dbContext.Entry(entity).State = EntityState.Detached;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/Extensions/ILiquidRepositoryExtensions.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Microsoft.EntityFrameworkCore;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq.Expressions;\n\nnamespace Liquid.Repository.EntityFramework.Extensions\n{\n    /// <summary>\n    /// Extension methods for <see cref=\"ILiquidRepository{TEntity, TIdentifier}\"/>.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class ILiquidRepositoryExtensions\n    {\n        /// <summary>\n        /// Gets the list of entities that matches the where clause,\n        /// including the related entities. \n        /// </summary>\n        /// <typeparam name=\"TEntity\"></typeparam>\n        /// <typeparam name=\"TIdentifier\"></typeparam>\n        /// <typeparam name=\"TContext\"></typeparam>\n        /// <param name=\"repository\"></param>\n        /// <param name=\"whereClause\"> The where clause.</param>\n        /// <param name=\"include\"> The include clause.</param>\n        /// <returns></returns>\n        public static ILiquidRepository<TEntity, TIdentifier> WhereInclude<TEntity, TIdentifier, TContext>(this ILiquidRepository<TEntity, TIdentifier> repository\n            , Expression<Func<TEntity, bool>> whereClause, Expression<Func<TEntity, object>> include = null) \n            where TEntity : LiquidEntity<TIdentifier>, new() where TContext : DbContext\n        {\n            var EfRepository = repository as EntityFrameworkRepository<TEntity, TIdentifier,TContext>;\n\n            EfRepository.WhereInclude(whereClause, include);\n\n            return repository;\n        }\n\n        /// <summary>\n        /// Gets the list of entities that matches the where clause,\n        /// including the related entities.\n        /// </summary>\n        /// <typeparam name=\"TEntity\"></typeparam>\n        /// <typeparam name=\"TIdentifier\"></typeparam>\n        /// <typeparam name=\"TContext\"></typeparam>\n        /// <param name=\"repository\"></param>\n        /// <param name=\"whereClause\">where clause.</param>\n        /// <param name=\"includes\">Entities to include.</param>\n        /// <returns></returns>\n        public static ILiquidRepository<TEntity, TIdentifier> WhereInclude<TEntity, TIdentifier, TContext>(this ILiquidRepository<TEntity, TIdentifier> repository\n                       , Expression<Func<TEntity, bool>> whereClause, string[] includes)\n            where TEntity : LiquidEntity<TIdentifier>, new() where TContext : DbContext\n        {\n            var EfRepository = repository as EntityFrameworkRepository<TEntity, TIdentifier, TContext>;\n\n            EfRepository.WhereInclude(whereClause, includes);\n\n            return repository;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/Extensions/IServiceCollectionExtensions.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Linq;\n\nnamespace Liquid.Repository.EntityFramework.Extensions\n{\n    /// <summary>\n    /// Entity Framework Service Collection Extensions Class.\n    /// </summary>\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Registers a <see cref=\"EntityFrameworkRepository{TEntity, TIdentifier, TContext}\"/> service \n        /// for the entity <typeparamref name=\"TEntity\"/>, and <see cref=\"DbContext\"/> \n        /// <typeparamref name=\"TContext\"/> with <see cref=\"IEntityFrameworkDataContext{TContext}\"/> \n        /// if not previously registered.\n        /// This method also registers <see cref=\"LiquidTelemetryInterceptor\"/> for EntityFrameworkRepository instance.\n        /// </summary>\n        /// <param name=\"services\">The services.</param>\n        /// <param name=\"optionsAction\">  An action to configure the <see cref=\"DbContextOptions\"/> \n        ///  for the context.</param>\n        public static IServiceCollection AddLiquidEntityFramework<TContext, TEntity, TIdentifier>(this IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction)\n            where TEntity : LiquidEntity<TIdentifier>, new()\n            where TContext : DbContext\n        {\n            AddLiquidDbContext<TContext>(services, optionsAction);\n\n            services.AddScoped<EntityFrameworkRepository<TEntity, TIdentifier, TContext>>();\n\n            services.AddScopedLiquidTelemetry<ILiquidRepository<TEntity, TIdentifier>, EntityFrameworkRepository<TEntity, TIdentifier, TContext>>();\n\n            return services;\n        }\n\n        private static void AddLiquidDbContext<TContext>(IServiceCollection services, Action<DbContextOptionsBuilder> optionsAction) where TContext : DbContext\n        {\n            var dbContext = services.FirstOrDefault(x => x.ServiceType == typeof(IEntityFrameworkDataContext<TContext>));\n\n            if(dbContext is null)\n            {\n                services.AddDbContext<TContext>(optionsAction);\n\n                services.AddScoped<IEntityFrameworkDataContext<TContext>, EntityFrameworkDataContext<TContext>>();                \n            }            \n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/IEntityFrameworkDataContext.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Microsoft.EntityFrameworkCore;\n\nnamespace Liquid.Repository.EntityFramework\n{\n    /// <summary>\n    /// EntityFramework database context interface.\n    /// </summary>\n    /// <typeparam name=\"TContext\">The type of the <see cref=\"DbContext\"/>.</typeparam>\n    /// <seealso cref=\"ILiquidDataContext\" />\n    public interface IEntityFrameworkDataContext<out TContext> : ILiquidDataContext where TContext : DbContext\n    {\n        /// <summary>\n        /// Gets the Entity Framework client.\n        /// </summary>\n        /// <value>\n        /// The Entity Framework client.\n        /// </value>\n        TContext DbClient { get; }\n    }\n}"
  },
  {
    "path": "src/Liquid.Repository.EntityFramework/Liquid.Repository.EntityFramework.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.Repository.EntityFramework</PackageId>\n    <Version>8.0.0</Version>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2019</Copyright>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <IsPackable>true</IsPackable>\n    <DebugType>Full</DebugType>\n    <NoWarn>1701;1702;1584;1658</NoWarn>\n  </PropertyGroup>\n  <ItemGroup>\n\t  <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n\t  <PackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"8.0.15\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/Exceptions/MongoEntitySettingsDoesNotExistException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.Repository.Mongo.Exceptions\n{\n    /// <summary>\n    /// Occurs when the Mongo Entity Settings aren't not found in any configuration provider. Check the entity name and the configuration files.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class MongoEntitySettingsDoesNotExistException : LiquidException\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoEntitySettingsDoesNotExistException\"/> class.\n        /// </summary>\n        /// <param name=\"entityName\">The entity name.</param>\n        public MongoEntitySettingsDoesNotExistException(string entityName)\n            : base($\"The Mongo Entity Settings for entity '{entityName}' does not exist.\")\n        {\n        }\n        ///<inheritdoc/>\n        public MongoEntitySettingsDoesNotExistException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.Repository.Mongo/Exceptions/MongoException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.Mongo.Exceptions\n{\n    /// <summary>\n    /// Occurs when an exception has occurred in Mongo Db.\n    /// </summary>\n    /// <seealso cref=\"LiquidException\" />\n    [ExcludeFromCodeCoverage]\n    public class MongoException : LiquidException\n    {\n        ///<inheritdoc/>\n        public MongoException()\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoException\"/> class.\n        /// </summary>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public MongoException(Exception innerException) : base(\"An error has occurred in database command. Please see inner exception\", innerException)\n        {\n        }\n\n        ///<inheritdoc/>\n        public MongoException(string message) : base(message)\n        {\n        }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoException\" /> class.\n        /// </summary>\n        /// <param name=\"message\">The message.</param>\n        /// <param name=\"innerException\">The inner exception.</param>\n        public MongoException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/Extensions/IMongoCollectionExtensions.cs",
    "content": "﻿using MongoDB.Driver;\nusing System;\nusing System.Linq.Expressions;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.Mongo.Extensions\n{\n    /// <summary>\n    /// Extends <see cref=\"IMongoCollection{TDocument}\"/> methods.\n    /// </summary>\n    public static class IMongoCollectionExtensions\n    {\n        /// <summary>\n        ///   Inserts a single document.\n        /// </summary>\n        /// <typeparam name=\"TDocument\">The type of the document.</typeparam>\n        /// <param name=\"collection\">The collection.</param>\n        /// <param name=\"document\">The document.</param>\n        /// <param name=\"session\">The transaction session.</param>\n        public static async Task InsertOneAsync<TDocument>(this IMongoCollection<TDocument> collection, TDocument document, IClientSessionHandle session = null)\n        {\n            if (session is null)\n            {\n                await collection.InsertOneAsync(document);\n            }\n            else\n            {\n                await collection.InsertOneAsync(session, document);\n            }\n        }\n        /// <summary>\n        /// Finds the documents matching the filter.\n        /// </summary>\n        /// <typeparam name=\"TDocument\">The type of the document.</typeparam>\n        /// <param name=\"collection\"> The collection.</param>\n        /// <param name=\"filter\"> The filter.</param>\n        /// <param name=\"session\">The transaction session.</param>\n        public static async Task<IAsyncCursor<TDocument>> FindAsync<TDocument>(this IMongoCollection<TDocument> collection, FilterDefinition<TDocument> filter, IClientSessionHandle session = null)\n        {\n            if (session is null)\n            {\n                return await collection.FindAsync(filter, options: null, cancellationToken: default);\n            }\n\n            return await collection.FindAsync(session, filter);\n        }\n        /// <summary>\n        /// Finds the documents matching the filter.\n        /// </summary>\n        /// <typeparam name=\"TDocument\">The type of the document.</typeparam>\n        /// <param name=\"collection\"> The collection.</param>\n        /// <param name=\"filter\"> The filter.</param>\n        /// <param name=\"session\">The transaction session.</param>\n        public static async Task<IAsyncCursor<TDocument>> FindAsync<TDocument>(this IMongoCollection<TDocument> collection, Expression<Func<TDocument, bool>> filter, IClientSessionHandle session = null)\n        {\n            if (session is null)\n            {\n                return await collection.FindAsync(filter, options: null, cancellationToken: default);\n            }\n\n            return await collection.FindAsync(session, filter);\n        }\n        /// <summary>\n        ///  Deletes a single document.\n        /// </summary>\n        /// <typeparam name=\"TDocument\">The type of the document.</typeparam>\n        /// <param name=\"collection\">The collection.</param>\n        /// <param name=\"filter\">The filter</param>\n        /// <param name=\"session\">The transaction session</param>\n        public static async Task<DeleteResult> DeleteOneAsync<TDocument>(this IMongoCollection<TDocument> collection, Expression<Func<TDocument, bool>> filter, IClientSessionHandle session = null)\n        {\n            if (session is null)\n            {\n                return await collection.DeleteOneAsync(filter);\n            }\n\n            return await collection.DeleteOneAsync(session, filter);\n        }\n        /// <summary>\n        /// Replaces a single document.\n        /// </summary>\n        /// <typeparam name=\"TDocument\">The type of the document.</typeparam>\n        /// <param name=\"collection\">The collection.</param>\n        /// <param name=\"filter\"> The filter.</param>\n        /// <param name=\"replacement\">The replacement.</param>\n        /// <param name=\"options\">The options.</param>\n        /// <param name=\"session\">The transaction session.</param>\n        public static async Task<ReplaceOneResult> ReplaceOneAsync<TDocument>(this IMongoCollection<TDocument> collection, Expression<Func<TDocument, bool>> filter, TDocument replacement, ReplaceOptions options = null, IClientSessionHandle session = null)\n        {\n            if (session is null)\n            {\n                return await collection.ReplaceOneAsync(filter, replacement, options);\n            }\n\n            return await collection.ReplaceOneAsync(session, filter, replacement, options);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/Extensions/IServiceCollectionExtensions.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Repository.Mongo.Settings;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\n\nnamespace Liquid.Repository.Mongo.Extensions\n{\n    /// <summary>\n    /// Mongo Db Service Collection Extensions Class.\n    /// </summary>\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Registers a <see cref=\"MongoRepository{TEntity, TIdentifier}\"/> for the entity <typeparamref name=\"TEntity\"/>,\n        /// and a <see cref=\"MongoClientFactory\"/>  if not previously registered.\n        /// This method may also registers <see cref=\"LiquidTelemetryInterceptor\"/> for MongoRepository instance.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that the repository should correspond to</typeparam>\n        /// <typeparam name=\"TIdentifier\">Entity identifier type.</typeparam>\n        /// <param name=\"services\">Extended ServiceCollection object.</param>\n        /// <param name=\"sectionName\">Name of the configuration section where all entities have their repository settings configured.</param>\n        /// <param name=\"collectionName\">Name of the collection in the database that the repository should correspond to.</param>\n        /// <param name=\"activateTelemetry\">Specifies whether the telemetry should be activated or not for this repository. Default: True.</param>\n        public static IServiceCollection AddLiquidMongoRepository<TEntity, TIdentifier>(this IServiceCollection services, string sectionName, string collectionName, bool activateTelemetry = true)\n            where TEntity : LiquidEntity<TIdentifier>, new()\n        {\n            services.TryAddSingleton<IMongoClientFactory, MongoClientFactory>();\n\n            services.AddOptions<MongoDbSettings>()\n             .Configure<IConfiguration>((settings, configuration) =>\n             {\n                 configuration.GetSection(sectionName).Bind(settings);\n             });\n\n            services.AddScoped<IMongoDataContext<TEntity>>((provider) =>\n            {\n                return ActivatorUtilities.CreateInstance<MongoDataContext<TEntity>>(provider, collectionName);\n            });\n\n\n            if (activateTelemetry)\n            {\n                services.AddScoped<MongoRepository<TEntity, TIdentifier>>();\n                services.AddScopedLiquidTelemetry<ILiquidRepository<TEntity, TIdentifier>, MongoRepository<TEntity, TIdentifier>>();\n            }\n            else\n            {\n                services.AddScoped<ILiquidRepository<TEntity, TIdentifier>, MongoRepository<TEntity, TIdentifier>>();\n            }\n\n\n            return services;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/IMongoClientFactory.cs",
    "content": "﻿using Liquid.Core.Settings;\nusing Liquid.Repository.Mongo.Settings;\nusing MongoDB.Driver;\n\nnamespace Liquid.Repository.Mongo\n{\n    /// <summary>\n    /// Provide client generator methods.\n    /// </summary>\n    public interface IMongoClientFactory\n    {\n        /// <summary>\n        /// Provide a new instance of <see cref=\"MongoClient\"/> with db conection started.\n        /// </summary>\n        /// <param name=\"collectionName\"></param>\n        /// <param name=\"settings\"></param>\n        IMongoClient GetClient(string collectionName, out MongoEntitySettings settings);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/IMongoDataContext.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.Repository.Mongo.Settings;\nusing MongoDB.Driver;\n\nnamespace Liquid.Repository.Mongo\n{\n    /// <summary>\n    /// Mongo database context interface.\n    /// </summary>\n    /// <seealso cref=\"ILiquidDataContext\" />\n    public interface IMongoDataContext<TEntity> : ILiquidDataContext\n    {\n        /// <summary>\n        /// Gets configurations set from <typeparamref name=\"TEntity\"/> attribute.\n        /// </summary>\n        MongoEntitySettings Settings { get; }\n        /// <summary>\n        /// Gets the Mongo Database.\n        /// </summary>\n        /// <value>\n        /// The client.\n        /// </value>\n        IMongoDatabase Database { get; }\n\n        /// <summary>\n        /// Gets the mongo client.\n        /// </summary>\n        /// <value>\n        /// The mongo client.\n        /// </value>\n        IMongoClient MongoClient { get; }\n\n        /// <summary>\n        /// Gets the mongo session handle.\n        /// </summary>\n        IClientSessionHandle ClientSessionHandle { get; }\n\n        /// <summary>\n        /// Sets an instance of <see cref=\"MongoDatabaseBase\"/> into de property Database, \n        /// which is obtained from MongoClient by database name.<see cref=\"MongoClient.GetDatabase(string, MongoDatabaseSettings)\"/>.\n        /// </summary>\n        /// <param name=\"databaseName\">The name of database.</param>\n        void SetDatabase(string databaseName);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/Liquid.Repository.Mongo.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.Repository.Mongo</PackageId>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2019</Copyright>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Version>8.0.0</Version>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <IsPackable>true</IsPackable>\n    <DebugType>Full</DebugType>\n    <ProjectGuid>{D7B0D4F0-756B-4038-9DB2-0A1AD65ED72A}</ProjectGuid>\n    <Description>\n\n    </Description>\n\n    <NoWarn>1701;1702;1584;1658</NoWarn>\n  </PropertyGroup>\n\n  \n\n  <ItemGroup>\n\t<PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n\t<PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n\t<PackageReference Include=\"MongoDB.Driver\" Version=\"3.4.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/MongoClientFactory.cs",
    "content": "﻿using Liquid.Repository.Mongo.Exceptions;\nusing Liquid.Repository.Mongo.Settings;\nusing Microsoft.Extensions.Options;\nusing MongoDB.Driver;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\n\nnamespace Liquid.Repository.Mongo\n{\n    ///<inheritdoc/>\n    public class MongoClientFactory : IMongoClientFactory\n    {\n        private readonly IOptions<MongoDbSettings> _settings;\n        private readonly IDictionary<string, IMongoClient> _mongoClients;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoClientFactory\" /> class.\n        /// </summary>\n        public MongoClientFactory(IOptions<MongoDbSettings> settings)\n        {\n            _mongoClients = new Dictionary<string, IMongoClient>();\n            _settings = settings ?? throw new ArgumentNullException(nameof(settings));\n        }\n\n        ///<inheritdoc/>\n        public IMongoClient GetClient(string collectionName, out MongoEntitySettings settings)\n        {\n            if (collectionName is null) throw new ArgumentNullException(nameof(collectionName));\n            settings = _settings.Value.Settings.FirstOrDefault(x => x.CollectionName == collectionName);\n\n            if (settings is null) throw new MongoEntitySettingsDoesNotExistException(collectionName);            \n\n            // Try to get from the created clients collection, otherwise creates a new client\n            IMongoClient mongoClient = _mongoClients.TryGetValue(collectionName, out mongoClient) ? mongoClient : CreateClient(settings);\n\n            return mongoClient;\n        }\n\n        private IMongoClient CreateClient(MongoEntitySettings databaseSettings)\n        {\n            var mongoClient = new MongoClient(databaseSettings.ConnectionString);\n\n            _mongoClients.Add(databaseSettings.CollectionName, mongoClient);\n\n            return mongoClient;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/MongoDataContext.cs",
    "content": "﻿using Liquid.Repository.Mongo.Exceptions;\nusing Liquid.Repository.Mongo.Settings;\nusing MongoDB.Driver;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.Mongo\n{\n    /// <summary>\n    /// Implements the Mongo data context for repositories.\n    /// </summary>\n    /// <seealso cref=\"IMongoDataContext{TEntity}\" />\n    public class MongoDataContext<TEntity> : IMongoDataContext<TEntity>\n    {\n        private bool _disposed = false;\n        private readonly IMongoClient _mongoClient;\n        private IMongoDatabase _database;\n        private IClientSessionHandle _clientSessionHandle;\n        private readonly MongoEntitySettings _settings;\n\n        /// <summary>\n        /// Gets the Mongo Database.\n        /// </summary>\n        /// <value>\n        /// The client.\n        /// </value>\n        public IMongoDatabase Database => _database;\n\n        /// <summary>\n        /// Gets the mongo client.\n        /// </summary>\n        /// <value>\n        /// The mongo client.\n        /// </value>\n        public IMongoClient MongoClient => _mongoClient;\n\n        /// <summary>\n        /// Gets the mongo session handle.\n        /// </summary>\n        public IClientSessionHandle ClientSessionHandle => _clientSessionHandle;\n\n        /// <summary>\n        /// Gets the identifier of data context.\n        /// </summary>\n        /// <value>\n        /// The identifier.\n        /// </value>\n        public string Id { get; }\n\n        /// <summary>\n        /// \n        /// </summary>\n        public MongoEntitySettings Settings => _settings;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoDataContext{Tentity}\" /> class.\n        /// </summary>\n        /// <param name=\"clientProvider\">Mongo client generator.</param>\n        /// <param name=\"collectionName\">        /// </param>\n        /// <exception cref=\"ArgumentNullException\">\n        /// clientProvider\n        /// or\n        /// settingsFactory\n        /// </exception>\n        public MongoDataContext(IMongoClientFactory clientProvider, string collectionName)\n        {    \n            if (clientProvider is null) throw new ArgumentNullException(nameof(clientProvider));\n            if (collectionName is null) throw new ArgumentNullException(nameof(collectionName));                      \n                        \n            _mongoClient = clientProvider.GetClient(collectionName, out _settings);\n\n            if (_settings is null) throw new MongoEntitySettingsDoesNotExistException(nameof(TEntity));\n\n            SetDatabase(_settings.DatabaseName);\n        }\n\n        /// <summary>\n        /// Starts the transaction of all data contexts in repositories inside UnitOfWork.\n        /// </summary>\n        public async Task StartTransactionAsync()\n        {\n            _clientSessionHandle = await _mongoClient.StartSessionAsync();\n            _clientSessionHandle.StartTransaction();\n        }\n\n        /// <summary>\n        /// Commits all commands added to the database context.\n        /// </summary>\n        public async Task CommitAsync()\n        {\n            await _clientSessionHandle.CommitTransactionAsync();\n        }\n\n        /// <summary>\n        /// Rollbacks the transactions.\n        /// </summary>\n        public async Task RollbackTransactionAsync()\n        {\n            await _clientSessionHandle.AbortTransactionAsync();\n        }\n\n        ///<inheritdoc/>\n        public void Dispose()\n        {\n            Dispose(true);\n            GC.SuppressFinalize(this);\n        }\n\n        /// <summary>\n        /// Releases the allocated resources <see cref=\"IClientSessionHandle\"/> for this context.\n        /// </summary>\n        /// <param name=\"disposing\">Indicates if method should perform dispose.</param>\n        protected virtual void Dispose(bool disposing)\n        {\n            if (_disposed)\n            {\n                return;\n            }\n\n            if (disposing)\n            {\n                if (_clientSessionHandle?.IsInTransaction == true) _clientSessionHandle.AbortTransaction();\n                _clientSessionHandle?.Dispose();\n            }\n\n            _disposed = true;\n        }\n\n        ///<inheritdoc/>\n        public void SetDatabase(string databaseName)\n        {\n            _database = _mongoClient.GetDatabase(databaseName);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/MongoRepository.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Liquid.Repository.Mongo.Extensions;\nusing Liquid.Repository.Mongo.Settings;\nusing MongoDB.Bson;\nusing MongoDB.Driver;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.Mongo\n{\n    /// <summary>\n    /// Mongo database repository class. Implements the <seealso cref=\"ILiquidRepository{TEntity, TIdentifier}\"/> interface to provide \n    /// the repository pattern access to a Mongo Db document. Also provides a Mongo data context to extend Mongo client resources.\n    /// </summary>\n    /// <typeparam name=\"TEntity\">The type of the entity.</typeparam>\n    /// <typeparam name=\"TIdentifier\">The type of the identifier.</typeparam>\n    /// <seealso cref=\"ILiquidRepository{TEntity, TIdentifier}\" />\n    public class MongoRepository<TEntity, TIdentifier> : ILiquidRepository<TEntity, TIdentifier> where TEntity : LiquidEntity<TIdentifier>, new()\n    {\n        private readonly MongoEntitySettings _settings;\n\n        ///<inheritdoc/>\n        public IMongoDataContext<TEntity> MongoDataContext { get; }\n\n        ///<inheritdoc/>\n        public ILiquidDataContext DataContext => MongoDataContext;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"MongoRepository{TEntity, TIdentifier}\" /> class.\n        /// </summary>\n        /// <param name=\"dataContext\">The data context.</param>\n        /// <exception cref=\"System.ArgumentNullException\">\n        /// telemetryFactory\n        /// or\n        /// dataContext\n        /// </exception>\n        public MongoRepository(IMongoDataContext<TEntity> dataContext)\n        {\n            MongoDataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));\n            \n            _settings = dataContext.Settings;    \n        }\n\n        ///<inheritdoc/>\n        public async Task AddAsync(TEntity entity)\n        {\n\n            var collection = MongoDataContext.Database.GetCollection<TEntity>(_settings.CollectionName);\n            await collection.InsertOneAsync(entity, MongoDataContext?.ClientSessionHandle);\n\n        }\n\n        ///<inheritdoc/>\n        public async Task<IEnumerable<TEntity>> FindAllAsync()\n        {\n            var collection = MongoDataContext.Database.GetCollection<TEntity>(_settings.CollectionName);\n\n            var response = await collection.FindAsync(new BsonDocument(), MongoDataContext?.ClientSessionHandle);\n            var returnValue = response.ToEnumerable();\n\n            return returnValue;\n        }\n\n        ///<inheritdoc/>\n        public async Task<TEntity> FindByIdAsync(TIdentifier id)\n        {\n            var collection = MongoDataContext.Database.GetCollection<TEntity>(_settings.CollectionName);\n            var result = await collection.FindAsync(e => e.Id.Equals(id), MongoDataContext?.ClientSessionHandle);\n            var returnValue = result.SingleOrDefault();\n\n            return returnValue;\n        }\n\n        ///<inheritdoc/>\n        public async Task RemoveByIdAsync(TIdentifier id)\n        {\n            var collection = MongoDataContext.Database.GetCollection<TEntity>(_settings.CollectionName);\n            await collection.DeleteOneAsync(e => e.Id.Equals(id), MongoDataContext?.ClientSessionHandle);\n        }\n\n        ///<inheritdoc/>\n        public async Task UpdateAsync(TEntity entity)\n        {\n\n            var collection = MongoDataContext.Database.GetCollection<TEntity>(_settings.CollectionName);\n            await collection.ReplaceOneAsync(x => x.Id.Equals(entity.Id), entity, new ReplaceOptions { IsUpsert = true }, MongoDataContext?.ClientSessionHandle);\n\n        }\n\n        ///<inheritdoc/>\n        public async Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> whereClause)\n        {\n            var collection = MongoDataContext.Database.GetCollection<TEntity>(_settings.CollectionName);\n\n            var returnValue = (await collection.FindAsync(whereClause, MongoDataContext?.ClientSessionHandle)).ToEnumerable();\n\n            return returnValue;\n        }        \n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.Mongo/Settings/MongoEntitySettings.cs",
    "content": "﻿using Liquid.Core.Settings;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.Mongo.Settings\n{\n    /// <summary>\n    /// Properties set list of service bus configurations.\n    /// </summary>\n    public class MongoDbSettings\n    {\n        /// <summary>\n        /// Properties set list of service bus configurations.\n        /// </summary>\n        public List<MongoEntitySettings> Settings { get; set; }\n    }\n\n    /// <summary>\n    /// MongoDB repository data entity settings.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class MongoEntitySettings\n    {\n        ///<inheritdoc/>\n        public string CollectionName { get; set; }\n\n        ///<inheritdoc/>\n        public string ShardKey { get; set; }\n\n        /// <summary>\n        /// Gets or sets the database connection string.\n        /// </summary>\n        /// <value>\n        /// The database connection string.\n        /// </value>\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name of the database.\n        /// </summary>\n        /// <value>\n        /// The name of the database.\n        /// </value>\n        public string DatabaseName { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.OData/Extensions/IServiceCollectionExtension.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.OData.Extensions\n{\n    /// <summary>\n    /// Extension methods for IServiceCollection.\n    /// </summary>\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Registers a <see cref=\"ODataRepository{TEntity, TIdentifier}\"/> for the entity <typeparamref name=\"TEntity\"/>,\n        /// and a <see cref=\"ODataClientFactory\"/>  if not previously registered.\n        /// </summary>\n        /// <typeparam name=\"TEntity\">Type of entity that the repository should correspond to</typeparam>\n        /// <typeparam name=\"TIdentifier\">Entity identifier type.</typeparam>\n        /// <param name=\"services\">Extended ServiceCollection object.</param>\n        /// <param name=\"sectionName\">Name of the configuration section where all entities have their repository settings configured.</param>\n        /// <param name=\"entityName\">Name of the entity in the database that the repository should correspond to.</param>        \n        public static IServiceCollection AddLiquidOdataRepository<TEntity, TIdentifier>(this IServiceCollection services, string sectionName, string entityName)\n            where TEntity : LiquidEntity<TIdentifier>, new()\n        {\n            services.TryAddSingleton<IODataClientFactory, ODataClientFactory>();\n            services.TryAddSingleton<ILiquidContext, LiquidContext>();\n\n            services.AddOptions<ODataOptions>()\n             .Configure<IConfiguration>((settings, configuration) =>\n             {\n                 configuration.GetSection(sectionName).Bind(settings);\n             });\n\n            services.AddScoped<ILiquidRepository<TEntity, TIdentifier>>((provider) =>\n            {\n                return ActivatorUtilities.CreateInstance<ODataRepository<TEntity, TIdentifier>>(provider, entityName);\n            });\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.OData/IODataClientFactory.cs",
    "content": "﻿using Simple.OData.Client;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.OData\n{\n    /// <summary>\n    /// Defines an object with the ability to create an OData client.\n    /// </summary>\n    public interface IODataClientFactory\n    {\n        /// <summary>\n        /// Create an OData client.\n        /// </summary>\n        /// <param name=\"entityName\">The entity name.</param>\n        IODataClient CreateODataClientAsync(string entityName);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.OData/Liquid.Repository.OData.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\t  <PackageId>Liquid.Repository.OData</PackageId>\n\t  <Nullable>enable</Nullable>\n\t  <PackageLicenseExpression>MIT</PackageLicenseExpression>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <DebugType>Full</DebugType>\n\t  <Description>\n\t\t  Liquid Repository adapter for Odata apis.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n  </PropertyGroup>\n\n\t<ItemGroup>\n\t\t<None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n\t\t\t<PackagePath></PackagePath>\n\t\t\t<Pack>True</Pack>\n\t\t</None>\n\t</ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n    <PackageReference Include=\"Simple.OData.Client\" Version=\"6.0.1\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Repository.OData/ODataClientFactory.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Options;\nusing Simple.OData.Client;\n\nnamespace Liquid.Repository.OData\n{\n    ///<inheritdoc/>\n    public class ODataClientFactory : IODataClientFactory\n    {\n        private readonly IOptions<ODataOptions> _options;\n        private readonly ILiquidContext _context;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"ODataClientFactory\"/>\n        /// </summary>\n        /// <param name=\"options\"></param>\n        /// <param name=\"context\"></param>\n        public ODataClientFactory(IOptions<ODataOptions> options, ILiquidContext context)\n        {\n            _options = options ?? throw new ArgumentNullException(nameof(options));\n            _context = context ?? throw new ArgumentNullException(nameof(context));\n        }\n\n        ///<inheritdoc/>\n        public IODataClient CreateODataClientAsync(string entityName)\n        {\n            var hasToken = _context.current.ContainsKey(\"OdataToken\");\n            var token = _context.Get(\"OdataToken\")?.ToString();\n\n            if (!hasToken || string.IsNullOrEmpty(token))\n            {\n                throw new KeyNotFoundException(\"Token is required to perform this operation. The 'OdataToken' \" +\n                    \"key was not found in the context.\");\n            }\n\n            var settings = _options?.Value?.Settings.FirstOrDefault(x => x.EntityName == entityName);\n\n            if (settings == null)\n                throw new ArgumentOutOfRangeException(nameof(entityName));\n\n            var client = new ODataClient(GetODataSettings(settings, token));\n\n            return client;\n        }\n\n        /// <summary>\n        ///Initialize a new instance of <see cref=\"ODataClientSettings\"/>\n        /// </summary>\n        /// <param name=\"settings\">OData settings.</param>\n        /// <param name=\"token\"> Authorization token.</param>\n        /// <returns></returns>\n        private static ODataClientSettings GetODataSettings(ODataSettings? settings, string token)\n        {\n            var odataSettings = new ODataClientSettings(new Uri(settings.BaseUrl));\n\n            odataSettings.BeforeRequest = (message) =>\n            {\n                message.Headers.Add(\"Authorization\", token);\n            };\n\n            if (!settings.ValidateCert)\n            {\n                var handler = new HttpClientHandler();\n\n                odataSettings.OnApplyClientHandler = (handler) =>\n                {\n                    handler.ServerCertificateCustomValidationCallback +=\n                                (sender, certificate, chain, errors) =>\n                                {\n                                    return true;\n                                };\n                };\n            }\n\n            return odataSettings;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.OData/ODataRepository.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing System.Linq.Expressions;\n\nnamespace Liquid.Repository.OData\n{\n    ///<inheritdoc/>\n    public class ODataRepository<TEntity, TIdentifier> : ILiquidRepository<TEntity, TIdentifier> where TEntity : LiquidEntity<TIdentifier>, new()\n    {\n        ///<inheritdoc/>\n        public ILiquidDataContext DataContext => throw new NotImplementedException();\n\n        private readonly IODataClientFactory _clientFactory;\n        private readonly string _entityName;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"ODataRepository{TEntity, TIdentifier}\"/>\n        /// </summary>\n        /// <param name=\"clientFactory\"> Factory to create OData client.</param>\n        /// <param name=\"entityName\"> Name of the entity to be used in the repository.</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public ODataRepository(IODataClientFactory clientFactory, string entityName)\n        {\n            _clientFactory = clientFactory ?? throw new ArgumentNullException(nameof(clientFactory));\n            _entityName = entityName ?? throw new ArgumentNullException(nameof(entityName));\n        }\n\n\n        ///<inheritdoc/>\n        public async Task AddAsync(TEntity entity)\n        {   \n            var client = _clientFactory.CreateODataClientAsync(_entityName);\n\n            await client.For<TEntity>().Set(entity).InsertEntryAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task<IEnumerable<TEntity>> FindAllAsync()\n        {\n            var client = _clientFactory.CreateODataClientAsync(_entityName);\n\n            return await client.For<TEntity>().FindEntriesAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task<TEntity> FindByIdAsync(TIdentifier id)\n        {\n            var client = _clientFactory.CreateODataClientAsync(_entityName);\n\n            return await client.For<TEntity>().Key(id).FindEntryAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task RemoveByIdAsync(TIdentifier id)\n        {\n            var client = _clientFactory.CreateODataClientAsync(_entityName);\n\n            await client.For<TEntity>().Key(id).DeleteEntryAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task UpdateAsync(TEntity entity)\n        {\n            var client = _clientFactory.CreateODataClientAsync(_entityName);\n\n            await client.For<TEntity>().Set(entity).UpdateEntryAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> whereClause)\n        {\n            var client = _clientFactory.CreateODataClientAsync(_entityName);\n\n            return await client.For<TEntity>().Filter(whereClause).FindEntriesAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Repository.OData/ODataSettings.cs",
    "content": "﻿namespace Liquid.Repository.OData\n{\n    /// <summary>\n    /// Odata configurations set.\n    /// </summary>\n    public class ODataSettings\n    {\n        /// <summary>\n        /// Name of entity to be configured.\n        /// </summary>\n        public string EntityName { get; set; }\n\n        /// <summary>\n        /// Base URL of the Odata service.\n        /// </summary>\n        public string BaseUrl { get; set; }\n\n        /// <summary>\n        /// Indicates if the Odata service requires certificate validations.\n        /// </summary>\n        public bool ValidateCert { get; set; } = false;\n    }\n\n    /// <summary>\n    /// Odata configuration options.\n    /// </summary>\n    public class ODataOptions\n    {\n        /// <summary>\n        /// List of Odata options set.\n        /// </summary>\n        public List<ODataSettings> Settings { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Storage.AzureStorage/BlobClientFactory.cs",
    "content": "﻿using Azure.Storage.Blobs;\nusing Microsoft.Extensions.Options;\n\nnamespace Liquid.Storage.AzureStorage\n{\n    ///<inheritdoc/>\n    public class BlobClientFactory : IBlobClientFactory\n    {\n        private readonly StorageSettings _options;\n        private readonly List<BlobContainerClient> _clients = new List<BlobContainerClient>();\n\n        ///<inheritdoc/>\n        public IList<BlobContainerClient> Clients => _clients;\n\n        /// <summary>\n        /// Inicialize a new instance of <see cref=\"BlobClientFactory\"/>\n        /// </summary>\n        /// <param name=\"options\">Configurations set.</param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public BlobClientFactory(IOptions<StorageSettings>? options)\n        {\n            _options = options?.Value ?? throw new ArgumentNullException(nameof(options));\n        }\n\n        ///<inheritdoc/>\n        public void SetContainerClients()\n        {\n            if (_options.Containers.Count == 0)\n                throw new ArgumentNullException(nameof(_options));\n\n            foreach (var container in _options.Containers)\n            {\n                var client = new BlobContainerClient(container.ConnectionString, container.ContainerName);\n\n                _clients.Add(client);\n            }\n        }\n\n        ///<inheritdoc/>\n        public BlobContainerClient GetContainerClient(string containerName)\n        {\n            var client = _clients.FirstOrDefault(x => x.Name == containerName);\n\n            if (client == null)\n            {\n                throw new ArgumentException($\"Container named {containerName} not found.\");\n            }\n\n            return client;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Storage.AzureStorage/Extensions/IServiceCollectionExtensions.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Storage.AzureStorage.Extensions\n{\n    /// <summary>\n    /// Extension methods of <see cref=\"IServiceCollection\"/>\n    /// for register Liquid Azure Storage services.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        /// Registers <see cref=\"LiquidStorageAzure\"/> service, it's dependency\n        /// <see cref=\"BlobClientFactory\"/>, and also set configuration\n        /// option <see cref=\"StorageSettings\"/>.\n        /// </summary>\n        /// <param name=\"services\">service collection instance.</param>\n        /// <param name=\"configSection\">configuration section of storage settings.</param>\n        public static IServiceCollection AddLiquidAzureStorageAdapter(this IServiceCollection services, string configSection)\n        {\n            services.AddOptions<StorageSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(configSection).Bind(settings);\n            });\n\n            services.AddSingleton<IBlobClientFactory, BlobClientFactory>();\n\n            services.AddScoped<ILiquidStorage, LiquidStorageAzure>();\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Storage.AzureStorage/IBlobClientFactory.cs",
    "content": "﻿using Azure.Storage.Blobs;\n\nnamespace Liquid.Storage.AzureStorage\n{\n    /// <summary>\n    /// <see cref=\"BlobContainerClient\"/> instances factory. \n    /// </summary>\n    public interface IBlobClientFactory\n    {\n        /// <summary>\n        /// List of instances of <see cref=\"BlobContainerClient\"/>.\n        /// </summary>\n        IList<BlobContainerClient> Clients { get; }\n\n        /// <summary>\n        /// Initialize an instance of <see cref=\"BlobContainerClient\"/> \n        /// for each container on the <see cref=\"StorageSettings\"/> and \n        /// add to <see cref=\"Clients\"/>.\n        /// </summary>\n        void SetContainerClients();\n\n        /// <summary>\n        /// Get an instance of <see cref=\"BlobContainerClient\"/>\n        /// by name.\n        /// </summary>\n        /// <param name=\"containerName\"></param>\n        /// <returns></returns>\n        BlobContainerClient GetContainerClient(string containerName);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Storage.AzureStorage/Liquid.Storage.AzureStorage.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\t  <ImplicitUsings>enable</ImplicitUsings>\n\t  <Nullable>enable</Nullable>\n\t  <Authors>Avanade Brazil</Authors>\n\t  <Company>Avanade Inc.</Company>\n\t  <Product>Liquid - Modern Application Framework</Product>\n\t  <Copyright>Avanade 2019</Copyright>\n\t  <Version>8.0.0</Version>\n\t  <GenerateDocumentationFile>true</GenerateDocumentationFile>\n\t  <IsPackable>true</IsPackable>\n\t  <Description>\n\t\t  Adapter for Microsoft Azure Storage integrations.\n\t\t  This component is part of Liquid Application Framework.\n\t  </Description>\n\t  <PackageIcon>logo.png</PackageIcon>\n\t  <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath>\\</PackagePath>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Azure.Storage.Blobs\" Version=\"12.24.0\" />\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Abstractions\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Binder\" Version=\"8.0.2\" />\n    <PackageReference Include=\"Microsoft.Extensions.Options\" Version=\"8.0.2\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.Storage.AzureStorage/LiquidStorageAzure.cs",
    "content": "﻿using Azure;\nusing Azure.Storage.Blobs.Models;\nusing Azure.Storage.Blobs.Specialized;\nusing Azure.Storage.Sas;\nusing Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing System.Text;\n\nnamespace Liquid.Storage.AzureStorage\n{\n    ///<inheritdoc/>\n    public class LiquidStorageAzure : ILiquidStorage\n    {\n        private readonly IBlobClientFactory _factory;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidStorageAzure\"/>\n        /// </summary>\n        /// <param name=\"factory\"></param>\n        /// <exception cref=\"ArgumentNullException\"></exception>\n        public LiquidStorageAzure(IBlobClientFactory factory)\n        {\n            _factory = factory ?? throw new ArgumentNullException(nameof(factory));\n\n            _factory.SetContainerClients();\n        }\n\n        ///<inheritdoc/>\n        public async Task DeleteByTags(IDictionary<string, string> tags, string containerName)\n        {\n            var client = _factory.GetContainerClient(containerName);\n\n            var stringFilterBd = new StringBuilder();\n            foreach (var tag in tags)\n            {\n                stringFilterBd.Append(@$\"\"\"{tag.Key}\"\" = '{tag.Value}' AND \");\n            }\n\n            var stringFilter = stringFilterBd.ToString();\n\n            stringFilter = stringFilter.Substring(0, stringFilter.Length - 4);\n\n            await foreach (TaggedBlobItem blobItem in client.FindBlobsByTagsAsync(stringFilter))\n            {\n                var blockBlob = client.GetBlockBlobClient(blobItem.BlobName);\n\n                await blockBlob.DeleteAsync();\n            }\n        }\n\n        ///<inheritdoc/>\n        public async Task<List<LiquidBlob>> GetAllBlobs(string containerName)\n        {\n            var client = _factory.GetContainerClient(containerName);\n\n            var results = new List<LiquidBlob>();\n\n            await foreach (var blobItem in client.GetBlobsAsync())\n            {\n                var blockBlob = client.GetBlockBlobClient(blobItem.Name);\n                var blob = await blockBlob.DownloadContentAsync();\n                var blobTags = await blockBlob.GetTagsAsync();\n\n                var item = new LiquidBlob\n                {\n                    Blob = blob.Value.Content.ToArray(),\n                    Tags = blobTags?.Value?.Tags,\n                    Name = blobItem.Name,\n                    AbsoluteUri = blockBlob.Uri.AbsoluteUri\n                };\n                results.Add(item);\n            }\n\n            return results;\n        }\n\n        ///<inheritdoc/>\n        public async Task Delete(string id, string containerName)\n        {\n            var client = _factory.GetContainerClient(containerName);\n\n            var blobClient = client.GetBlobClient(id);\n\n            await blobClient.DeleteAsync();\n        }\n\n        ///<inheritdoc/>\n        public async Task<List<LiquidBlob>> ReadBlobsByTags(IDictionary<string, string> tags, string containerName)\n        {\n            var client = _factory.GetContainerClient(containerName);\n\n            var stringFilterBd = new StringBuilder(); \n            foreach (var tag in tags)\n            {\n                stringFilterBd.Append(@$\"\"\"{tag.Key}\"\" = '{tag.Value}' AND \");\n            }\n\n            var stringFilter = stringFilterBd.ToString();\n            stringFilter = stringFilter.Substring(0, stringFilter.Length - 4);\n\n            var results = new List<LiquidBlob>();\n            await foreach (TaggedBlobItem blobItem in client.FindBlobsByTagsAsync(stringFilter))\n            {\n                var blockBlob = client.GetBlockBlobClient(blobItem.BlobName);\n                var blob = await blockBlob.DownloadContentAsync();\n                var blobTags = await blockBlob.GetTagsAsync();\n\n                var item = new LiquidBlob\n                {\n                    Blob = blob.Value.Content.ToArray(),\n                    Tags = blobTags?.Value?.Tags,\n                    Name = blobItem.BlobName,\n                    AbsoluteUri = blockBlob.Uri.AbsoluteUri\n                };\n                results.Add(item);\n            }\n            return results;\n        }\n\n        ///<inheritdoc/>\n        public async Task<string> UploadBlob(byte[] data, string name, string containerName, IDictionary<string, string>? tags = null)\n        {\n            var client = _factory.GetContainerClient(containerName);\n\n            var blockBlob = client.GetBlockBlobClient(name);\n\n            var options = new BlobUploadOptions()\n            {\n                Tags = tags\n            };\n            await blockBlob.UploadAsync(new MemoryStream(data), options);\n\n            return blockBlob.Uri.AbsoluteUri;\n        }\n\n        ///<inheritdoc/>\n        public async Task<LiquidBlob> ReadBlobsByName(string blobName, string containerName)\n        {\n            try\n            {\n                var client = _factory.GetContainerClient(containerName);\n                var blockBlob = client.GetBlockBlobClient(blobName);\n                var blob = await blockBlob.DownloadContentAsync();\n                var tags = await blockBlob.GetTagsAsync();\n\n                var item = new LiquidBlob\n                {\n                    Blob = blob.Value.Content.ToArray(),\n                    Tags = tags?.Value?.Tags,\n                    Name = blobName,\n                    AbsoluteUri = blockBlob.Uri.AbsoluteUri\n                };\n\n                return item;\n            }\n            catch (RequestFailedException storageRequestFailedException)\n                when (storageRequestFailedException.ErrorCode == BlobErrorCode.BlobNotFound)\n            {\n                return null;\n            }\n            catch (Exception ex)\n            {\n                throw new ArgumentOutOfRangeException(\"Error reading blob\", ex);\n            }\n\n        }\n\n        ///<inheritdoc/>\n        public string? GetBlobSasUri(string blobName, string containerName, DateTimeOffset expiresOn, string permissions)\n        {\n            var blobClient = _factory.GetContainerClient(containerName);\n\n            var blockBlob = blobClient.GetBlockBlobClient(blobName);\n\n            if (!blobClient.CanGenerateSasUri)\n            {\n                return null;\n            }\n\n            var sasBuilder = new BlobSasBuilder()\n            {\n                BlobContainerName = blobClient.Name,\n                BlobName = blobName,\n                Resource = \"b\",\n            };\n\n            sasBuilder.ExpiresOn = expiresOn;\n            sasBuilder.SetPermissions(permissions);\n\n            var sasURI = blockBlob.GenerateSasUri(sasBuilder);\n\n            return sasURI.AbsoluteUri;\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.Storage.AzureStorage/StorageSettings.cs",
    "content": "﻿namespace Liquid.Storage.AzureStorage\n{\n    /// <summary>\n    /// Set of Azure Storage containers configs.\n    /// </summary>\n    public class StorageSettings\n    {\n        /// <summary>\n        /// List of container settings.\n        /// </summary>\n        public List<ContainerSettings> Containers { get; set; } = new List<ContainerSettings>();\n    }\n\n    /// <summary>\n    /// Set of a container connection configuration.\n    /// </summary>\n    public class ContainerSettings\n    {\n        /// <summary>\n        /// A connection string includes the authentication information\n        /// required for your application to access data in an Azure Storage\n        /// account at runtime.\n        /// </summary>\n        public string ConnectionString { get; set; }\n\n        /// <summary>\n        /// The name of the blob container in the storage account to reference.\n        /// </summary>\n        public string ContainerName { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Attributes/SwaggerAuthorizationHeaderAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Attributes\n{\n    /// <summary>\n    /// Swagger authorization header attribute class.\n    /// </summary>\n    /// <seealso cref=\"SwaggerCustomHeaderAttribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\n    [ExcludeFromCodeCoverage]\n    public class SwaggerAuthorizationHeaderAttribute : SwaggerBaseHeaderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SwaggerAuthorizationHeaderAttribute\"/> class.\n        /// </summary>\n        public SwaggerAuthorizationHeaderAttribute() : base(\"Authorization\", true, \"Example: bearer {your token}\")\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Attributes/SwaggerBaseHeaderAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Attributes\n{\n    /// <summary>\n    /// Swagger base parameter attribute class.\n    /// </summary>\n    /// <seealso cref=\"Attribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\n    [ExcludeFromCodeCoverage]\n    public abstract class SwaggerBaseHeaderAttribute : Attribute\n    {\n        /// <summary>\n        /// Gets the name.\n        /// </summary>\n        /// <value>\n        /// The name.\n        /// </value>\n        public string Name { get; }\n\n        /// <summary>\n        /// Gets a value indicating whether this <see cref=\"SwaggerCustomHeaderAttribute\"/> is required.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if required; otherwise, <c>false</c>.\n        /// </value>\n        public bool Required { get; }\n\n        /// <summary>\n        /// Gets the description.\n        /// </summary>\n        /// <value>\n        /// The description.\n        /// </value>\n        public string Description { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SwaggerCustomHeaderAttribute\" /> class.\n        /// </summary>\n        /// <param name=\"name\">The name.</param>\n        /// <param name=\"required\">if set to <c>true</c> [required].</param>\n        /// <param name=\"description\">The description.</param>\n        protected SwaggerBaseHeaderAttribute(string name, bool required = false, string description = \"\")\n        {\n            Name = name;\n            Required = required;\n            Description = description;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Attributes/SwaggerChannelHeaderAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Attributes\n{\n    /// <summary>\n    /// Adds a \"Channel\" header to Swagger methods.\n    /// </summary>\n    /// <seealso cref=\"SwaggerCustomHeaderAttribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\n    [ExcludeFromCodeCoverage]\n    public class SwaggerChannelHeaderAttribute : SwaggerBaseHeaderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SwaggerChannelHeaderAttribute\" /> class.\n        /// </summary>\n        public SwaggerChannelHeaderAttribute() : base(\"Channel\", false, \"Example: ios, android, web. default value: web\")\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Attributes/SwaggerCultureHeaderAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Attributes\n{\n    /// <summary>\n    /// Culture header attribute class.\n    /// </summary>\n    /// <seealso cref=\"SwaggerCustomHeaderAttribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\n    [ExcludeFromCodeCoverage]\n    public class SwaggerCultureHeaderAttribute : SwaggerBaseHeaderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SwaggerCultureHeaderAttribute\"/> class.\n        /// </summary>\n        public SwaggerCultureHeaderAttribute() : base(\"Culture\", false, \"Example: pt-BR, en-US\")\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Attributes/SwaggerCustomHeaderAttribute.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Attributes\n{\n    /// <summary>\n    /// Swagger header base attribute class. Used to populate custom headers in Swagger.\n    /// </summary>\n    /// <seealso cref=\"Attribute\" />\n    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]\n    [ExcludeFromCodeCoverage]\n    public class SwaggerCustomHeaderAttribute : SwaggerBaseHeaderAttribute\n    {\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"SwaggerCustomHeaderAttribute\" /> class.\n        /// </summary>\n        /// <param name=\"name\">The name.</param>\n        /// <param name=\"required\">if set to <c>true</c> [required].</param>\n        /// <param name=\"description\">The description.</param>\n        public SwaggerCustomHeaderAttribute(string name, bool required = false, string description = \"\") : base(name, required, description)\n        {\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Entities/LiquidErrorResponse.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text;\n\nnamespace Liquid.WebApi.Http.Entities\n{\n    /// <summary>\n    /// Properties for response request that throws unexpected error.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidErrorResponse\n    {\n        /// <summary>\n        /// Status code of error.\n        /// </summary>\n        public int StatusCode { get; set; }\n\n        /// <summary>\n        /// Error message.\n        /// </summary>\n        public string Message { get; set; }\n\n        /// <summary>\n        /// Detailed exception.\n        /// </summary>\n        public Exception Detailed { get; set; }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Exceptions/LiquidContextKeysException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.WebApi.Http.Exceptions\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class LiquidContextKeysException : LiquidException\n    {\n        ///<inheritdoc/>\n        public LiquidContextKeysException()\n        {\n        }\n\n        ///<inheritdoc/>\n        public LiquidContextKeysException(string contextKey) : base($\"The value of required context key '{contextKey}' was not found in request.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public LiquidContextKeysException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Exceptions/LiquidScopedKeysException.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Runtime.Serialization;\n\nnamespace Liquid.WebApi.Http.Exceptions\n{\n    ///<inheritdoc/>\n    [ExcludeFromCodeCoverage]\n    [Serializable]\n    public class LiquidScopedtKeysException : LiquidException\n    {\n        ///<inheritdoc/>\n        public LiquidScopedtKeysException()\n        {\n        }\n\n        ///<inheritdoc/>\n        public LiquidScopedtKeysException(string contextKey) : base($\"The value of required logging scoped key '{contextKey}' was not found in request.\")\n        {\n        }\n\n        ///<inheritdoc/>\n        public LiquidScopedtKeysException(string message, Exception innerException) : base(message, innerException)\n        {\n        }\n\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Extensions/DependencyInjection/IApplicationBuilderExtensions.cs",
    "content": "﻿using Liquid.WebApi.Http.Middlewares;\nusing Liquid.WebApi.Http.Settings;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// .Net application builder extensions class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IApplicationBuilderExtensions\n    {\n        /// <summary>\n        /// Adds <see cref=\"LiquidCultureMiddleware\"/> to the application builder.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        public static IApplicationBuilder UseLiquidCulture(this IApplicationBuilder builder)\n        {\n            return builder.UseMiddleware<LiquidCultureMiddleware>();\n        }\n\n        /// <summary>\n        /// Adds <see cref=\"LiquidExceptionMiddleware\"/> to the application builder.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        public static IApplicationBuilder UseLiquidException(this IApplicationBuilder builder)\n        {\n            return builder.UseMiddleware<LiquidExceptionMiddleware>();\n        }\n\n        /// <summary>\n        /// Adds <see cref=\"LiquidContextMiddleware\"/> to the application builder.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        public static IApplicationBuilder UseLiquidContext(this IApplicationBuilder builder)\n        {\n            return builder.UseMiddleware<LiquidContextMiddleware>();\n        }\n\n        /// <summary>\n        /// Adds <see cref=\"LiquidScopedLoggingMiddleware\"/> to the application builder.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        public static IApplicationBuilder UseLiquidScopedLogging(this IApplicationBuilder builder)\n        {\n            return builder.UseMiddleware<LiquidScopedLoggingMiddleware>();\n        }\n\n        /// <summary>\n        /// Register the Swagger middleware with Liquid Configuration settings.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        public static IApplicationBuilder UseLiquidSwagger(this IApplicationBuilder builder)\n        {\n            var configuration = builder.ApplicationServices.GetService<IOptions<SwaggerSettings>>();\n\n            var swaggerSettings = configuration.Value;\n            builder.UseSwagger().UseSwaggerUI(options =>\n            {\n                options.SwaggerEndpoint(swaggerSettings.SwaggerEndpoint.Url, swaggerSettings.SwaggerEndpoint.Name);\n            });\n            return builder;\n        }\n\n        /// <summary>\n        /// Groups the execution of <see cref=\"UseLiquidCulture(IApplicationBuilder)\"/>, \n        /// <see cref=\"UseLiquidScopedLogging(IApplicationBuilder)\"/> , <see cref=\"UseLiquidContext(IApplicationBuilder)\"/>,\n        /// <see cref=\"UseLiquidSwagger(IApplicationBuilder)\"/> and <see cref=\"UseLiquidException(IApplicationBuilder)\"/> \n        /// in this particular order, to add all Liquid functionality to the.net pipeline.\n        /// </summary>\n        /// <param name=\"builder\">Extended application builder.</param>\n        public static IApplicationBuilder UseLiquidConfigure(this IApplicationBuilder builder)\n        {\n            builder.UseLiquidCulture();\n            builder.UseLiquidScopedLogging();\n            builder.UseLiquidContext();\n            builder.UseLiquidSwagger();\n            builder.UseLiquidException();\n\n            return builder;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Extensions/DependencyInjection/IServiceCollectionExtensions.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Core.Extensions;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.WebApi.Http.Filters.Swagger;\nusing Liquid.WebApi.Http.Settings;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing Microsoft.OpenApi.Models;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.IO;\nusing System.Linq;\nusing System.Reflection;\n\nnamespace Liquid.WebApi.Http.Extensions.DependencyInjection\n{\n    /// <summary>\n    /// Startup extension methods. Used to configure the startup application.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class IServiceCollectionExtensions\n    {\n        /// <summary>\n        ///  Registers a <see cref=\"LiquidContext\"/> service and execute registration methods\n        ///  set mapping <see cref=\"IServiceCollectionAutoMapperExtensions.LiquidAddAutoMapper(IServiceCollection, Action{AutoMapper.IMapperConfigurationExpression}, Assembly[])\"/>,\n        ///  register domain handlers <see cref=\"IServiceCollectionCoreExtensions.AddLiquidHandlers(IServiceCollection, bool, bool, Assembly[])\"/>, \n        ///  and swagger <see cref=\"AddLiquidSwagger(IServiceCollection)\"/>\n        /// </summary>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        /// <param name=\"assemblies\">Array of assemblies that the domain handlers are implemented.</param>\n        /// <param name=\"sectionName\">Swagger configuration section name.</param>\n        /// <param name=\"middlewares\">Indicates if middlewares options must be binded.</param>\n        public static IServiceCollection AddLiquidHttp(this IServiceCollection services, string sectionName, bool middlewares = false, params Assembly[] assemblies)\n        {\n            if (middlewares)\n            {\n                services.AddOptions<ScopedContextSettings>()\n                 .Configure<IConfiguration>((settings, configuration) =>\n                 {\n                     configuration.GetSection(sectionName + \":ScopedContext\").Bind(settings);\n                 });\n\n                services.AddOptions<CultureSettings>()\n                 .Configure<IConfiguration>((settings, configuration) =>\n                 {\n                     configuration.GetSection(sectionName + \":Culture\").Bind(settings);\n                 });\n\n                services.AddOptions<ScopedLoggingSettings>()\n                .Configure<IConfiguration>((settings, configuration) =>\n                {\n                    configuration.GetSection(sectionName + \":ScopedLogging\").Bind(settings);\n                });\n            }\n\n            services.AddScoped<ILiquidContext, LiquidContext>();\n            services.AddLiquidSerializers();\n\n            services.AddOptions<SwaggerSettings>()\n            .Configure<IConfiguration>((settings, configuration) =>\n            {\n                configuration.GetSection(sectionName + \":Swagger\").Bind(settings);\n            });\n\n            services.LiquidAddAutoMapper(assemblies);\n            services.AddLiquidHandlers(true, true, assemblies);\n\n            services.AddLiquidSwagger();\n            return services;\n        }\n\n        /// <summary>\n        /// Adds swagger with liquid configuration <see cref=\"SwaggerSettings\"/> and\n        /// filters <see cref=\"AddHeaderParameterFilter\"/>, <see cref=\"DefaultResponseFilter\"/>\n        /// and <see cref=\"OverloadMethodsSameVerb\"/>.\n        /// </summary>\n        /// <param name=\"services\">Extended service collection instance.</param>\n        public static IServiceCollection AddLiquidSwagger(this IServiceCollection services)\n        {\n            var serviceProvider = services.BuildServiceProvider();\n\n            var configuration = serviceProvider.GetService<IOptions<SwaggerSettings>>();\n            if (configuration?.Value == null) throw new LiquidException(\"'swagger' settings does not exist in appsettings.json file. Please check the file.\");\n\n            var swaggerSettings = configuration.Value;\n            services.AddSwaggerGen(options =>\n            {\n                options.SwaggerDoc(swaggerSettings.Name,\n                    new OpenApiInfo\n                    {\n                        Title = swaggerSettings.Title,\n                        Version = swaggerSettings.Version,\n                        Description = swaggerSettings.Description\n                    });\n                options.OperationFilter<AddHeaderParameterFilter>();\n                options.OperationFilter<DefaultResponseFilter>();\n                options.OperationFilter<OverloadMethodsSameVerb>();\n\n                Directory.GetFiles(AppContext.BaseDirectory, \"*.xml\").AsEnumerable().Each(file => options.IncludeXmlComments(file));\n\n                options.CustomSchemaIds(x => x.FullName);\n            });\n            return services;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Extensions/HttpContextExtensions.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing Microsoft.AspNetCore.Http;\n\nnamespace Liquid.WebApi.Http.Extensions\n{\n    /// <summary>\n    /// Http context extensions class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public static class HttpContextExtensions\n    {\n        /// <summary>\n        /// Gets the header value from request.\n        /// </summary>\n        /// <param name=\"context\">The http context.</param>\n        /// <param name=\"key\">The header key.</param>\n        /// <returns>Header value from http request, otherwise <see cref=\"string.Empty\" />.</returns>\n        public static string GetValueFromHeader(this HttpContext context, string key)\n        {\n            IHeaderDictionary headerDictionary = null;\n            if (context != null)\n            {\n                headerDictionary = context.Request?.Headers;\n            }\n            if (headerDictionary == null)\n            {\n                return string.Empty;\n            }\n            var stringValues = headerDictionary.FirstOrDefault(m => string.Equals(m.Key, key, StringComparison.InvariantCultureIgnoreCase)).Value;\n            if (string.IsNullOrEmpty(stringValues))\n            {\n                return string.Empty;\n            }\n            return stringValues;\n        }\n\n        /// <summary>\n        /// Gets the value from querystring.\n        /// </summary>\n        /// <param name=\"context\">The request.</param>\n        /// <param name=\"key\">The key.</param>\n        /// <returns></returns>\n        public static string GetValueFromQuery(this HttpContext context, string key)\n        {\n            var queryCollection = context.Request?.Query;\n\n            if (queryCollection == null)\n                return string.Empty;\n\n            var stringValues = queryCollection.FirstOrDefault(m => string.Equals(m.Key, key, StringComparison.InvariantCultureIgnoreCase)).Value;\n\n            if (string.IsNullOrEmpty(stringValues)) \n                return string.Empty;\n\n            return stringValues;\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Filters/Swagger/AddHeaderParameterFilter.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Reflection;\nusing Liquid.WebApi.Http.Attributes;\nusing Microsoft.OpenApi.Models;\nusing Swashbuckle.AspNetCore.SwaggerGen;\n\nnamespace Liquid.WebApi.Http.Filters.Swagger\n{\n    /// <summary>\n    /// Adds headers to swagger document if the action has custom swagger attributes.\n    /// </summary>\n    /// <seealso cref=\"IOperationFilter\" />\n    [ExcludeFromCodeCoverage]\n    internal class AddHeaderParameterFilter : IOperationFilter\n    {\n        /// <summary>\n        /// Applies the specified operation.\n        /// </summary>\n        /// <param name=\"operation\">The operation.</param>\n        /// <param name=\"context\">The context.</param>\n        public void Apply(OpenApiOperation operation, OperationFilterContext context)\n        {\n            if (!context.ApiDescription.TryGetMethodInfo(out var methodInfo)) return;\n\n            var controllerAttributes = methodInfo?.DeclaringType?.GetCustomAttributes<SwaggerBaseHeaderAttribute>().ToList();\n            var actionAttributes = methodInfo?.GetCustomAttributes<SwaggerBaseHeaderAttribute>().ToList();\n            controllerAttributes?.AddRange(actionAttributes);\n\n            var swaggerAttributes = controllerAttributes?.Distinct();\n\n            if (swaggerAttributes == null) return;\n\n\n            foreach (var swaggerAttribute in swaggerAttributes)\n            {\n                if (operation.Parameters == null) { operation.Parameters = new List<OpenApiParameter>(); }\n\n                if (!operation.Parameters.Any(p => p.Name.Equals(swaggerAttribute.Name, StringComparison.InvariantCultureIgnoreCase)))\n                {\n                    operation.Parameters.Add(new OpenApiParameter\n                    {\n                        Name = swaggerAttribute.Name,\n                        In = ParameterLocation.Header,\n                        Required = swaggerAttribute.Required,\n                        Description = swaggerAttribute.Description\n                    });\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Filters/Swagger/DefaultResponseFilter.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing Microsoft.OpenApi.Models;\nusing Swashbuckle.AspNetCore.SwaggerGen;\n\nnamespace Liquid.WebApi.Http.Filters.Swagger\n{\n    /// <summary>\n    /// Sets the default responses for each action call.\n    /// </summary>\n    /// <seealso cref=\"IOperationFilter\" />\n    [ExcludeFromCodeCoverage]\n    internal sealed class DefaultResponseFilter : IOperationFilter\n    {\n        /// <summary>\n        /// Adds the defaults headers to all responses.\n        /// </summary>\n        /// <param name=\"operation\">The operation.</param>\n        /// <param name=\"context\">The context.</param>\n        public void Apply(OpenApiOperation operation, OperationFilterContext context)\n        {\n            operation.Responses.Add(\"400\", new OpenApiResponse { Description = \"The request is invalid.\" });\n            operation.Responses.Add(\"404\", new OpenApiResponse { Description = \"Resource not found.\" });\n            operation.Responses.Add(\"500\", new OpenApiResponse { Description = \"An internal server error has occurred.\" });\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Filters/Swagger/DocumentSortFilter.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing Liquid.Core.Extensions;\nusing Liquid.Core.Utils;\nusing Microsoft.OpenApi.Models;\nusing Swashbuckle.AspNetCore.SwaggerGen;\n\nnamespace Liquid.WebApi.Http.Filters.Swagger\n{\n    /// <summary>\n    /// The Swagger document custom sort filter class.\n    /// </summary>\n    /// <seealso cref=\"IDocumentFilter\" />\n    [ExcludeFromCodeCoverage]\n    internal sealed class DocumentSortFilter : IDocumentFilter\n    {\n        /// <summary>\n        /// Applies the specified swagger document.\n        /// </summary>\n        /// <param name=\"swaggerDoc\">The swagger document.</param>\n        /// <param name=\"context\">The context.</param>\n        public void Apply(OpenApiDocument swaggerDoc, DocumentFilterContext context)\n        {\n            var paths = swaggerDoc.Paths.OrderBy(e => e.Key);\n            swaggerDoc.Paths = new OpenApiPaths();\n            paths.AsEnumerable().Each(path => swaggerDoc.Paths.Add(path.Key, path.Value));\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Filters/Swagger/OverloadMethodsSameVerb.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Linq;\nusing System.Text;\nusing Liquid.Core.Extensions;\nusing Liquid.Core.Utils;\nusing Microsoft.OpenApi.Models;\nusing Swashbuckle.AspNetCore.SwaggerGen;\n\nnamespace Liquid.WebApi.Http.Filters.Swagger\n{\n    /// <summary>\n    /// Adds the parameters to the method to avoid same method name.\n    /// </summary>\n    /// <seealso cref=\"IOperationFilter\" />\n    [ExcludeFromCodeCoverage]\n    internal sealed class OverloadMethodsSameVerb : IOperationFilter\n    {\n        /// <summary>\n        /// Changes the verbs by concatenating the parameters and verbs.\n        /// </summary>\n        /// <param name=\"operation\">The operation.</param>\n        /// <param name=\"context\">The context.</param>\n        public void Apply(OpenApiOperation operation, OperationFilterContext context)\n        {\n            if (operation.Parameters == null) return;\n\n            var builder = new StringBuilder($\"{context?.ApiDescription?.HttpMethod}_{context?.MethodInfo.Name}_{context?.ApiDescription?.RelativePath?.Replace(\"/\", \"_\")}_{operation.OperationId}By\");\n            operation.Parameters.AsEnumerable().Each(parameter => builder.Append(CultureInfo.CurrentCulture.TextInfo.ToTitleCase(parameter.Name)));\n            operation.OperationId = builder.ToString();\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Implementations/LiquidControllerBase.cs",
    "content": "﻿using MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.Controllers\n{\n    /// <summary>\n    /// Base Controller Class.\n    /// </summary>\n    /// <seealso cref=\"ControllerBase\" />\n    public abstract class LiquidControllerBase : ControllerBase\n    {\n        /// <summary>\n        /// Gets or sets the mediator service.\n        /// </summary>\n        /// <value>\n        /// The mediator service.\n        /// </value>\n        [ExcludeFromCodeCoverage]\n        protected IMediator Mediator { get; }\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidControllerBase\" /> class.\n        /// </summary>\n        /// <param name=\"mediator\">The mediator service.</param>\n        protected LiquidControllerBase(IMediator mediator)\n        {\n            Mediator = mediator ?? throw new ArgumentNullException(nameof(mediator));\n        }\n        \n\n        /// <summary>\n        /// Executes the action <see cref=\"Mediator.Send{TResponse}(IRequest{TResponse}, System.Threading.CancellationToken)\"/>.\n        /// </summary>\n        /// <param name=\"request\">The request command or query.</param>\n        protected virtual async Task<TResponse> ExecuteAsync<TResponse>(IRequest<TResponse> request)\n        {\n            return await Mediator.Send(request);\n        }\n\n        /// <summary>\n        /// Executes the action and returns the response using a custom http response code.\n        /// </summary>\n        /// <typeparam name=\"TRequest\">The type of the request.</typeparam>\n        /// <param name=\"request\">The request command or query.</param>\n        /// <param name=\"responseCode\">The http response code.</param>\n        protected virtual async Task<IActionResult> ExecuteAsync<TRequest>(IRequest<TRequest> request, HttpStatusCode responseCode)\n        {\n            var response =  await Mediator.Send(request);\n\n            return StatusCode((int)responseCode, response);\n        }  \n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Implementations/LiquidNotificationHelper.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.WebApi.Http.Interfaces;\nusing System;\n\nnamespace Liquid.WebApi.Http.Implementations\n{\n    ///<inheritdoc/>\n    public class LiquidNotificationHelper : ILiquidNotificationHelper\n    {\n        private readonly ILiquidContextNotifications _contextNotifications;\n\n        /// <summary>\n        /// Inicialize a new instace of <see cref=\"LiquidNotificationHelper\"/>\n        /// </summary>\n        /// <param name=\"contextNotifications\"></param>\n        public LiquidNotificationHelper(ILiquidContextNotifications contextNotifications)\n        {\n            _contextNotifications = contextNotifications ?? throw new ArgumentNullException(nameof(contextNotifications));\n        }\n        \n        ///<inheritdoc/>\n        public object IncludeMessages<TResponse>(TResponse response)\n        {\n            var messages = _contextNotifications.GetNotifications();\n\n            if (messages is null)\n                return response;\n\n            return new { response, messages };\n\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Interfaces/ILiquidNotificationHelper.cs",
    "content": "﻿namespace Liquid.WebApi.Http.Interfaces\n{\n    /// <summary>\n    /// Abstracts the management of context notifications.\n    /// </summary>\n    public interface ILiquidNotificationHelper\n    {\n        /// <summary>\n        /// Add context notification messages to the response object.\n        /// </summary>\n        /// <typeparam name=\"TResponse\">Type of response object obtained upon return of a request.</typeparam>\n        /// <param name=\"response\">Object obtained upon return of a request.</param>\n        object IncludeMessages<TResponse>(TResponse response);\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Liquid.WebApi.Http.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <PackageId>Liquid.WebApi.Http</PackageId>\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade 2019</Copyright>\n    <PackageProjectUrl>https://github.com/Avanade/Liquid-Application-Framework</PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Version>8.0.0</Version>\n    <GenerateDocumentationFile>true</GenerateDocumentationFile>\n    <IsPackable>true</IsPackable>\n    <DebugType>Full</DebugType>\n    <ProjectGuid>{25D05D84-4DFB-4F3D-92A2-B06DFA244BA4}</ProjectGuid>\n    <Description>\n      The Liquid.WebApi.Http contains modules and functionalities to provide a better way to configure and use a web api project using asp.net core 3.1.\n      This components already register some dependencies, sets custom middlewares, configure swagger and so on.\n      This component is part of Liquid Application Framework.\n    </Description>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Swashbuckle.AspNetCore\" Version=\"8.1.1\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Middlewares/LiquidContextMiddleware.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.WebApi.Http.Exceptions;\nusing Liquid.WebApi.Http.Extensions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Options;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.Middlewares\n{\n    /// <summary>\n    /// Inserts configured context keys in LiquidContext service.\n    /// Includes its behavior in netcore pipelines before request execution.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidContextMiddleware\n    {\n        private readonly RequestDelegate _next;\n        private readonly IOptions<ScopedContextSettings> _options;\n\n        /// <summary>\n        /// Initialize a instance of <see cref=\"LiquidContextMiddleware\"/>\n        /// </summary>\n        /// <param name=\"next\">Invoked request.</param>\n        /// <param name=\"options\">Context keys configuration.</param>\n        public LiquidContextMiddleware(RequestDelegate next, IOptions<ScopedContextSettings> options)\n        {\n            _next = next;\n            _options = options;\n        }\n\n        /// <summary>\n        /// Obtains the value of configured keys from HttpContext and inserts them in LiquidContext service.\n        /// Includes its behavior in netcore pipelines before request execution.\n        /// </summary>\n        /// <param name=\"context\">HTTP-specific information about an individual HTTP request.</param>\n        public async Task InvokeAsync(HttpContext context)\n        {\n\n            ILiquidContext liquidContext = context.RequestServices.GetRequiredService<ILiquidContext>();\n\n            var value = string.Empty;\n\n            foreach (var key in _options.Value.Keys)\n            {\n                value = context.GetValueFromHeader(key.KeyName);\n\n                if (string.IsNullOrEmpty(value))\n                    value = context.GetValueFromQuery(key.KeyName);\n\n                if (string.IsNullOrEmpty(value) && key.Required)\n                    throw new LiquidContextKeysException(key.KeyName);\n\n                liquidContext.Upsert(key.KeyName, value);\n            }\n\n            if (_options.Value.Culture)\n            {\n                liquidContext.Upsert(\"culture\", CultureInfo.CurrentCulture.Name);\n            }\n\n            await _next(context);\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Middlewares/LiquidCultureMiddleware.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.WebApi.Http.Extensions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Options;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Globalization;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.Middlewares\n{\n    /// <summary>\n    /// Configures the culture in the current thread.\n    /// Includes its behavior in netcore pipelines before request execution.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public sealed class LiquidCultureMiddleware\n    {\n        private const string _culture = \"culture\";\n        private readonly IOptions<CultureSettings> _options;\n        private readonly RequestDelegate _next;\n\n        /// <summary>\n        /// Initializes a new instance of the <see cref=\"LiquidCultureMiddleware\" /> class.\n        /// </summary>\n        /// <param name=\"next\">The next.</param>\n        /// <param name=\"options\"></param>\n        public LiquidCultureMiddleware(RequestDelegate next, IOptions<CultureSettings> options)\n        {\n            _next = next;\n            _options = options;\n        }\n\n        /// <summary>\n        /// Configures the culture in the current thread as set on request or in appsettings, prioritizing request informations.\n        /// Includes its behavior in netcore pipelines before request execution.\n        /// </summary>\n        /// <param name=\"context\">HTTP-specific information about an individual HTTP request.</param>\n        public async Task InvokeAsync(HttpContext context)\n        {\n            var cultureCode = context.GetValueFromHeader(_culture).ToString();\n\n            if (string.IsNullOrEmpty(cultureCode))\n            {\n                cultureCode = context.GetValueFromQuery(_culture).ToString();\n            }\n\n            if (string.IsNullOrEmpty(cultureCode) && !string.IsNullOrEmpty(_options.Value.DefaultCulture))\n            {\n                cultureCode = _options.Value.DefaultCulture;\n            }\n\n            if (!string.IsNullOrEmpty(cultureCode))\n            {\n                CultureInfo.CurrentCulture = new CultureInfo(cultureCode);\n                CultureInfo.CurrentUICulture = new CultureInfo(cultureCode);\n            }\n\n            await _next(context);\n        }\n    }\n}"
  },
  {
    "path": "src/Liquid.WebApi.Http/Middlewares/LiquidExceptionMiddleware.cs",
    "content": "﻿using FluentValidation;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.WebApi.Http.Entities;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.Middlewares\n{\n    /// <summary>\n    /// Generates a log and serialize a formated Json response object for generic exceptions.\n    /// Includes its behavior in netcore pipelines after request execution when thows error.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidExceptionMiddleware\n    {\n        private readonly ILogger<LiquidExceptionMiddleware> _logger;\n        private readonly RequestDelegate _next;\n        private readonly ILiquidSerializerProvider _serializerProvider;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidExceptionMiddleware\"/>\n        /// </summary>\n        /// <param name=\"logger\"></param>\n        /// <param name=\"serializerProvider\"></param>\n        /// <param name=\"next\"></param>\n        public LiquidExceptionMiddleware(RequestDelegate next\n            , ILogger<LiquidExceptionMiddleware> logger\n            , ILiquidSerializerProvider serializerProvider)\n        {\n            _logger = logger;\n            _next = next;\n            _serializerProvider = serializerProvider;\n        }\n\n        /// <summary>\n        /// Generates a log and serialize a formated Json response object for exceptions.\n        /// Includes its behavior in netcore pipelines after request execution when thows error.\n        /// </summary>\n        /// <param name=\"context\">HTTP-specific information about an individual HTTP request.</param>\n        /// <returns></returns>\n        public async Task InvokeAsync(HttpContext context)\n        {\n            try\n            {\n                await _next(context);\n            }\n            catch (ValidationException ex)\n            {\n                _logger.LogError(ex, $\"Liquid request validation error: {ex}\");\n                await HandleExceptionAsync(context, ex, HttpStatusCode.BadRequest);\n            }\n            catch (Exception ex)\n            {\n                _logger.LogError(ex, $\"Unexpected error: {ex}\");\n                await HandleExceptionAsync(context, ex, HttpStatusCode.InternalServerError);\n            }\n        }\n\n        private Task HandleExceptionAsync(HttpContext context, Exception exception, HttpStatusCode statusCode)\n        {\n            context.Response.ContentType = context.Request.ContentType;\n\n            context.Response.StatusCode = (int)statusCode;\n\n            var response = new LiquidErrorResponse()\n            {\n                StatusCode = context.Response.StatusCode,\n                Message = \"An error occurred whilst processing your request.\",\n                Detailed = exception\n            };\n\n            var serializer = GetSerializer(context.Request.ContentType);\n\n            return context.Response.WriteAsync(serializer.Serialize(response));\n        }\n\n        private ILiquidSerializer GetSerializer(string contentType)\n        {\n            ILiquidSerializer serializer;\n\n            switch (contentType)\n            {\n                case \"application/json\":\n                    serializer = _serializerProvider.GetSerializerByType(typeof(LiquidJsonSerializer));\n                    break;\n                case \"application/xml\":\n                    serializer = _serializerProvider.GetSerializerByType(typeof(LiquidXmlSerializer));\n                    break;\n                default:\n                    serializer = _serializerProvider.GetSerializerByType(typeof(LiquidJsonSerializer));\n                    break;\n            }\n\n            return serializer;\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Middlewares/LiquidScopedLoggingMiddleware.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.WebApi.Http.Exceptions;\nusing Liquid.WebApi.Http.Extensions;\nusing Microsoft.AspNetCore.Http;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.Middlewares\n{\n    /// <summary>\n    /// Inserts configured context keys in ILogger service scope.\n    /// Includes its behavior in netcore pipelines before request execution.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class LiquidScopedLoggingMiddleware\n    {\n        private readonly RequestDelegate _next;\n        private readonly ILogger<LiquidScopedLoggingMiddleware> _logger;\n        private readonly IOptions<ScopedLoggingSettings> _options;\n\n        /// <summary>\n        /// Initialize a new instance of <see cref=\"LiquidScopedLoggingMiddleware\"/>\n        /// </summary>\n        /// <param name=\"next\">Invoked request.</param>\n        /// <param name=\"logger\">Logger service instance.</param>\n        /// <param name=\"options\">Context keys set.</param>\n        public LiquidScopedLoggingMiddleware(RequestDelegate next, ILogger<LiquidScopedLoggingMiddleware> logger, IOptions<ScopedLoggingSettings> options)\n        {\n            _next = next;\n            _logger = logger;\n            _options = options;\n        }\n\n        /// <summary>\n        /// Obtains the value of configured keys from HttpContext and inserts them in ILogger service scope.\n        /// Includes its behavior in netcore pipelines before request execution.\n        /// </summary>\n        /// <param name=\"context\">HTTP-specific information about an individual HTTP request.</param>\n        public async Task InvokeAsync(HttpContext context)\n        {\n            var scope = new List<KeyValuePair<string, object>>();            \n\n            foreach (var key in _options.Value.Keys)\n            {\n                var value = context.GetValueFromHeader(key.KeyName);\n\n                if (string.IsNullOrEmpty(value))\n                    value = context.GetValueFromQuery(key.KeyName);\n\n                if (string.IsNullOrEmpty(value) && key.Required)\n                    throw new LiquidScopedtKeysException(key.KeyName);\n\n                scope.Add(new KeyValuePair<string, object>(key.KeyName, value));\n            }\n\n            using (_logger.BeginScope(scope.ToArray()))\n            {\n                await _next(context);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "src/Liquid.WebApi.Http/Settings/SwaggerSettings.cs",
    "content": "﻿using Liquid.Core.Attributes;\nusing System.Text.Json.Serialization;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.Settings\n{\n    /// <summary>\n    /// Swagger Configuration Settings Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    [LiquidSectionName(\"liquid:swagger\")]\n    public class SwaggerSettings\n    {\n        /// <summary>\n        /// Gets or sets the name.\n        /// </summary>\n        /// <value>\n        /// The name.\n        /// </value>\n        [JsonPropertyName(\"name\")]\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the host.\n        /// </summary>\n        /// <value>\n        /// The host.\n        /// </value>\n        [JsonPropertyName(\"host\")]\n        public string Host { get; set; }\n\n        /// <summary>\n        /// Gets or sets schemes.\n        /// </summary>\n        /// <value>\n        /// Schemes.\n        /// </value>\n        [JsonPropertyName(\"schemes\")]\n        public string[] Schemes { get; set; }\n\n        /// <summary>\n        /// Gets or sets the title.\n        /// </summary>\n        /// <value>\n        /// The title.\n        /// </value>\n        [JsonPropertyName(\"title\")]\n        public string Title { get; set; }\n\n        /// <summary>\n        /// Gets or sets the version.\n        /// </summary>\n        /// <value>\n        /// The version.\n        /// </value>\n        [JsonPropertyName(\"version\")]\n        public string Version { get; set; }\n\n        /// <summary>\n        /// Gets or sets the description.\n        /// </summary>\n        /// <value>\n        /// The description.\n        /// </value>\n        [JsonPropertyName(\"description\")]\n        public string Description { get; set; }\n\n        /// <summary>\n        /// Gets or sets the swagger endpoint.\n        /// </summary>\n        /// <value>\n        /// The swagger endpoint.\n        /// </value>\n        [JsonPropertyName(\"endpoint\")]\n        public SwaggerEndpoint SwaggerEndpoint { get; set; }\n    }\n\n    /// <summary>\n    /// Swagger Endpoint Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class SwaggerEndpoint\n    {\n        /// <summary>\n        /// Gets or sets the URL.\n        /// </summary>\n        /// <value>\n        /// The URL.\n        /// </value>\n        [JsonPropertyName(\"url\")]\n        public string Url { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name.\n        /// </summary>\n        /// <value>\n        /// The name.\n        /// </value>\n        [JsonPropertyName(\"name\")]\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "templates/Liquid.Templates.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.32106.194\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"Liquid.Templates\", \"src\\Liquid.Templates\\Liquid.Templates.csproj\", \"{7320B7F9-FC40-4636-AC7B-DF23D295875F}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{7320B7F9-FC40-4636-AC7B-DF23D295875F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{7320B7F9-FC40-4636-AC7B-DF23D295875F}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{7320B7F9-FC40-4636-AC7B-DF23D295875F}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{7320B7F9-FC40-4636-AC7B-DF23D295875F}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {127F401F-B8DD-4005-B309-6FB8D52B9752}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Liquid.Templates.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <PackageType>Template</PackageType>\n    <PackageVersion>8.0.0-beta-01</PackageVersion>\n    <PackageId>Liquid.Templates</PackageId>\n    <Title>Liquid Templates</Title>\n   <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Authors>Avanade Brazil</Authors>\n    <Company>Avanade Brazil Inc.</Company>\n    <Product>Liquid - Modern Application Framework</Product>\n    <Copyright>Avanade</Copyright>\n    <PackageProjectUrl></PackageProjectUrl>\n    <PackageIcon>logo.png</PackageIcon>\n    <Description>Templates to create an application by using Liquid Application Framework.</Description>\n    <PackageTags>dotnet-new;templates</PackageTags>\n    <TargetFramework>netstandard2.1</TargetFramework>\n\n    <IncludeContentInPack>true</IncludeContentInPack>\n    <IncludeBuildOutput>false</IncludeBuildOutput>\n    <ContentTargetFolders>content</ContentTargetFolders>\n    <PackageIcon>logo.png</PackageIcon>\n    <PackageIconUrl />\n    <PackageLicenseExpression>MIT</PackageLicenseExpression>\n    <Company>Avanade Inc.</Company>\n    <Product>Liquid Application Framework</Product>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Content Include=\"Templates\\**\\*\" Exclude=\"Templates\\**\\bin\\**;Templates\\**\\obj\\**\" />\n    <Compile Remove=\"**\\*\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\">\n      <Pack>True</Pack>\n      <PackagePath></PackagePath>\n    </None>\n  </ItemGroup>\n\n</Project>"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Web\", \"ASP.NET\" ],\n  \"identity\": \"Liquid.Crud.AddEntity\",\n  \"name\": \"Liquid entity class, CRUD mediator handlers and CRUD controller\",\n  \"shortName\": \"liquidcrudaddentity\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Entities/ENTITYNAME.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\n\nnamespace PROJECTNAME.Domain.Entities\n{\n    public class ENTITYNAME : LiquidEntity<ENTITYIDTYPE>\n    {\n        //TODO: declare entity properties.\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/CreateENTITYNAME/CreateENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class CreateENTITYNAMEHandler : IRequestHandler<CreateENTITYNAMERequest>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public CreateENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        public async Task Handle(CreateENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            await _repository.AddAsync(request.Body);\n        }\n\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/CreateENTITYNAME/CreateENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class CreateENTITYNAMERequest : IRequest\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public CreateENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/CreateENTITYNAME/CreateENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class CreateENTITYNAMEValidator : AbstractValidator<CreateENTITYNAMERequest>\n    {\n        public CreateENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/ListENTITYNAME/ListENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ListENTITYNAMEHandler : IRequestHandler<ListENTITYNAMERequest, ListENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public ListENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>        \n        public async Task<ListENTITYNAMEResponse> Handle(ListENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindAllAsync();\n\n            return new ListENTITYNAMEResponse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/ListENTITYNAME/ListENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ListENTITYNAMERequest : IRequest<ListENTITYNAMEResponse>\n    {\n        public ListENTITYNAMERequest()\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/ListENTITYNAME/ListENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\nusing System.Collections.Generic;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ListENTITYNAMEResponse\n    {\n        public IEnumerable<ENTITYNAME> Data { get; set; }\n\n        public ListENTITYNAMEResponse(IEnumerable<ENTITYNAME> data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/ReadENTITYNAME/ReadENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ReadENTITYNAMEHandler : IRequestHandler<ReadENTITYNAMERequest, ReadENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public ReadENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>        \n        public async Task<ReadENTITYNAMEResponse> Handle(ReadENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindByIdAsync(request.Id);\n\n            return new ReadENTITYNAMEResponse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/ReadENTITYNAME/ReadENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ReadENTITYNAMERequest : IRequest<ReadENTITYNAMEResponse>\n    {\n        public ENTITYIDTYPE Id { get; set; }\n\n        public ReadENTITYNAMERequest(ENTITYIDTYPE id)\n        {\n            Id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/ReadENTITYNAME/ReadENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ReadENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public ReadENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/RemoveENTITYNAME/RemoveENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class RemoveENTITYNAMEHandler : IRequestHandler<RemoveENTITYNAMERequest, RemoveENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public RemoveENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>        \n        public async Task<RemoveENTITYNAMEResponse> Handle(RemoveENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindByIdAsync(request.Id);\n\n            if (data != null)\n            {\n                await _repository.RemoveByIdAsync(request.Id);\n                //await _mediator.Publish(new GenericEntityRemovedNotification<TEntity, TIdentifier>(entity));\n            }\n\n            return new RemoveENTITYNAMEResponse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/RemoveENTITYNAME/RemoveENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class RemoveENTITYNAMERequest : IRequest<RemoveENTITYNAMEResponse>\n    {\n        public ENTITYIDTYPE Id { get; set; }\n\n        public RemoveENTITYNAMERequest(ENTITYIDTYPE id)\n        {\n            Id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/RemoveENTITYNAME/RemoveENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class RemoveENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public RemoveENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMEHandler : IRequestHandler<UpdateENTITYNAMERequest, UpdateENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public UpdateENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<UpdateENTITYNAMEResponse> Handle(UpdateENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindByIdAsync(request.Body.Id);\n\n            if (data != null)\n            {\n                await _repository.UpdateAsync(request.Body);\n            }\n\n            return new UpdateENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMERequest : IRequest<UpdateENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public UpdateENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public UpdateENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMEValidator : AbstractValidator<UpdateENTITYNAMERequest>\n    {\n        public UpdateENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.AddEntity/PROJECTNAME.WebApi/Controllers/ENTITYNAMEController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing PROJECTNAME.Domain.Entities;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing System;\nusing PROJECTNAME.Domain.Handlers;\n\nnamespace PROJECTNAME.WebApi.Controllers\n{\n    [ApiController]\n    [Route(\"api/[controller]\")]\n    public class ENTITYNAMEController : LiquidControllerBase\n    {\n        public ENTITYNAMEController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        [HttpGet(\"{id}\")]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n\n        public async Task<IActionResult> GetById([FromRoute] ENTITYIDTYPE id)\n        {\n            var response = await ExecuteAsync(new ReadENTITYNAMERequest(id));\n\n            if (response.Data == null) return NotFound();\n\n            return Ok(response.Data);\n        }\n\n        [HttpGet]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> Get()\n        {\n            var response = await ExecuteAsync(new ListENTITYNAMERequest());\n\n            if (response.Data == null) return NotFound();\n\n            return Ok(response.Data);\n        }\n\n        [HttpPost]\n        [ProducesResponseType(StatusCodes.Status201Created)]\n        public async Task<IActionResult> Post([FromBody] ENTITYNAME entity)\n        {\n            await Mediator.Send(new CreateENTITYNAMERequest(entity));\n\n            return CreatedAtAction(nameof(GetById), new { id = entity.Id }, entity);\n        }\n\n        [HttpPut]\n        [ProducesResponseType(StatusCodes.Status204NoContent)]\n        public async Task<IActionResult> Put([FromBody] ENTITYNAME entity)\n        {\n            var response = await ExecuteAsync(new UpdateENTITYNAMERequest(entity));\n\n            if (response.Data == null) return NotFound();\n\n            return NoContent();\n        }\n\n        [HttpDelete(\"{id}\")]\n        [ProducesResponseType(StatusCodes.Status204NoContent)]\n        public async Task<IActionResult> Delete([FromRoute] ENTITYIDTYPE id)\n        {\n            var response = await ExecuteAsync(new RemoveENTITYNAMERequest(id));\n\n            if (response.Data == null) return NotFound();\n\n            return NoContent();\n        }\n    }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"WebApi\", \"Solution\" ],\n  \"identity\": \"Liquid.Crud.Solution\",\n  \"name\": \"Liquid WebAPI CRUD Solution (Domain and WebAPI projects)\",\n  \"shortName\": \"liquidcrudsolution\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Entities/ENTITYNAME.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\n\nnamespace PROJECTNAME.Domain.Entities\n{\n    public class ENTITYNAME : LiquidEntity<ENTITYIDTYPE>\n    {\n        //TODO: declare entity properties.\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/CreateENTITYNAME/CreateENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class CreateENTITYNAMEHandler : IRequestHandler<CreateENTITYNAMERequest>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public CreateENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        public async Task Handle(CreateENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            await _repository.AddAsync(request.Body);\n        }\n\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/CreateENTITYNAME/CreateENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class CreateENTITYNAMERequest : IRequest\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public CreateENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/CreateENTITYNAME/CreateENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class CreateENTITYNAMEValidator : AbstractValidator<CreateENTITYNAMERequest>\n    {\n        public CreateENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/ListENTITYNAME/ListENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ListENTITYNAMEHandler : IRequestHandler<ListENTITYNAMERequest, ListENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public ListENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>        \n        public async Task<ListENTITYNAMEResponse> Handle(ListENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindAllAsync();\n\n            return new ListENTITYNAMEResponse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/ListENTITYNAME/ListENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ListENTITYNAMERequest : IRequest<ListENTITYNAMEResponse>\n    {\n        public ListENTITYNAMERequest()\n        {\n\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/ListENTITYNAME/ListENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\nusing System.Collections.Generic;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ListENTITYNAMEResponse\n    {\n        public IEnumerable<ENTITYNAME> Data { get; set; }\n\n        public ListENTITYNAMEResponse(IEnumerable<ENTITYNAME> data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/ReadENTITYNAME/ReadENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ReadENTITYNAMEHandler : IRequestHandler<ReadENTITYNAMERequest, ReadENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public ReadENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>        \n        public async Task<ReadENTITYNAMEResponse> Handle(ReadENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindByIdAsync(request.Id);\n\n            return new ReadENTITYNAMEResponse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/ReadENTITYNAME/ReadENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ReadENTITYNAMERequest : IRequest<ReadENTITYNAMEResponse>\n    {\n        public ENTITYIDTYPE Id { get; set; }\n\n        public ReadENTITYNAMERequest(ENTITYIDTYPE id)\n        {\n            Id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/ReadENTITYNAME/ReadENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class ReadENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public ReadENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/RemoveENTITYNAME/RemoveENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class RemoveENTITYNAMEHandler : IRequestHandler<RemoveENTITYNAMERequest, RemoveENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public RemoveENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n        ///<inheritdoc/>        \n        public async Task<RemoveENTITYNAMEResponse> Handle(RemoveENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindByIdAsync(request.Id);\n\n            if (data != null)\n            {\n                await _repository.RemoveByIdAsync(request.Id);\n                //await _mediator.Publish(new GenericEntityRemovedNotification<TEntity, TIdentifier>(entity));\n            }\n\n            return new RemoveENTITYNAMEResponse(data);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/RemoveENTITYNAME/RemoveENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class RemoveENTITYNAMERequest : IRequest<RemoveENTITYNAMEResponse>\n    {\n        public ENTITYIDTYPE Id { get; set; }\n\n        public RemoveENTITYNAMERequest(ENTITYIDTYPE id)\n        {\n            Id = id;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/RemoveENTITYNAME/RemoveENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class RemoveENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public RemoveENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMEHandler : IRequestHandler<UpdateENTITYNAMERequest, UpdateENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public UpdateENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<UpdateENTITYNAMEResponse> Handle(UpdateENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            var data = await _repository.FindByIdAsync(request.Body.Id);\n\n            if (data != null)\n            {\n                await _repository.UpdateAsync(request.Body);\n            }\n\n            return new UpdateENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMERequest : IRequest<UpdateENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public UpdateENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public UpdateENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/Handlers/UpdateENTITYNAME/UpdateENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class UpdateENTITYNAMEValidator : AbstractValidator<UpdateENTITYNAMERequest>\n    {\n        public UpdateENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/IDomainInjection.cs",
    "content": "﻿namespace PROJECTNAME.Domain\n{\n    public interface IDomainInjection\n    {\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Domain/PROJECTNAME.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0-alpha-05\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.Microservice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.8.34408.163\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"PROJECTNAME.Domain\", \"PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\", \"{31F60967-56CC-4B1C-B79F-620DD7DD7031}\"\nEndProject\nProject(\"{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}\") = \"PROJECTNAME.WebApi\", \"PROJECTNAME.WebApi\\PROJECTNAME.WebApi.csproj\", \"{11436432-DC12-4D60-8A84-848A3DC65967}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{31F60967-56CC-4B1C-B79F-620DD7DD7031}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{31F60967-56CC-4B1C-B79F-620DD7DD7031}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{31F60967-56CC-4B1C-B79F-620DD7DD7031}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{31F60967-56CC-4B1C-B79F-620DD7DD7031}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{11436432-DC12-4D60-8A84-848A3DC65967}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{11436432-DC12-4D60-8A84-848A3DC65967}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{11436432-DC12-4D60-8A84-848A3DC65967}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{11436432-DC12-4D60-8A84-848A3DC65967}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {5F34B1DC-5775-449B-8CEC-CBA30C2AB958}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.WebApi/Controllers/ENTITYNAMEController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing PROJECTNAME.Domain.Entities;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing System;\nusing PROJECTNAME.Domain.Handlers;\n\nnamespace PROJECTNAME.WebApi.Controllers\n{\n    [ApiController]\n    [Route(\"api/[controller]\")]\n    public class ENTITYNAMEController : LiquidControllerBase\n    {\n        public ENTITYNAMEController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        [HttpGet(\"{id}\")]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n\n        public async Task<IActionResult> GetById([FromRoute] ENTITYIDTYPE id)\n        {\n            var response = await ExecuteAsync(new ReadENTITYNAMERequest(id));\n\n            if (response.Data == null) return NotFound();\n\n            return Ok(response.Data);\n        }\n\n        [HttpGet]\n        [ProducesResponseType(StatusCodes.Status200OK)]\n        public async Task<IActionResult> Get()\n        {\n            var response = await ExecuteAsync(new ListENTITYNAMERequest());\n\n            if (response.Data == null) return NotFound();\n\n            return Ok(response.Data);\n        }\n\n        [HttpPost]\n        [ProducesResponseType(StatusCodes.Status201Created)]\n        public async Task<IActionResult> Post([FromBody] ENTITYNAME entity)\n        {\n            await Mediator.Send(new CreateENTITYNAMERequest(entity));\n\n            return CreatedAtAction(nameof(GetById), new { id = entity.Id }, entity);\n        }\n\n        [HttpPut]\n        [ProducesResponseType(StatusCodes.Status204NoContent)]\n        public async Task<IActionResult> Put([FromBody] ENTITYNAME entity)\n        {\n            var response = await ExecuteAsync(new UpdateENTITYNAMERequest(entity));\n\n            if (response.Data == null) return NotFound();\n\n            return NoContent();\n        }\n\n        [HttpDelete(\"{id}\")]\n        [ProducesResponseType(StatusCodes.Status204NoContent)]\n        public async Task<IActionResult> Delete([FromRoute] ENTITYIDTYPE id)\n        {\n            var response = await ExecuteAsync(new RemoveENTITYNAMERequest(id));\n\n            if (response.Data == null) return NotFound();\n\n            return NoContent();\n        }\n    }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.WebApi/PROJECTNAME.WebApi.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <InvariantGlobalization>true</InvariantGlobalization>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.WebApi.Http\" Version=\"8.0.0-alpha-02\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.WebApi/PROJECTNAME.WebApi.http",
    "content": "@PROJECTNAME.WebApi_HostAddress = http://localhost:5003\n\nGET {{PROJECTNAME.WebApi_HostAddress}}/ENTITYNAME/\nAccept: application/json\n\n###\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.WebApi/Program.cs",
    "content": "using Liquid.WebApi.Http.Extensions.DependencyInjection;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing PROJECTNAME.Domain;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services to the container.\n\n//TODO: Register and configure repository Liquid Cartridge\n//\n// Examples:\n//\n// [Mongo Cartridge]\n// 1. add Liquid Cartridge using CLI : dotnet add package Liquid.Repository.Mongo --version 6.*\n// 3. import liquid cartridge reference here: using Liquid.Repository.Mongo.Extensions;\n// 4. call cartridge DI method here : builder.Services.AddLiquidMongoRepository<ENTITYNAME, ENTITYIDTYPE>(\"Liquid:MyMongoDbSettings:Entities\");\n// 5. edit appsettings.json file to include database configurations.\n//\n//[EntityFramework Cartridge]\n// 1. add DbContext using CLI command: dotnet new liquiddbcontextproject --projectName PROJECTNAME --entityName ENTITYNAME\n// 2. add PROJECTNAME.Repository to solution: dotnet sln add PROJECTNAME.Repository/PROJECTNAME.Repository.csproj\n// 3. add PROJECTNAME.Repository project reference to PROJECTNAME.WebApi project: dotnet add reference ../PROJECTNAME.Repository/PROJECTNAME.Repository.csproj\n// 4. add database dependency in this project using CLI command: dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.*\n// 5. import EntityFrameworkCore reference here: using Microsoft.EntityFrameworkCore;\n// 6. set database options here: Action<DbContextOptionsBuilder> options = (opt) => opt.UseInMemoryDatabase(\"CRUD\");\n// 7. add Liquid Cartridge in this project using CLI command: dotnet add package Liquid.Repository.EntityFramework --version 6.*\n// 8. import liquid cartridge reference here: using Liquid.Repository.EntityFramework.Extensions;\n// 9. import PROJECTNAME.Repository here: using PROJECTNAME.Repository;\n// 9. call cartridge DI method here: builder.Services.AddLiquidEntityFramework<LiquidDbContext, ENTITYNAME, ENTITYIDTYPE>(options);\n// 10. edit appsettings.json file to include database configurations if necessary (for InMemory it's not necessary).\n\nbuilder.Services.AddLiquidHttp(\"Liquid\", false, typeof(IDomainInjection).Assembly);\nbuilder.Services.AddControllers();\n// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.WebApi/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Crud.Solution/src/PROJECTNAME.WebApi/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Trace\",\n      \"Microsoft\": \"Trace\",\n      \"Microsoft.Hosting.Lifetime\": \"Trace\"\n    },\n    \"Console\": {\n      \"IncludeScopes\": true,\n      \"FormatterName\": \"json\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"Liquid\": {\n    \"swagger\": {\n      \"name\": \"v1\",\n      \"host\": \"\",\n      \"schemes\": [ \"http\", \"https\" ],\n      \"title\": \"PROJECTNAME.WebApi\",\n      \"version\": \"v1\",\n      \"description\": \"PROJECTNAME APIs\",\n      \"SwaggerEndpoint\": {\n        \"url\": \"/swagger/v1/swagger.json\",\n        \"name\": \"PROJECTNAMEWebApi\"\n      }\n    },\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"MyMongoDbSettings\": {\n      \"Settings\": [\n        {\n          \"connectionString\": \"\",\n          \"databaseName\": \"MySampleDb\",\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.DbContext.AddEntity/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Class\" ],\n  \"identity\": \"Liquid.DbContext.AddEntity\",\n  \"name\": \"Liquid DbContext entity configuration class (for Entity Framework)\",\n  \"shortName\": \"liquidbcontextaddentity\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.DbContext.AddEntity/PROJECTNAME.Repository/Configurations/ENTITYNAMEConfiguration.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace PROJECTNAME.Repository.Configurations\n{\n    public class ENTITYNAMEConfiguration : IEntityTypeConfiguration<ENTITYNAME>\n    {\n        public void Configure(EntityTypeBuilder<ENTITYNAME> builder)\n        {\n            builder.Property(o => o.Id).ValueGeneratedOnAdd();\n\n            builder.HasKey(o => o.Id);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.DbContext.Project/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Library\", \"Project\" ],\n  \"identity\": \"Liquid.Repository.DbContext.Project\",\n  \"name\": \"Liquid Repository project (EntityFramework DbContext configurations)\",\n  \"shortName\": \"liquiddbcontextproject\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.DbContext.Project/PROJECTNAME.Repository/Configurations/ENTITYNAMEConfiguration.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\n\nnamespace PROJECTNAME.Repository.Configurations\n{\n    public class ENTITYNAMEConfiguration : IEntityTypeConfiguration<ENTITYNAME>\n    {\n        public void Configure(EntityTypeBuilder<ENTITYNAME> builder)\n        {\n            builder.Property(o => o.Id).ValueGeneratedOnAdd();\n\n            builder.HasKey(o => o.Id);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.DbContext.Project/PROJECTNAME.Repository/LiquidDbContext.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\nusing System;\n\nnamespace PROJECTNAME.Repository\n{\n    public class LiquidDbContext : DbContext\n    {\n        public LiquidDbContext() : base() { }\n\n        public LiquidDbContext(DbContextOptions<LiquidDbContext> options) : base(options) { }\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.DbContext.Project/PROJECTNAME.Repository/PROJECTNAME.Repository.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore\" Version=\"6.0.31\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.AddHandler/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Library\" ],\n  \"identity\": \"Liquid.Domain.AddHandler\",\n  \"name\": \"Liquid mediator command handler\",\n  \"shortName\": \"liquiddomainaddhandler\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.AddHandler/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEHandler : IRequestHandler<COMMANDNAMEENTITYNAMERequest, COMMANDNAMEENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public COMMANDNAMEENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<COMMANDNAMEENTITYNAMEResponse> Handle(COMMANDNAMEENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            //TODO: implement handler operation.\n\n            return new COMMANDNAMEENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.AddHandler/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMERequest : IRequest<COMMANDNAMEENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public COMMANDNAMEENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.AddHandler/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public COMMANDNAMEENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.AddHandler/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEValidator : AbstractValidator<COMMANDNAMEENTITYNAMERequest>\n    {\n        public COMMANDNAMEENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Library\", \"Project\" ],\n  \"identity\": \"Liquid.Domain.Project\",\n  \"name\": \"Liquid Domain project (mediator command handler)\",\n  \"shortName\": \"liquiddomainproject\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/PROJECTNAME.Domain/Entities/ENTITYNAME.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\n\nnamespace PROJECTNAME.Domain.Entities\n{\n    public class ENTITYNAME : LiquidEntity<ENTITYIDTYPE>\n    {\n        //TODO: declare entity properties.\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEHandler : IRequestHandler<COMMANDNAMEENTITYNAMERequest, COMMANDNAMEENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public COMMANDNAMEENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<COMMANDNAMEENTITYNAMEResponse> Handle(COMMANDNAMEENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            //TODO: implement handler operation.\n\n            return new COMMANDNAMEENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMERequest : IRequest<COMMANDNAMEENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public COMMANDNAMEENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public COMMANDNAMEENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEValidator : AbstractValidator<COMMANDNAMEENTITYNAMERequest>\n    {\n        public COMMANDNAMEENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.Domain.Project/PROJECTNAME.Domain/PROJECTNAME.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0-alpha-05\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Web\", \"ASP.NET\" ],\n  \"identity\": \"Liquid.WebApi.AddEntity\",\n  \"name\": \"Liquid entity class, mediator command handler and CRUD controller\",\n  \"shortName\": \"liquidwebapiaddentity\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/PROJECTNAME.Domain/Entities/ENTITYNAME.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\n\nnamespace PROJECTNAME.Domain.Entities\n{\n    public class ENTITYNAME : LiquidEntity<ENTITYIDTYPE>\n    {\n        //TODO: declare entity properties.\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEHandler : IRequestHandler<COMMANDNAMEENTITYNAMERequest, COMMANDNAMEENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public COMMANDNAMEENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<COMMANDNAMEENTITYNAMEResponse> Handle(COMMANDNAMEENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            //TODO: implement handler operation.\n\n            return new COMMANDNAMEENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMERequest : IRequest<COMMANDNAMEENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public COMMANDNAMEENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public COMMANDNAMEENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEValidator : AbstractValidator<COMMANDNAMEENTITYNAMERequest>\n    {\n        public COMMANDNAMEENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.AddEntity/PROJECTNAME.WebApi/Controllers/ENTITYNAMEController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing PROJECTNAME.Domain.Entities;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing System;\nusing PROJECTNAME.Domain.Handlers;\n\nnamespace PROJECTNAME.WebApi.Controllers\n{\n    [ApiController]\n    [Route(\"api/[controller]\")]\n    public class ENTITYNAMEController : LiquidControllerBase\n    {\n        public ENTITYNAMEController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        [HttpPost]\n        public async Task<IActionResult> COMMANDNAME([FromBody] ENTITYNAME entity) => await ExecuteAsync(new COMMANDNAMEENTITYNAMERequest(entity), HttpStatusCode.OK);\n\n    }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Web\", \"WebApi\" ],\n  \"identity\": \"Liquid.WebApi.Project\",\n  \"name\": \"Liquid WebAPI project\",\n  \"shortName\": \"liquidwebapiproject\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/PROJECTNAME.WebApi/Controllers/ENTITYNAMEController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing PROJECTNAME.Domain.Entities;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing System;\nusing PROJECTNAME.Domain.Handlers;\n\nnamespace PROJECTNAME.WebApi.Controllers\n{\n    [ApiController]\n    [Route(\"api/[controller]\")]\n    public class ENTITYNAMEController : LiquidControllerBase\n    {\n        public ENTITYNAMEController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        [HttpPost]\n        public async Task<IActionResult> COMMANDNAME([FromBody] ENTITYNAME entity) => await ExecuteAsync(new COMMANDNAMEENTITYNAMERequest(entity), HttpStatusCode.OK);\n\n    }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/PROJECTNAME.WebApi/PROJECTNAME.WebApi.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <InvariantGlobalization>true</InvariantGlobalization>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.WebApi.Http\" Version=\"8.0.0-alpha-02\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/PROJECTNAME.WebApi/PROJECTNAME.WebApi.http",
    "content": "@PROJECTNAME.WebApi_HostAddress = http://localhost:5003\n\nGET {{PROJECTNAME.WebApi_HostAddress}}/ENTITYNAME/\nAccept: application/json\n\n###\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/PROJECTNAME.WebApi/Program.cs",
    "content": "using Liquid.WebApi.Http.Extensions.DependencyInjection;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing PROJECTNAME.Domain;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services to the container.\n\n//TODO: Register and configure repository Liquid Cartridge\n//\n// Examples:\n//\n// [Mongo Cartridge]\n// 1. add Liquid Cartridge using CLI : dotnet add package Liquid.Repository.Mongo --version 6.*\n// 3. import liquid cartridge reference here: using Liquid.Repository.Mongo.Extensions;\n// 4. call cartridge DI method here : builder.Services.AddLiquidMongoRepository<ENTITYNAME, ENTITYIDTYPE>(\"Liquid:MyMongoDbSettings:Entities\");\n// 5. edit appsettings.json file to include database configurations.\n//\n//[EntityFramework Cartridge]\n// 1. add DbContext using CLI command: dotnet new liquiddbcontextproject --projectName PROJECTNAME --entityName ENTITYNAME\n// 2. add PROJECTNAME.Repository to solution: dotnet sln add PROJECTNAME.Repository/PROJECTNAME.Repository.csproj\n// 3. add PROJECTNAME.Repository project reference to PROJECTNAME.WebApi project: dotnet add reference ../PROJECTNAME.Repository/PROJECTNAME.Repository.csproj\n// 4. add database dependency in this project using CLI command: dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.*\n// 5. import EntityFrameworkCore reference here: using Microsoft.EntityFrameworkCore;\n// 6. set database options here: Action<DbContextOptionsBuilder> options = (opt) => opt.UseInMemoryDatabase(\"CRUD\");\n// 7. add Liquid Cartridge in this project using CLI command: dotnet add package Liquid.Repository.EntityFramework --version 6.*\n// 8. import liquid cartridge reference here: using Liquid.Repository.EntityFramework.Extensions;\n// 9. import PROJECTNAME.Repository here: using PROJECTNAME.Repository;\n// 9. call cartridge DI method here: builder.Services.AddLiquidEntityFramework<LiquidDbContext, ENTITYNAME, ENTITYIDTYPE>(options);\n// 10. edit appsettings.json file to include database configurations if necessary (for InMemory it's not necessary).\n\nbuilder.Services.AddLiquidHttp(\"Liquid\", false, typeof(COMMANDNAMEENTITYNAMERequest).Assembly);\nbuilder.Services.AddControllers();\n// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/PROJECTNAME.WebApi/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Project/PROJECTNAME.WebApi/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Trace\",\n      \"Microsoft\": \"Trace\",\n      \"Microsoft.Hosting.Lifetime\": \"Trace\"\n    },\n    \"Console\": {\n      \"IncludeScopes\": true,\n      \"FormatterName\": \"json\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"Liquid\": {\n    \"swagger\": {\n      \"name\": \"v1\",\n      \"host\": \"\",\n      \"schemes\": [ \"http\", \"https\" ],\n      \"title\": \"PROJECTNAME.WebApi\",\n      \"version\": \"v1\",\n      \"description\": \"PROJECTNAME APIs\",\n      \"SwaggerEndpoint\": {\n        \"url\": \"/swagger/v1/swagger.json\",\n        \"name\": \"PROJECTNAMEWebApi\"\n      }\n    },\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"MyMongoDbSettings\": {\n      \"Settings\": [\n        {\n          \"connectionString\": \"\",\n          \"databaseName\": \"MySampleDb\",\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"WebApi\", \"Solution\" ],\n  \"identity\": \"Liquid.WebApi.Solution\",\n  \"name\": \"Liquid WebAPI solution (Domain and WebAPI projects)\",\n  \"shortName\": \"liquidwebapisolution\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Domain/Entities/ENTITYNAME.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\n\nnamespace PROJECTNAME.Domain.Entities\n{\n    public class ENTITYNAME : LiquidEntity<ENTITYIDTYPE>\n    {\n        //TODO: declare entity properties.\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEHandler : IRequestHandler<COMMANDNAMEENTITYNAMERequest, COMMANDNAMEENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public COMMANDNAMEENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<COMMANDNAMEENTITYNAMEResponse> Handle(COMMANDNAMEENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            //TODO: implement handler operation.\n\n            return new COMMANDNAMEENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMERequest : IRequest<COMMANDNAMEENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public COMMANDNAMEENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public COMMANDNAMEENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEValidator : AbstractValidator<COMMANDNAMEENTITYNAMERequest>\n    {\n        public COMMANDNAMEENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Domain/PROJECTNAME.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0-alpha-05\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.Microservice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.8.34408.163\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"PROJECTNAME.Domain\", \"PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\", \"{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"PROJECTNAME.WebApi\", \"PROJECTNAME.WebApi\\PROJECTNAME.WebApi.csproj\", \"{D5B3CA90-0B90-4CE5-A108-AF53BEE9EB44}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{D5B3CA90-0B90-4CE5-A108-AF53BEE9EB44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{D5B3CA90-0B90-4CE5-A108-AF53BEE9EB44}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{D5B3CA90-0B90-4CE5-A108-AF53BEE9EB44}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{D5B3CA90-0B90-4CE5-A108-AF53BEE9EB44}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {F64CB676-D776-4B6A-B54B-59EA1BD87241}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.WebApi/Controllers/ENTITYNAMEController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing PROJECTNAME.Domain.Entities;\nusing System.Net;\nusing System.Threading.Tasks;\nusing Microsoft.AspNetCore.Http;\nusing System;\nusing PROJECTNAME.Domain.Handlers;\n\nnamespace PROJECTNAME.WebApi.Controllers\n{\n    [ApiController]\n    [Route(\"api/[controller]\")]\n    public class ENTITYNAMEController : LiquidControllerBase\n    {\n        public ENTITYNAMEController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        [HttpPost]\n        public async Task<IActionResult> COMMANDNAME([FromBody] ENTITYNAME entity) => await ExecuteAsync(new COMMANDNAMEENTITYNAMERequest(entity), HttpStatusCode.OK);\n\n    }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.WebApi/PROJECTNAME.WebApi.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk.Web\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>enable</Nullable>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <InvariantGlobalization>true</InvariantGlobalization>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.WebApi.Http\" Version=\"8.0.0-alpha-02\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.WebApi/PROJECTNAME.WebApi.http",
    "content": "@PROJECTNAME.WebApi_HostAddress = http://localhost:5003\n\nGET {{PROJECTNAME.WebApi_HostAddress}}/ENTITYNAME/\nAccept: application/json\n\n###\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.WebApi/Program.cs",
    "content": "using Liquid.WebApi.Http.Extensions.DependencyInjection;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing PROJECTNAME.Domain;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System;\n\nvar builder = WebApplication.CreateBuilder(args);\n\n// Add services to the container.\n\n//TODO: Register and configure repository Liquid Cartridge\n//\n// Examples:\n//\n// [Mongo Cartridge]\n// 1. add Liquid Cartridge using CLI : dotnet add package Liquid.Repository.Mongo --version 6.*\n// 3. import liquid cartridge reference here: using Liquid.Repository.Mongo.Extensions;\n// 4. call cartridge DI method here : builder.Services.AddLiquidMongoRepository<ENTITYNAME, ENTITYIDTYPE>(\"Liquid:MyMongoDbSettings:Entities\");\n// 5. edit appsettings.json file to include database configurations.\n//\n//[EntityFramework Cartridge]\n// 1. add DbContext using CLI command: dotnet new liquiddbcontextproject --projectName PROJECTNAME --entityName ENTITYNAME\n// 2. add PROJECTNAME.Repository to solution: dotnet sln add PROJECTNAME.Repository/PROJECTNAME.Repository.csproj\n// 3. add PROJECTNAME.Repository project reference to PROJECTNAME.WebApi project: dotnet add reference ../PROJECTNAME.Repository/PROJECTNAME.Repository.csproj\n// 4. add database dependency in this project using CLI command: dotnet add package Microsoft.EntityFrameworkCore.InMemory --version 6.*\n// 5. import EntityFrameworkCore reference here: using Microsoft.EntityFrameworkCore;\n// 6. set database options here: Action<DbContextOptionsBuilder> options = (opt) => opt.UseInMemoryDatabase(\"CRUD\");\n// 7. add Liquid Cartridge in this project using CLI command: dotnet add package Liquid.Repository.EntityFramework --version 6.*\n// 8. import liquid cartridge reference here: using Liquid.Repository.EntityFramework.Extensions;\n// 9. import PROJECTNAME.Repository here: using PROJECTNAME.Repository;\n// 9. call cartridge DI method here: builder.Services.AddLiquidEntityFramework<LiquidDbContext, ENTITYNAME, ENTITYIDTYPE>(options);\n// 10. edit appsettings.json file to include database configurations if necessary (for InMemory it's not necessary).\n\nbuilder.Services.AddLiquidHttp(\"Liquid\", false, typeof(COMMANDNAMEENTITYNAMERequest).Assembly);\nbuilder.Services.AddControllers();\n// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle\nbuilder.Services.AddEndpointsApiExplorer();\nbuilder.Services.AddSwaggerGen();\n\nvar app = builder.Build();\n\n// Configure the HTTP request pipeline.\nif (app.Environment.IsDevelopment())\n{\n    app.UseSwagger();\n    app.UseSwaggerUI();\n}\n\napp.UseHttpsRedirection();\n\napp.UseAuthorization();\n\napp.MapControllers();\n\napp.Run();"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.WebApi/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WebApi.Solution/src/PROJECTNAME.WebApi/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Trace\",\n      \"Microsoft\": \"Trace\",\n      \"Microsoft.Hosting.Lifetime\": \"Trace\"\n    },\n    \"Console\": {\n      \"IncludeScopes\": true,\n      \"FormatterName\": \"json\"\n    }\n  },\n  \"AllowedHosts\": \"*\",\n  \"Liquid\": {\n    \"swagger\": {\n      \"name\": \"v1\",\n      \"host\": \"\",\n      \"schemes\": [ \"http\", \"https\" ],\n      \"title\": \"PROJECTNAME.WebApi\",\n      \"version\": \"v1\",\n      \"description\": \"PROJECTNAME APIs\",\n      \"SwaggerEndpoint\": {\n        \"url\": \"/swagger/v1/swagger.json\",\n        \"name\": \"PROJECTNAMEWebApi\"\n      }\n    },\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"MyMongoDbSettings\": {\n      \"Settings\": [\n        {\n          \"connectionString\": \"\",\n          \"databaseName\": \"MySampleDb\",\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Project/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Worker\", \"Web\" ],\n  \"identity\": \"Liquid.WorkerService.Project\",\n  \"name\": \"Liquid WorkerService project\",\n  \"shortName\": \"liquidworkerproject\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Project/PROJECTNAME.WorkerService/PROJECTNAME.WorkerService.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Worker\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" Version=\"8.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Project/PROJECTNAME.WorkerService/Program.cs",
    "content": "using Liquid.Core.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System;\n\nnamespace PROJECTNAME.WorkerService\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureServices((hostContext, services) =>\n                {\n                    //TODO: Register and configure messaging consumer and repository Liquid Cartridge\n                    //\n                    // Example:\n                    //\n                    // [ServiceBus and Mongo Cartridges]\n                    // 1. add Liquid Cartridge using CLI : dotnet add package Liquid.Messaging.ServiceBus --version 6.X.X\n                    // 2. add Liquid Cartridge using CLI : dotnet add package Liquid.Repository.Mongo --version 6.X.X\n                    // 3. import liquid cartridge reference here: using Liquid.Repository.Mongo.Extensions;\n                    // 4. import liquid cartridge reference here: using Liquid.Messaging.ServiceBus.Extensions.DependencyInjection;\n                    // 5. call repository cartridge DI method :\n                    //  services.AddLiquidMongoRepository<ENTITYNAME, Guid>(\"Liquid:MyMongoDbSettings\", \"SampleCollection\");\n                    // 6. call messaging cartridge DI method :\n                    //  services.AddLiquidServiceBusConsumer<Worker, ENTITYNAME>(\"Liquid:ServiceBus\", \"liquidinput\", false, typeof(COMMANDNAMEENTITYNAMERequest).Assembly);\n                    // 7. edit appsettings.json file to include database and message queue configurations.\n\n                });\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Project/PROJECTNAME.WorkerService/Worker.cs",
    "content": "using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace PROJECTNAME.WorkerService\n{\n    public class Worker : ILiquidWorker<ENTITYNAME>\n    {\n        private readonly ILogger<Worker> _logger;\n        private readonly IMediator _mediator;\n\n        public Worker(ILogger<Worker> logger, IMediator mediator)\n        {\n            _logger = logger;\n            _mediator = mediator;\n        }\n\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<ENTITYNAME> args, CancellationToken cancellationToken)\n        {\n\n            await _mediator.Send(new COMMANDNAMEENTITYNAMERequest(args.Data));\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Project/PROJECTNAME.WorkerService/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Project/PROJECTNAME.WorkerService/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"Liquid\": {\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"ScopedContext\": {\n      \"keys\": [\n        {\n          \"keyName\": \"Connection\",\n          \"required\": false\n        }\n      ]\n    },\n    \"ScopedLogging\": {\n      \"keys\": [\n        {\n          \"keyName\": \"Connection\",\n          \"required\": false\n        }\n      ]\n    },\n    \"MyMongoDbSettings\": {\n      \"Settings\": [\n        {\n          \"connectionString\": \"\",\n          \"databaseName\": \"MySampleDb\",\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      ]\n    },\n    \"ServiceBus\": {\n      \"Settings\": [\n        {\n          \"ConnectionString\": \"\",\n          \"EntityPath\": \"liquidinput\"\n        }\n      ]\n    }\n  }  \n} \n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/.template.config/template.json",
    "content": "{\n  \"$schema\": \"http://json.schemastore.org/template\",\n  \"author\": \"Avanade Brazil\",\n  \"classifications\": [ \"LAF\", \"Worker\", \"Web\", \"Solution\" ],\n  \"identity\": \"Liquid.WorkerService.Solution\",\n  \"name\": \"Liquid WorkerService solution (Domain and WorkerService projects)\",\n  \"description\": \"Create a worker service solution with worker and domain projects using Liquid Framework.\",\n  \"shortName\": \"liquidworkersolution\",\n  \"tags\": {\n    \"language\": \"C#\",\n    \"type\": \"project\"\n  },\n  \"symbols\": {\n    \"projectName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"PROJECTNAME\",\n      \"FileRename\": \"PROJECTNAME\",\n      \"defaultValue\": \"MyProject\"\n    },\n    \"entityName\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYNAME\",\n      \"FileRename\": \"ENTITYNAME\",\n      \"defaultValue\": \"MyObject\"\n    },\n    \"command\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"COMMANDNAME\",\n      \"FileRename\": \"COMMANDNAME\",\n      \"defaultValue\": \"MyCommand\"\n    },\n    \"entityIdType\": {\n      \"type\": \"parameter\",\n      \"replaces\": \"ENTITYIDTYPE\",\n      \"defaultValue\": \"int\"\n    }\n  }\n}"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Domain/Entities/ENTITYNAME.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\n\nnamespace PROJECTNAME.Domain.Entities\n{\n    public class ENTITYNAME : LiquidEntity<ENTITYIDTYPE>\n    {\n        //TODO: declare entity properties.\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEHandler.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing MediatR;\nusing PROJECTNAME.Domain.Entities;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing System;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEHandler : IRequestHandler<COMMANDNAMEENTITYNAMERequest, COMMANDNAMEENTITYNAMEResponse>\n    {\n        private readonly ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> _repository;\n\n        public COMMANDNAMEENTITYNAMEHandler(ILiquidRepository<ENTITYNAME, ENTITYIDTYPE> repository)\n        {\n            _repository = repository;\n        }\n\n\n        public async Task<COMMANDNAMEENTITYNAMEResponse> Handle(COMMANDNAMEENTITYNAMERequest request, CancellationToken cancellationToken)\n        {\n            //TODO: implement handler operation.\n\n            return new COMMANDNAMEENTITYNAMEResponse(request.Body);\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMERequest.cs",
    "content": "﻿using MediatR;\nusing PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMERequest : IRequest<COMMANDNAMEENTITYNAMEResponse>\n    {\n        public ENTITYNAME Body { get; set; }\n\n        public COMMANDNAMEENTITYNAMERequest(ENTITYNAME body)\n        {\n            Body = body;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEResponse.cs",
    "content": "﻿using PROJECTNAME.Domain.Entities;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEResponse\n    {\n        public ENTITYNAME Data { get; set; }\n\n        public COMMANDNAMEENTITYNAMEResponse(ENTITYNAME data)\n        {\n            Data = data;\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Domain/Handlers/COMMANDNAMEENTITYNAME/COMMANDNAMEENTITYNAMEValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace PROJECTNAME.Domain.Handlers\n{\n    public class COMMANDNAMEENTITYNAMEValidator : AbstractValidator<COMMANDNAMEENTITYNAMERequest>\n    {\n        public COMMANDNAMEENTITYNAMEValidator()\n        {\n            RuleFor(request => request.Body.Id).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Domain/PROJECTNAME.Domain.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Liquid.Core\" Version=\"8.0.0-alpha-05\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.Microservice.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 16\nVisualStudioVersion = 16.0.32106.194\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"PROJECTNAME.WorkerService\", \"PROJECTNAME.WorkerService\\PROJECTNAME.WorkerService.csproj\", \"{BF0E153B-F391-431B-AD2D-BB81799F39A6}\"\nEndProject\nProject(\"{9A19103F-16F7-4668-BE54-9A1E7A4F7556}\") = \"PROJECTNAME.Domain\", \"PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\", \"{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|Any CPU = Debug|Any CPU\n\t\tRelease|Any CPU = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{BF0E153B-F391-431B-AD2D-BB81799F39A6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{BF0E153B-F391-431B-AD2D-BB81799F39A6}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{BF0E153B-F391-431B-AD2D-BB81799F39A6}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{BF0E153B-F391-431B-AD2D-BB81799F39A6}.Release|Any CPU.Build.0 = Release|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Debug|Any CPU.Build.0 = Debug|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Release|Any CPU.ActiveCfg = Release|Any CPU\n\t\t{C45FC20A-6DAD-4BDE-BC3D-EBECF4058565}.Release|Any CPU.Build.0 = Release|Any CPU\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {F64CB676-D776-4B6A-B54B-59EA1BD87241}\n\tEndGlobalSection\nEndGlobal\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.WorkerService/PROJECTNAME.WorkerService.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk.Worker\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Hosting\" Version=\"8.0.0\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\PROJECTNAME.Domain\\PROJECTNAME.Domain.csproj\" />\n  </ItemGroup>\n</Project>\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.WorkerService/Program.cs",
    "content": "using Liquid.Core.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System;\n\nnamespace PROJECTNAME.WorkerService\n{\n    public class Program\n    {\n        public static void Main(string[] args)\n        {\n            CreateHostBuilder(args).Build().Run();\n        }\n\n        public static IHostBuilder CreateHostBuilder(string[] args) =>\n            Host.CreateDefaultBuilder(args)\n                .ConfigureServices((hostContext, services) =>\n                {\n                    //TODO: Register and configure messaging consumer and repository Liquid Cartridge\n                    //\n                    // Example:\n                    //\n                    // [ServiceBus and Mongo Cartridges]\n                    // 1. add Liquid Cartridge using CLI : dotnet add package Liquid.Messaging.ServiceBus --version 6.X.X\n                    // 2. add Liquid Cartridge using CLI : dotnet add package Liquid.Repository.Mongo --version 6.X.X\n                    // 3. import liquid cartridge reference here: using Liquid.Repository.Mongo.Extensions;\n                    // 4. import liquid cartridge reference here: using Liquid.Messaging.ServiceBus.Extensions.DependencyInjection;\n                    // 5. call repository cartridge DI method :\n                    //  services.AddLiquidMongoRepository<ENTITYNAME, Guid>(\"Liquid:MyMongoDbSettings\", \"SampleCollection\");\n                    // 6. call messaging cartridge DI method :\n                    //  services.AddLiquidServiceBusConsumer<Worker, ENTITYNAME>(\"Liquid:ServiceBus\", \"liquidinput\", false, typeof(COMMANDNAMEENTITYNAMERequest).Assembly);\n                    // 7. edit appsettings.json file to include database and message queue configurations.\n\n                });\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.WorkerService/Worker.cs",
    "content": "using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\nusing PROJECTNAME.Domain.Entities;\nusing PROJECTNAME.Domain.Handlers;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace PROJECTNAME.WorkerService\n{\n    public class Worker : ILiquidWorker<ENTITYNAME>\n    {\n        private readonly ILogger<Worker> _logger;\n        private readonly IMediator _mediator;\n\n        public Worker(ILogger<Worker> logger, IMediator mediator)\n        {\n            _logger = logger;\n            _mediator = mediator;\n        }\n\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<ENTITYNAME> args, CancellationToken cancellationToken)\n        {\n\n            await _mediator.Send(new COMMANDNAMEENTITYNAMERequest(args.Data));\n        }\n    }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.WorkerService/appsettings.Development.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  }\n}\n"
  },
  {
    "path": "templates/src/Liquid.Templates/Templates/Liquid.WorkerService.Solution/src/PROJECTNAME.WorkerService/appsettings.json",
    "content": "{\n  \"Logging\": {\n    \"LogLevel\": {\n      \"Default\": \"Information\",\n      \"Microsoft\": \"Warning\",\n      \"Microsoft.Hosting.Lifetime\": \"Information\"\n    }\n  },\n  \"Liquid\": {\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    },\n    \"ScopedContext\": {\n      \"keys\": [\n        {\n          \"keyName\": \"Connection\",\n          \"required\": false\n        }\n      ]\n    },\n    \"ScopedLogging\": {\n      \"keys\": [\n        {\n          \"keyName\": \"Connection\",\n          \"required\": false\n        }\n      ]\n    },\n    \"MyMongoDbSettings\": {\n      \"Settings\": [\n        {\n          \"connectionString\": \"\",\n          \"databaseName\": \"MySampleDb\",\n          \"CollectionName\": \"SampleCollection\",\n          \"ShardKey\": \"id\"\n        }\n      ]\n    },\n    \"ServiceBus\": {\n      \"Settings\": [\n        {\n          \"ConnectionString\": \"\",\n          \"EntityPath\": \"liquidinput\"\n        }\n      ]\n    }\n  }  \n} \n"
  },
  {
    "path": "test/CodeCoverage.runsettings",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- File name extension must be .runsettings -->\n<RunSettings>\n  <DataCollectionRunSettings>\n    <DataCollectors>\n      <DataCollector friendlyName=\"Code Coverage\" uri=\"datacollector://Microsoft/CodeCoverage/2.0\" assemblyQualifiedName=\"Microsoft.VisualStudio.Coverage.DynamicCoverageDataCollector, Microsoft.VisualStudio.TraceCollector, Version=11.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a\">\n        <Configuration>\n          <CodeCoverage>\n            <CompanyNames>\n              <Exclude>\n                <CompanyName>.*nunit.*</CompanyName>\n                <CompanyName>.*microsoft.*</CompanyName>\n              </Exclude>\n            </CompanyNames>\n\n            <!-- Exclude modules that aren't to be processed, by their name / path -->\n            <ModulePaths>\n              <Exclude>\n                <ModulePath>.*Polly.*</ModulePath>\n              </Exclude>\n            </ModulePaths>\n\n            <!-- Match attributes on any code element: -->\n            <Attributes>\n              <Exclude>\n                <Attribute>^System\\.Diagnostics\\.DebuggerHiddenAttribute$</Attribute>\n                <Attribute>^System\\.Diagnostics\\.DebuggerNonUserCodeAttribute$</Attribute>\n                <!--<Attribute>^System\\.Runtime\\.CompilerServices.CompilerGeneratedAttribute$</Attribute>-->\n                <Attribute>^System\\.CodeDom\\.Compiler.GeneratedCodeAttribute$</Attribute>\n                <Attribute>^System\\.Diagnostics\\.CodeAnalysis.ExcludeFromCodeCoverageAttribute$</Attribute>\n              </Exclude>\n            </Attributes>\n\n            <!-- Match the path of the source files in which each method is defined: -->\n            <Sources>\n              <Exclude>\n                <Source>.*\\\\atlmfc\\\\.*</Source>\n                <Source>.*\\\\vctools\\\\.*</Source>\n                <Source>.*\\\\public\\\\sdk\\\\.*</Source>\n                <Source>.*\\\\microsoft sdks\\\\.*</Source>\n                <Source>.*\\\\vc\\\\include\\\\.*</Source>\n              </Exclude>\n            </Sources>\n\n            <!-- We recommend you do not change the following values: -->\n            <UseVerifiableInstrumentation>True</UseVerifiableInstrumentation>\n            <AllowLowIntegrityProcesses>True</AllowLowIntegrityProcesses>\n            <CollectFromChildProcesses>True</CollectFromChildProcesses>\n            <CollectAspDotNet>False</CollectAspDotNet>\n\n          </CodeCoverage>\n        </Configuration>\n      </DataCollector>\n    </DataCollectors>\n  </DataCollectionRunSettings>\n</RunSettings>\n"
  },
  {
    "path": "test/Liquid.Cache.Memory.Tests/IServiceCollectionExtensionTest.cs",
    "content": "using Liquid.Cache.Memory.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Caching.Distributed;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing System.Linq;\nusing Xunit;\n\nnamespace Liquid.Cache.Memory.Tests\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidMemoryDistributedCache_WhenWithTelemetryTrue_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLogging();\n            _sut.AddLiquidMemoryDistributedCache(options =>\n            {\n                options.SizeLimit = 3000;\n            }, true);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ImplementationType == typeof(MemoryDistributedCache)));\n\n        }\n\n        [Fact]\n        public void AddLiquidMemoryDistributedCache_WhenWithTelemetryfalse_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLiquidMemoryDistributedCache(options =>\n            {\n                options.SizeLimit = 3000;\n            }, false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ImplementationType == typeof(MemoryDistributedCache)));\n\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Cache.Memory.Tests/Liquid.Cache.Memory.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Cache.Memory\\Liquid.Cache.Memory.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Cache.NCache.Tests/IServiceCollectionExtensionTest.cs",
    "content": "using Liquid.Cache.NCache.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing Xunit;\n\nnamespace Liquid.Cache.NCache.Tests\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidNCacheDistributedCache_WhenWithTelemetryTrue_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLogging();\n            _sut.AddLiquidNCacheDistributedCache(configuration =>\n            {\n                configuration.CacheName = \"myCache\";\n                configuration.EnableLogs = false;\n                configuration.ExceptionsEnabled = true;\n            }, true);\n\n            var provider = _sut.BuildServiceProvider();\n\n            //Assert.NotNull(provider.GetService<ILiquidCache>());\n            //Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n\n        }\n\n        [Fact]\n        public void AddLiquidNCacheDistributedCache_WhenWithTelemetryfalse_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLiquidNCacheDistributedCache(configuration =>\n            {\n                configuration.CacheName = \"myCache\";\n                configuration.EnableLogs = false;\n                configuration.ExceptionsEnabled = true;\n            }, false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            //Assert.NotNull(provider.GetService<ILiquidCache>());\n            //Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Cache.NCache.Tests/Liquid.Cache.NCache.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n\n    <GenerateDocumentationFile>True</GenerateDocumentationFile>\n\n    <ProduceReferenceAssembly>False</ProduceReferenceAssembly>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Cache.NCache\\Liquid.Cache.NCache.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"client.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"config.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"tls.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Cache.NCache.Tests/client.ncconf",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n  <configuration>\n    <ncache-server connection-retries=\"3\" retry-connection-delay=\"0\" retry-interval=\"1\" command-retries=\"3\" command-retry-interval=\"0.1\" client-request-timeout=\"90\" connection-timeout=\"5\" port=\"9800\"/>\n    <cache id=\"myReplicatedCache\" client-cache-id=\"\" client-cache-syncmode=\"optimistic\" default-readthru-provider=\"\" default-writethru-provider=\"\" load-balance=\"True\" enable-client-logs=\"False\" log-level=\"error\">\n      <server name=\"10.0.5.1\"/>\n    </cache>\n  </configuration>\n"
  },
  {
    "path": "test/Liquid.Cache.NCache.Tests/config.ncconf",
    "content": "<configuration>\n  <cache-config cache-name=\"myCache\" alias=\"\" config-id=\"e097c2c0-88af-4aa2-8a8a-c6432eeaa3fe\" config-version=\"0\" store-type=\"distributed-cache\">\n    <cache-settings inproc=\"True\" last-modified=\"\" auto-start=\"False\" data-format=\"Binary\">\n      <logging enable-logs=\"True\" trace-errors=\"True\" trace-notices=\"False\" trace-warnings=\"False\" trace-debug=\"False\" log-path=\"\"/>\n      <performance-counters enable-counters=\"True\" snmp-port=\"0\"/>\n      <data-load-balancing enabled=\"False\" auto-balancing-threshold=\"60%\" auto-balancing-interval=\"30sec\"/>\n      <compression enable-compression=\"False\" threshold=\"100kb\"/>\n      <client-death-detection/>\n      <client-activity-notification enabled=\"False\" retention-period=\"5sec\"/>\n      <cache-notifications item-remove=\"False\" item-add=\"False\" item-update=\"False\"/>\n      <cleanup interval=\"15sec\"/>\n      <storage type=\"heap\" cache-size=\"1024mb\"/>\n      <eviction-policy enabled-eviction=\"True\" default-priority=\"normal\" policy=\"lru\" eviction-ratio=\"5%\"/>\n      <expiration-policy enabled=\"False\">\n        <absolute-expiration longer-enabled=\"False\" longer-value=\"0\" default-enabled=\"False\" default-value=\"0\"/>\n        <sliding-expiration longer-enabled=\"False\" longer-value=\"0\" default-enabled=\"False\" default-value=\"0\"/>\n      </expiration-policy>\n      <cache-topology topology=\"local-cache\"/>\n      <tasks-config max-tasks=\"10\" chunk-size=\"100\" communicate-stats=\"False\" queue-size=\"10\" max-avoidable-exceptions=\"10\"/>\n      <split-brain-recovery enable=\"False\" detection-interval=\"60\"/>\n    </cache-settings>\n  </cache-config>\n\n\n</configuration>"
  },
  {
    "path": "test/Liquid.Cache.NCache.Tests/tls.ncconf",
    "content": "<tls-info>\n\t<certificate-name>certificate-name</certificate-name>\n\t<certificate-thumbprint>your-thumbprint</certificate-thumbprint>\n\t<enable>false</enable>\n\t<enable-client-server-tls>false</enable-client-server-tls>\n\t<use-mutual-tls-for-client-to-server>false</use-mutual-tls-for-client-to-server>\n</tls-info>"
  },
  {
    "path": "test/Liquid.Cache.Redis.Tests/IServiceCollectionExtensionTest.cs",
    "content": "using Liquid.Cache.Redis.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Caching.StackExchangeRedis;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing System.Linq;\nusing Xunit;\n\nnamespace Liquid.Cache.Redis.Tests\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidRedisDistributedCache_WhenWithTelemetryTrue_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLogging();\n            _sut.AddLiquidRedisDistributedCache(options =>\n            {\n                options.Configuration = _configProvider.GetConnectionString(\"Test\");\n                options.InstanceName = \"TestInstance\";\n            }, true);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ImplementationType == typeof(LiquidCache)));\n\n        }\n\n        [Fact]\n        public void AddLiquidRedisDistributedCache_WhenWithTelemetryfalse_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLiquidRedisDistributedCache(options =>\n            {\n                options.Configuration = _configProvider.GetConnectionString(\"Test\");\n                options.InstanceName = \"TestInstance\";\n            }, false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ImplementationType == typeof(LiquidCache)));\n\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Cache.Redis.Tests/Liquid.Cache.Redis.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Cache.Redis\\Liquid.Cache.Redis.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Cache.SqlServer.Tests/IServiceCollectionExtensionTest.cs",
    "content": "using Liquid.Cache.SqlServer.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Caching.SqlServer;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing Xunit;\n\nnamespace Liquid.Cache.SqlServer.Tests\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidSqlServerDistributedCache_WhenWithTelemetryTrue_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLogging();\n            _sut.AddLiquidSqlServerDistributedCache(options =>\n            {\n                options.ConnectionString = \"DistCache_ConnectionString\";\n                options.SchemaName = \"dbo\";\n                options.TableName = \"TestCache\";\n            }, true);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ImplementationType == typeof(SqlServerCache)));\n\n        }\n\n        [Fact]\n        public void AddLiquidSqlServerDistributedCache_WhenWithTelemetryfalse_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddLiquidSqlServerDistributedCache(options =>\n            {\n                options.ConnectionString = \"DistCache_ConnectionString\";\n                options.SchemaName = \"dbo\";\n                options.TableName = \"TestCache\";\n            }, false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ImplementationType == typeof(SqlServerCache)));\n\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Cache.SqlServer.Tests/Liquid.Cache.SqlServer.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Abstractions\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Cache.SqlServer\\Liquid.Cache.SqlServer.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Extensions/IServiceCollectionExtension.cs",
    "content": "﻿using System.IO;\nusing System.Text;\nusing Liquid.Core.Telemetry.ElasticApm.Extensions.DependencyInjection;\nusing Liquid.Core.Telemetry.ElasticApm.Tests.Settings;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests.Extensions\n{\n    internal static class IServiceCollectionExtension\n    {\n        public static IServiceCollection AddElasticApmByConfiguration(this IServiceCollection services, bool enable)\n        {\n            var sb = new StringBuilder(\"{ \\\"ElasticApm\\\": {\");\n            sb.Append(\" \\\"ServerUrl\\\": \\\"http://elasticapm:8200\\\",\");\n            sb.Append(\" \\\"SecretToken\\\": \\\"apm-server-secret-token\\\",\");\n            sb.Append(\" \\\"TransactionSampleRate\\\": 1.0,\");\n            sb.Append(\" \\\"CloudProvider\\\": \\\"none\\\",\");\n            sb.Append(\" \\\"Enabled\\\": \");\n            sb.Append(enable.ToString().ToLower());\n            sb.Append(\" } }\");\n\n            using MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(sb.ToString()));\n\n            var config = new ConfigurationBuilder()\n                .AddJsonStream(stream)\n                .Build();\n\n            services.Configure<ElasticApmSettings>(config.GetSection(nameof(ElasticApmSettings)));\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            return services;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/IApplicationBuilderExtensionsTests.cs",
    "content": "﻿using System;\nusing Liquid.Core.Telemetry.ElasticApm.Extensions.DependencyInjection;\nusing Liquid.Core.Telemetry.ElasticApm.Tests.Settings;\nusing Microsoft.AspNetCore.Builder;\nusing Microsoft.Extensions.Configuration;\nusing NSubstitute;\nusing Xunit;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests\n{\n    public sealed class IApplicationBuilderExtensionsTests\n    {\n        private readonly IApplicationBuilder _builder;\n\n        public IApplicationBuilderExtensionsTests()\n        {\n            _builder = Substitute.For<IApplicationBuilder>();\n        }\n\n        [Fact]\n        public void UseElasticApmTelemetry_WhenConfigured()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n\n            var config = new ConfigurationSettings().AddElasticApm();\n\n            // Act\n            _builder.UseLiquidElasticApm(config);\n\n            // Assert\n            _builder.Received(2);\n        }\n\n        [Fact]\n        public void UseElasticApmTelemetry_WhenNotConfigured()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n\n            var config = new ConfigurationBuilder().Build();\n\n            // Act\n            _builder.UseLiquidElasticApm(config);\n\n            // Assert\n            _builder.Received(1);\n        }\n\n        [Fact]\n        public void UseElasticApmTelemetry_WhenConfigured_Enabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n\n            var config = new ConfigurationSettings().AddElasticApm(enable: true);\n\n            // Act\n            _builder.UseLiquidElasticApm(config);\n\n            // Assert\n            _builder.Received(2);\n        }\n\n        [Fact]\n        public void UseElasticApmTelemetry_WhenConfigured_NotEnabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n\n            var config = new ConfigurationSettings().AddElasticApm(enable: false);\n\n            // Act\n            _builder.UseLiquidElasticApm(config);\n\n            // Assert\n            _builder.Received(2);\n        }\n\n        [Fact]\n        public void UseElasticApmTelemetry_WhenEnvironement_Enabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", \"true\");\n\n            var config = new ConfigurationSettings().AddElasticApm();\n\n            // Act\n            _builder.UseLiquidElasticApm(config);\n\n            // Assert\n            _builder.Received(2);\n        }\n\n        [Fact]\n        public void UseElasticApmTelemetry_WhenEnvironement_NotEnabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", \"false\");\n\n            var config = new ConfigurationSettings().AddElasticApm();\n\n            // Act\n            _builder.UseLiquidElasticApm(config);\n\n            // Assert\n            _builder.Received(1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/IServiceCollectionExtensionsTests.cs",
    "content": "﻿using System;\nusing Liquid.Core.Telemetry.ElasticApm.Extensions.DependencyInjection;\nusing Liquid.Core.Telemetry.ElasticApm.Tests.Mocks;\nusing Liquid.Core.Telemetry.ElasticApm.Tests.Settings;\nusing MediatR;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Xunit;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests\n{\n    public sealed class IServiceCollectionExtensionsTests\n    {\n        [Fact]\n        public void AddElasticApmTelemetry_WhenConfigured()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n            var services = new ServiceCollection().AddLogging();\n\n            var config = new ConfigurationSettings().AddElasticApm();\n            services.Configure<ElasticApmSettings>(config.GetSection(nameof(ElasticApmSettings)));\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            // Act\n            using ServiceProvider serviceprovider = services.BuildServiceProvider();\n            var behaviour = serviceprovider.GetService<IPipelineBehavior<RequestMock, ResponseMock>>();\n\n            // Assert\n            Assert.NotNull(behaviour);\n        }\n\n        [Fact]\n        public void AddElasticApmTelemetry_WhenNotConfigured()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n            var services = new ServiceCollection().AddLogging();\n\n            var config = new ConfigurationBuilder().Build();\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            // Act\n            using ServiceProvider serviceprovider = services.BuildServiceProvider();\n            var behaviour = serviceprovider.GetService<IPipelineBehavior<RequestMock, ResponseMock>>();\n\n            // Assert\n            Assert.Null(behaviour);\n        }\n\n        [Fact]\n        public void AddElasticApmTelemetry_WhenConfigured_Enabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n            var services = new ServiceCollection().AddLogging();\n\n            var config = new ConfigurationSettings().AddElasticApm(enable: true);\n            services.Configure<ElasticApmSettings>(config.GetSection(nameof(ElasticApmSettings)));\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            // Act\n            using ServiceProvider serviceprovider = services.BuildServiceProvider();\n            var behaviour = serviceprovider.GetService<IPipelineBehavior<RequestMock, ResponseMock>>();\n\n            // Assert\n            Assert.NotNull(behaviour);\n        }\n\n        [Fact]\n        public void AddElasticApmTelemetry_WhenConfigured_NotEnabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", null);\n            var services = new ServiceCollection().AddLogging();\n\n            var config = new ConfigurationSettings().AddElasticApm(enable: false);\n            services.Configure<ElasticApmSettings>(config.GetSection(nameof(ElasticApmSettings)));\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            // Act\n            using ServiceProvider serviceprovider = services.BuildServiceProvider();\n            var behaviour = serviceprovider.GetService<IPipelineBehavior<RequestMock, ResponseMock>>();\n\n            // Assert\n            Assert.Null(behaviour);\n        }\n\n        [Fact]\n        public void AddElasticApmTelemetry_WhenEnvironement_Enabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", \"true\");\n\n            var services = new ServiceCollection().AddLogging();\n\n            var config = new ConfigurationSettings().AddElasticApm(enable: false);\n            services.Configure<ElasticApmSettings>(config.GetSection(nameof(ElasticApmSettings)));\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            // Act\n            using ServiceProvider serviceprovider = services.BuildServiceProvider();\n            var behaviour = serviceprovider.GetService<IPipelineBehavior<RequestMock, ResponseMock>>();\n\n            // Assert\n            //Assert.NotNull(behaviour);\n        }\n\n        [Fact]\n        public void AddElasticApmTelemetry_WhenEnvironement_NotEnabled()\n        {\n            // Arrange\n            Environment.SetEnvironmentVariable(\"ELASTIC_APM_ENABLED\", \"false\");\n\n            var services = new ServiceCollection().AddLogging();\n\n            var config = new ConfigurationSettings().AddElasticApm();\n            services.Configure<ElasticApmSettings>(config.GetSection(nameof(ElasticApmSettings)));\n\n            services.AddLiquidElasticApmTelemetry(config);\n\n            // Act\n            using ServiceProvider serviceprovider = services.BuildServiceProvider();\n            var behaviour = serviceprovider.GetService<IPipelineBehavior<RequestMock, ResponseMock>>();\n\n            // Assert\n            //Assert.Null(behaviour);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Liquid.Core.Telemetry.ElasticApm.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <Compile Remove=\"Mocks\\LoggerMock.cs\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Json\" Version=\"8.0.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Core.Telemetry.ElasticApm\\Liquid.Core.Telemetry.ElasticApm.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/LiquidElasticApmInterceptorTests.cs",
    "content": "using System;\nusing System.Threading.Tasks;\nusing Castle.DynamicProxy;\nusing Elastic.Apm.Api;\nusing Liquid.Core.Telemetry.ElasticApm.Implementations;\nusing Liquid.Core.Telemetry.ElasticApm.Tests.Mocks;\nusing Microsoft.Extensions.Logging;\nusing NSubstitute;\nusing Xunit;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests\n{\n    public class LiquidElasticApmInterceptorTests\n    {\n        private readonly LiquidElasticApmInterceptor _sut;\n\n        private readonly IMockService _service;\n\n        private readonly ILogger<LiquidElasticApmInterceptor> _logger;\n\n        private readonly ITracer _tracer;\n\n        public LiquidElasticApmInterceptorTests()\n        {\n            _logger = Substitute.For<ILogger<LiquidElasticApmInterceptor>>();\n\n            _tracer = Substitute.For<ITracer>();\n\n            _sut = new LiquidElasticApmInterceptor(_logger, _tracer);\n\n            var generator = new ProxyGenerator();\n\n            var logger = Substitute.For<ILogger<MockService>>();\n\n            IMockService service = new MockService(logger);\n\n            _service = generator.CreateInterfaceProxyWithTarget(service, _sut);\n        }\n\n        [Fact]\n        public async Task Intercept_WhenMethodExecutionIsSucessfull_TracerStarts()\n        {\n            await _service.Get();\n\n            _logger.Received(0);\n\n            _tracer.Received(1);\n        }\n\n        [Fact]\n        public async Task Intercept_WhenMethodExecutionThrowsException_TracerStartsLogsException()\n        {\n            await Assert.ThrowsAsync<NotImplementedException>(() => _service.GetError());\n\n            _logger.Received(1);\n\n            _tracer.Received(1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/LiquidElasticApmTelemetryBehaviorTests.cs",
    "content": "using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Elastic.Apm.Api;\nusing Liquid.Core.Telemetry.ElasticApm.MediatR;\nusing Liquid.Core.Telemetry.ElasticApm.Tests.Mocks;\nusing MediatR;\nusing Microsoft.Extensions.Logging;\nusing NSubstitute;\nusing Xunit;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests\n{\n    public class LiquidElasticApmTelemetryBehavior\n    {\n        private readonly ILogger<LiquidElasticApmTelemetryBehavior<RequestMock, ResponseMock>> _logger;\n\n        private readonly ITracer _tracer;\n\n        public LiquidElasticApmTelemetryBehavior()\n        {\n            _logger = Substitute.For<ILogger<LiquidElasticApmTelemetryBehavior<RequestMock, ResponseMock>>>();\n            _tracer = Substitute.For<ITracer>();\n        }\n\n        [Fact]\n        public async Task Handle_WhenMethodExecutionIsSucessfull_LogsStartEnd()\n        {\n            // Arrange\n            var handler = Substitute.For<IRequestHandler<RequestMock, ResponseMock>>();\n            var pipelineBehavior = new LiquidElasticApmTelemetryBehavior<RequestMock, ResponseMock>(_logger, _tracer); \n\n            // Act\n            await pipelineBehavior.Handle(new RequestMock(), () => \n            { \n                return handler.Handle(new RequestMock(), CancellationToken.None); \n            }, CancellationToken.None);\n\n            // Assert\n            _logger.Received(2);\n            _tracer.Received(1);\n        }\n\n        [Fact]\n        public async Task Handle_WhenMethodExecutionThrowsException_LogsException()\n        {\n            // Arrange\n            var handler = new CommandHandlerMock();\n            var pipelineBehavior = new LiquidElasticApmTelemetryBehavior<RequestMock, ResponseMock>(_logger, _tracer);\n\n            // Act\n            await Assert.ThrowsAsync<NotImplementedException>(() => \n                pipelineBehavior.Handle(new RequestMock(), () =>\n                {\n                    return handler.Handle(new RequestMock(), CancellationToken.None);\n                }, CancellationToken.None)\n            );\n\n            // Assert\n            _logger.Received(3);\n            _tracer.Received(1);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Mocks/CommandHandlerMock.cs",
    "content": "﻿using System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing MediatR;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests.Mocks\n{\n    public sealed class CommandHandlerMock : IRequestHandler<RequestMock, ResponseMock>\n    {\n        public Task<ResponseMock> Handle(RequestMock request, CancellationToken cancellationToken)\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Mocks/IMockService.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests.Mocks\n{\n    public interface IMockService\n    {\n        Task<string> Get();\n        Task<string> GetError();\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Mocks/MockService.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests.Mocks\n{\n    public class MockService : IMockService\n    {\n        private readonly ILogger<MockService> _logger;\n        public MockService(ILogger<MockService> logger)\n        {\n            _logger = logger;\n        }\n        public MockService()\n        {\n\n        }\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<string> Get()\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            _logger.LogInformation(\"sucess\");\n            return \"Test\";\n        }\n\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<string> GetError()\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Mocks/RequestMock.cs",
    "content": "﻿using MediatR;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests.Mocks\n{\n    public sealed class RequestMock : IRequest<ResponseMock>\n    {\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Mocks/ResponseMock.cs",
    "content": "﻿namespace Liquid.Core.Telemetry.ElasticApm.Tests.Mocks\n{\n    public sealed class ResponseMock\n    {\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Settings/ConfigurationSettings.cs",
    "content": "﻿using System.IO;\nusing System.Text;\nusing System.Text.Json;\nusing System.Text.Json.Serialization;\nusing Microsoft.Extensions.Configuration;\n\nnamespace Liquid.Core.Telemetry.ElasticApm.Tests.Settings\n{\n    internal class ConfigurationSettings\n    {\n        internal IConfiguration AddElasticApm(bool? enable = null)\n        {\n            var elasticApmSettings = new ElasticApmSettings\n            {\n                ServerUrl = \"http://elasticapm:8200\",\n                SecretToken = \"apm-server-secret-token\",\n                TransactionSampleRate = 1.0,\n                CloudProvider = \"none\"\n            };\n\n            if (enable.HasValue)\n            {\n                elasticApmSettings.Enabled = enable.Value;\n            }\n\n            var options = new JsonSerializerOptions\n            {\n                DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull\n            };\n            var sb = new StringBuilder(\"{ \\\"ElasticApm\\\": \");\n            sb.Append(JsonSerializer.Serialize(elasticApmSettings, options));\n            sb.Append(\" }\");\n\n            using MemoryStream stream = new MemoryStream(Encoding.ASCII.GetBytes(sb.ToString()));\n            var config = new ConfigurationBuilder()\n                .AddJsonStream(stream)\n                .Build();\n\n            return config;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Settings/ElasticApmSettings.cs",
    "content": "﻿namespace Liquid.Core.Telemetry.ElasticApm.Tests.Settings\n{\n    internal sealed class ElasticApmSettings : IElasticApmSettings\n    {\n        public string ServerUrl { get; set; }\n\n        public string SecretToken { get; set; }\n\n        public double TransactionSampleRate { get; set; }\n\n        public string CloudProvider { get; set; }\n\n        public bool? Enabled { get; set; } = null;\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Telemetry.ElasticApm.Tests/Settings/IElasticApmSettings.cs",
    "content": "﻿namespace Liquid.Core.Telemetry.ElasticApm.Tests.Settings\n{\n    internal interface IElasticApmSettings\n    {\n        string ServerUrl { get; set; }\n\n        string SecretToken { get; set; }\n\n        double TransactionSampleRate { get; set; }\n\n        string CloudProvider { get; set; }\n\n        bool? Enabled { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Cache/IServiceCollectionExtensionTests.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Caching.Distributed;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing System.Linq;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Cache\n{\n    public class IServiceCollectionExtensionTests\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n        private readonly IDistributedCache _distributedCache = Substitute.For<IDistributedCache>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidDistributedCache_WhenWithTelemetryTrue_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddSingleton(_distributedCache);\n            _sut.AddLogging();\n            _sut.AddLiquidDistributedCache(true);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n\n        }\n\n        [Fact]\n        public void AddLiquidDistributedCache_WhenWithTelemetryfalse_GetServicesReturnLiqudCache()\n        {\n            SetCollection();\n            _sut.AddSingleton(_distributedCache);\n            _sut.AddLiquidDistributedCache(false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<ILiquidCache>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidCache) && x.Lifetime == ServiceLifetime.Scoped));\n\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Cache/LiquidCacheTests.cs",
    "content": "using Liquid.Core.Extensions;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.Caching.Distributed;\nusing NSubstitute;\nusing System;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Cache\n{\n    public class LiquidCacheTests\n    {\n        private readonly IDistributedCache _distributedCache = Substitute.For<IDistributedCache>();\n        private readonly LiquidCache _sut;\n\n        public LiquidCacheTests()\n        {\n            _sut = new LiquidCache(_distributedCache);\n        }\n        [Fact]\n        public void Ctor_WhenIDistributedCacheIsNull_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new LiquidCache(null));\n        }\n\n        [Fact]\n        public void GetByteArray_WhenKeyExists_ThenReturnByteArray()\n        {\n            //Arrange\n            var bytes = new byte[] { 1, 2, 3, 4, 5 };\n            _distributedCache.Get(Arg.Any<string>()).Returns(bytes);\n\n            //Act\n            var result = _sut.Get(\"test\");\n\n            //Assert\n            Assert.Equal(bytes, result);\n        }\n\n        [Fact]\n        public async Task GetAsyncByteArray_WhenKeyExists_ThenReturnByteArray()\n        {\n            //Arrange\n            var bytes = new byte[] { 1, 2, 3, 4, 5 };\n            _distributedCache.GetAsync(Arg.Any<string>()).Returns(bytes);\n\n            //Act\n            var result = await _sut.GetAsync(\"test\");\n\n            //Assert\n            Assert.Equal(bytes, result);\n\n        }\n\n        [Fact]\n        public void GetComplexType_WhenKeyExists_ThenReturnType()\n        {\n            //Arrange\n            var values = new MockType();\n            _distributedCache.Get(Arg.Any<string>()).Returns(values.ToJsonBytes());\n\n            //Act\n            var result = _sut.Get<MockType>(\"test\");\n\n            //Assert\n            Assert.IsType<MockType>(result);\n        }\n\n        [Fact]\n        public async Task GetAsyncComplexType_WhenKeyExists_ThenReturnType()\n        {\n            //Arrange\n            var values = new MockType();\n            _distributedCache.GetAsync(Arg.Any<string>()).Returns(values.ToJsonBytes());\n\n            //Act\n            var result = await _sut.GetAsync<MockType>(\"test\");\n\n            //Assert\n            Assert.IsType<MockType>(result);\n\n        }\n\n        [Fact]\n        public void GetPrimitiveType_WhenKeyExists_ThenReturnPrimitive()\n        {\n            //Arrange\n            var values = false;\n            _distributedCache.Get(Arg.Any<string>()).Returns(values.ToJsonBytes());\n\n            //Act\n            var result = _sut.Get<bool>(\"test\");\n\n            //Assert\n            Assert.IsType<bool>(result);\n            Assert.Equal(values, result);\n        }\n\n        [Fact]\n        public async Task GetAsyncPrimitiveType_WhenKeyExists_ThenReturnPrimitive()\n        {\n            //Arrange\n            var values = true;\n            _distributedCache.GetAsync(Arg.Any<string>()).Returns(values.ToJsonBytes());\n\n            //Act\n            var result = await _sut.GetAsync<bool>(\"test\");\n\n            //Assert\n            Assert.IsType<bool>(result);\n            Assert.Equal(values, result);\n        }\n\n        [Fact]\n        public void GetGuid_WhenKeyExists_ThenReturnGuid()\n        {\n            //Arrange\n            var values = new Guid();\n            _distributedCache.Get(Arg.Any<string>()).Returns(values.ToJsonBytes());\n\n            //Act\n            var result = _sut.Get<Guid>(\"test\");\n\n            //Assert\n            Assert.IsType<Guid>(result);\n            Assert.Equal(values, result);\n        }\n\n        [Fact]\n        public async Task GetAsyncGuid_WhenKeyExists_ThenReturnGuid()\n        {\n            //Arrange\n            var values = new Guid();\n            _distributedCache.GetAsync(Arg.Any<string>()).Returns(values.ToJsonBytes());\n\n            //Act\n            var result = await _sut.GetAsync<Guid>(\"test\");\n\n            //Assert\n            Assert.IsType<Guid>(result);\n            Assert.Equal(values, result);\n        }\n\n        [Fact]\n        public void SetByteArray_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var bytes = new byte[] { 1, 2, 3, 4, 5 };\n\n            //Act\n            _sut.Set(\"test\", bytes, default);\n\n            //Assert\n\n            _distributedCache.Received(1).Set(\"test\", bytes, Arg.Any<DistributedCacheEntryOptions>());\n        }\n\n        [Fact]\n        public async Task SetAsyncByteArray_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var bytes = new byte[] { 1, 2, 3, 4, 5 };\n\n            //Act\n            await _sut.SetAsync(\"test\", bytes, default);\n\n            //Assert\n            await _distributedCache.Received(1).SetAsync(\"test\", bytes, Arg.Any<DistributedCacheEntryOptions>());\n\n        }\n\n        [Fact]\n        public void SetComplexType_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var values = new MockType();\n\n            //Act\n            _sut.Set(\"test\", values, default);\n\n            //Assert\n\n            _distributedCache.Received(1).Set(\"test\", Arg.Any<byte[]>(), Arg.Any<DistributedCacheEntryOptions>());\n        }\n\n        [Fact]\n        public async Task SetAsyncComplexType_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var values = new MockType();\n\n            //Act\n            await _sut.SetAsync(\"test\", values, default);\n\n            //Assert\n            await _distributedCache.Received(1).SetAsync(\"test\", Arg.Any<byte[]>(), Arg.Any<DistributedCacheEntryOptions>());\n\n        }\n\n        [Fact]\n        public void SetPrimitiveType_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var values = \"Test value\";\n\n            //Act\n            _sut.Set(\"test\", values, default);\n\n            //Assert\n\n            _distributedCache.Received(1).Set(\"test\", Arg.Any<byte[]>(), Arg.Any<DistributedCacheEntryOptions>());\n        }\n\n        [Fact]\n        public async Task SetAsyncPrimitiveType_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var values = \"Test value\";\n\n            //Act\n            await _sut.SetAsync(\"test\", values, default);\n\n            //Assert\n            await _distributedCache.Received(1).SetAsync(\"test\", Arg.Any<byte[]>(), Arg.Any<DistributedCacheEntryOptions>());\n\n        }\n\n        [Fact]\n        public void SetGuid_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var values = new Guid();\n\n            //Act\n            _sut.Set(\"test\", values, default);\n\n            //Assert\n\n            _distributedCache.Received(1).Set(\"test\", Arg.Any<byte[]>(), Arg.Any<DistributedCacheEntryOptions>());\n        }\n\n        [Fact]\n        public async Task SetAsyncGuid_WhenSucessfullySet_ThenDistributeCacheSetReceivedCall()\n        {\n            //Arrange\n            var values = new Guid();\n\n            //Act\n            await _sut.SetAsync(\"test\", values, default);\n\n            //Assert\n            await _distributedCache.Received(1).SetAsync(\"test\", Arg.Any<byte[]>(), Arg.Any<DistributedCacheEntryOptions>());\n\n        }\n\n        [Fact]\n        public void Refresh_WhenSucessfull_ThenDistributeCacheRefreshReceivedCall()\n        {\n            //Arrange\n\n            //Act\n            _sut.Refresh(\"test\");\n\n            //Assert\n\n            _distributedCache.Received(1).Refresh(\"test\");\n        }\n\n        [Fact]\n        public async Task RefreshAsync_WhenSucessfull_ThenDistributeCacheRefreshAsyncReceivedCall()\n        {\n            //Arrange\n\n            //Act\n            await _sut.RefreshAsync(\"test\");\n\n            //Assert\n\n            await _distributedCache.Received(1).RefreshAsync(\"test\");\n\n        }\n\n        [Fact]\n        public void Remove_WhenSucessfull_ThenDistributeCacheRemoveReceivedCall()\n        {\n            //Arrange\n\n            //Act\n            _sut.Remove(\"test\");\n\n            //Assert\n\n            _distributedCache.Received(1).Remove(\"test\");\n        }\n\n        [Fact]\n        public async Task RemoveAsync_WhenSucessfull_ThenDistributeCacheRemoveAsyncReceivedCall()\n        {\n            //Arrange\n\n            //Act\n            await _sut.RemoveAsync(\"test\");\n\n            //Assert\n\n            await _distributedCache.Received(1).RemoveAsync(\"test\");\n\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test1/Test1Command.cs",
    "content": "﻿using MediatR;\n\nnamespace Liquid.Domain.Tests.CommandHandlers.Test1\n{\n    public class Test1Command : IRequest<Test1Response>\n    {\n        \n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test1/Test1CommandHandler.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing AutoMapper;\nusing MediatR;\n\nnamespace Liquid.Domain.Tests.CommandHandlers.Test1\n{\n    public class Test1CommandHandler : IRequestHandler<Test1Command, Test1Response>\n    {\n        public async Task<Test1Response> Handle(Test1Command request, CancellationToken cancellationToken)\n        {\n            return await Task.FromResult(new Test1Response());\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test1/Test1Response.cs",
    "content": "﻿namespace Liquid.Domain.Tests.CommandHandlers.Test1\n{\n    public class Test1Response\n    {\n        \n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test2/Test2Command.cs",
    "content": "﻿using System.Text.Json.Serialization;\nusing MediatR;\n\nnamespace Liquid.Domain.Tests.CommandHandlers.Test2\n{\n    public class Test2Command : IRequest<Test2Response>\n    {\n        [JsonPropertyName(\"id\")]\n        public int Id { get; set; }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test2/Test2CommandHandler.cs",
    "content": "﻿using System.Threading;\nusing System.Threading.Tasks;\nusing AutoMapper;\nusing MediatR;\n\nnamespace Liquid.Domain.Tests.CommandHandlers.Test2\n{\n    public class Test2CommandHandler : IRequestHandler<Test2Command, Test2Response>\n    {\n        public async Task<Test2Response> Handle(Test2Command request, CancellationToken cancellationToken)\n        {\n            return await Task.FromResult(new Test2Response());\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test2/Test2CommandValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace Liquid.Domain.Tests.CommandHandlers.Test2\n{\n    public class Test2CommandValidator : AbstractValidator<Test2Command>\n    {\n        public Test2CommandValidator()\n        {\n            RuleFor(command => command.Id).GreaterThan(0);\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/CommandHandlers/Test2/Test2Response.cs",
    "content": "﻿namespace Liquid.Domain.Tests.CommandHandlers.Test2\n{\n    public class Test2Response\n    {\n        \n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/IServiceCollectionLiquidExtensionTest.cs",
    "content": "﻿using Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing NSubstitute;\nusing System.Linq;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class IServiceCollectionLiquidExtensionTest\n    {\n        private IServiceCollection _sut;\n\n        [Fact]\n        [System.Obsolete(\"The extension method AddLiquidTelemetryInterceptor<IMockService, MockInterceptService>() is obsolete, so is this!\")]\n        public void AddLiquidTelemetryInterceptor_WhenSuccessfullyInjectsInterceptor_GetServiceSuccessfully()\n        {\n            SetCollection();\n\n            _sut.AddLiquidTelemetryInterceptor<IMockService, MockInterceptService>();\n\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IMockService) && x.Lifetime == ServiceLifetime.Transient));\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IMockService>());\n        }\n\n        [Fact]\n        public void AddScopedLiquidTelemetry_WhenSuccessfullyInjectsInterceptor_GetServiceSuccessfully()\n        {\n            SetCollection();\n\n            _sut.AddScopedLiquidTelemetry<IMockService, MockInterceptService>();\n\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IMockService) && x.Lifetime == ServiceLifetime.Scoped));\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IMockService>());\n        }\n\n        private void SetCollection()\n        {\n            _sut = new ServiceCollection();\n            _sut.AddSingleton<MockInterceptService>();\n            _sut.AddSingleton(Substitute.For<ILogger<LiquidTelemetryInterceptor>>());\n        }\n\n        [Fact]\n        public void AddSingletonLiquidTelemetry_WhenSuccessfullyInjectsInterceptor_GetServiceSuccessfully()\n        {\n            SetCollection();\n\n            _sut.AddSingletonLiquidTelemetry<IMockService, MockInterceptService>();\n\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IMockService) && x.Lifetime == ServiceLifetime.Singleton));\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IMockService>());\n        }\n\n        [Fact]\n        public void AddTransientLiquidTelemetry_WhenSuccessfullyInjectsInterceptor_GetServiceSuccessfully()\n        {\n            SetCollection();\n\n            _sut.AddTransientLiquidTelemetry<IMockService, MockInterceptService>();\n\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IMockService) && x.Lifetime == ServiceLifetime.Transient));\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IMockService>());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LiquidContextNotificationsTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class LiquidContextNotificationsTest\n    {\n        private ILiquidContextNotifications _sut;\n\n        public LiquidContextNotificationsTest()\n        {\n            _sut = new LiquidContextNotifications(new LiquidContext());\n        }\n\n        private void InitializeNotifications()\n        {\n            _sut.InsertNotification(\"initialize notifications\");\n        }\n\n        [Fact]\n        public void InsertNotificaton_WhenContextHasNoNotifications_Inserted()\n        {\n            _sut.InsertNotification(\"test case\");\n\n            var result = _sut.GetNotifications();\n\n            Assert.True(result.Count == 1);\n            Assert.True(result.Contains(\"test case\"));\n        }\n\n        [Fact]\n        public void InsertNotification_WhenContextHasNotifications_Inserted()\n        {\n            InitializeNotifications();\n\n            _sut.InsertNotification(\"test case 2\");\n\n            var result = _sut.GetNotifications();\n\n            Assert.True(result.Count > 1);\n            Assert.True(result.Contains(\"test case 2\"));\n        }\n\n        [Fact]\n        public void UpdateNotification_WhenNotificationTextAlredyExists_Inserted()\n        {\n            InitializeNotifications();\n\n            _sut.InsertNotification(\"test case\");\n\n            var result = _sut.GetNotifications();\n\n            Assert.True(result.Count > 1);\n            Assert.True(result.Contains(\"test case\"));\n        }\n\n        [Fact]\n        public void GetNotifications_WhenContexthasNone_ReturnNull()\n        {\n            var result = _sut.GetNotifications();\n\n            Assert.Null(result);\n        }\n\n        [Fact]\n        public void GetNotifications_WhenContexthasNotifications_ReturnNotifications()\n        {\n            InitializeNotifications();\n\n            var result = _sut.GetNotifications();\n\n            Assert.True(result.Count >= 1);\n            Assert.NotNull(result);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LiquidContextTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class LiquidContextTest\n    {\n        private ILiquidContext _sut;\n        public LiquidContextTest()\n        {\n            _sut = new LiquidContext();\n            _sut.Upsert(\"teste\", 123);\n        }\n\n        [Fact]\n        public void UpsertKey_WhenContextIsEmpty_KeyInserted()\n        {\n            var sut = new LiquidContext();\n\n            sut.Upsert(\"teste\", 123);\n\n            Assert.True((int)sut.current[\"teste\"] == 123);\n        }\n\n        [Fact]\n        public void UpsertKey_WhenInsertNewKey_NewKeyInserted()\n        {\n            _sut.Upsert(\"case2\", 456);\n\n            Assert.True((int)_sut.current[\"teste\"] == 123);\n            Assert.True((int)_sut.current[\"case2\"] == 456);\n            Assert.True(_sut.current.Count == 2);\n        }\n\n        [Fact]\n        public void UpsertKey_WhenUpdateKey_KeyUpdated()\n        {\n            _sut.Upsert(\"teste\", 456);\n\n            Assert.True((int)_sut.current[\"teste\"] == 456);\n            Assert.True(_sut.current.Count == 1);\n        }\n\n        [Fact]\n        public void Get_WhenKeyExists_ReturnValue()\n        {\n            var result = _sut.Get(\"teste\");\n\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public void Get_WhenKeyDoesntExist_ReturnNull()\n        {\n            var result = _sut.Get(\"case3\");\n\n            Assert.Null(result);\n\n        }\n\n        [Fact]\n        public void Get_WhenCurrentHasNoItens_ReturnNull()\n        {\n            var sut = new LiquidContext();\n\n            var result = sut.Get(\"teste\");\n\n            Assert.Null(result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LiquidJsonSerializerTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class LiquidJsonSerializerTest\n    {\n        private ILiquidSerializer _sut;\n\n        public LiquidJsonSerializerTest()\n        {\n            _sut = new LiquidJsonSerializer();\n        }\n\n        [Fact]\n        public void Serialize_WhenSerializeObject_ReturnJsonString()\n        {\n            var content = new { stringProperty = \"1\", intPropery = 2 };\n\n            var result = _sut.Serialize(content);\n\n            Assert.NotNull(result);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LiquidSerializerProviderTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class LiquidSerializerProviderTest\n    {\n        private ILiquidSerializerProvider _sut;\n\n        private List<ILiquidSerializer> _serializers;\n\n        public LiquidSerializerProviderTest()\n        {\n            _serializers = new List<ILiquidSerializer>();\n\n            _serializers.Add(new LiquidJsonSerializer());\n\n            _sut = new LiquidSerializerProvider(_serializers);\n        }\n\n        [Fact]\n        public void GetSerializerByType_WhenServiceTypeExists_ReturnService()\n        {\n            var result = _sut.GetSerializerByType(typeof(LiquidJsonSerializer));\n\n            Assert.NotNull(result);\n            Assert.Equal(typeof(LiquidJsonSerializer), result.GetType());\n        }\n\n        [Fact]\n        public void GetSerializerByType_WhenServiceTypeDoesntExists_ReturnNull()\n        {\n            var result = _sut.GetSerializerByType(typeof(LiquidXmlSerializer));\n\n            Assert.Null(result);\n        }\n\n        [Fact]\n        public void Ctor_WhenArgumentIsNull_ThrowException()\n        {\n            IEnumerable<ILiquidSerializer> serializers = default;\n\n            Assert.Throws<ArgumentNullException>(() => new LiquidSerializerProvider(serializers));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LiquidTelemetryInterceptorTest.cs",
    "content": "﻿using Castle.DynamicProxy;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.Logging;\nusing NSubstitute;\nusing System;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class LiquidTelemetryInterceptorTest\n    {\n        private LiquidTelemetryInterceptor _sut;\n        private IMockService _input;\n        private ILogger<LiquidTelemetryInterceptor> _logger;\n\n        public LiquidTelemetryInterceptorTest()\n        {\n            var generator = new ProxyGenerator();\n\n            var logger = Substitute.For<ILogger<MockService>>();\n\n            IMockService service = new MockService(logger);\n\n            _logger = Substitute.For<ILogger<LiquidTelemetryInterceptor>>();\n\n            _sut = new LiquidTelemetryInterceptor(_logger);\n\n            _input = generator.CreateInterfaceProxyWithTarget(service, _sut);\n\n        }\n\n        [Fact]\n        public async Task Intercept_WhenMethodExecutionIsSucessfull_LogStarEnd()\n        {\n            await _input.Get();\n\n            _logger.Received(2);\n\n        }\n\n        [Fact]\n        public async Task Intercept_WhenMethodExecutionThrowsException_LogStarExceptionAndEnd()\n        {\n            await Assert.ThrowsAsync<NotImplementedException>(() => _input.GetError());\n\n            _logger.Received(3);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LiquidXmlSerializerTest.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Tests.Mocks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Core\n{\n    public class LiquidXmlSerializerTest\n    {\n        private ILiquidSerializer _sut;\n\n        public LiquidXmlSerializerTest()\n        {\n            _sut = new LiquidXmlSerializer();\n        }\n\n        [Fact]\n        public void Serialize_WhenContentTyped_ReturnXmlString()\n        {\n            var content = new MockSerializeObject(1, \"2\");\n\n            var result = _sut.Serialize(content);\n\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public void Serialize_WhenContentIsAnonymous_ThrowException()\n        {\n            var content = new { stringProperty = \"1\", intPropery = 2 };\n\n            Assert.Throws<SerializerFailException>(() => _sut.Serialize(content));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Core/LocalizationTest.cs",
    "content": "﻿namespace Liquid.Core.Tests.Core\n{\n    public class LocalizationTest\n    {\n        //private const string StringValueKey = \"stringValueKey\";\n        //private ILocalization _subjectUnderTest;\n        //private IServiceProvider _serviceProvider;\n\n        //public LocalizationTest()\n        //{\n        //    IServiceCollection services = new ServiceCollection();\n        //    var builder = new ConfigurationBuilder();\n\n        //    builder.AddJsonFile(\"appsettings.json\");\n\n        //    var config = builder.Build();\n        //    services.AddSingleton(config);\n\n        //    services.AddLiquidConfiguration();\n        //    services.AddLocalizationService();\n        //    _serviceProvider = services.BuildServiceProvider();\n\n\n        //    var cultureInfo = new CultureInfo(\"pt-BR\");\n        //    Thread.CurrentThread.CurrentCulture = cultureInfo;\n        //    Thread.CurrentThread.CurrentUICulture = cultureInfo;\n        //    _subjectUnderTest = _serviceProvider.GetService<ILocalization>();\n        //}\n\n        ///// <summary>\n        ///// Asserts if can read string from cache.\n        ///// </summary>\n        //[Fact]\n        //public void Verify_if_can_read_string_from_file()\n        //{\n        //    var stringValue = _subjectUnderTest.Get(StringValueKey);\n        //    Assert.Equal(\"Texto em português\", stringValue);\n        //    stringValue = _subjectUnderTest.Get(StringValueKey, \"android\");\n        //    Assert.Equal(\"Texto em português\", stringValue);\n        //    stringValue = _subjectUnderTest.Get(StringValueKey, new CultureInfo(\"en-US\"));\n        //    Assert.Equal(\"English text\", stringValue);\n        //    stringValue = _subjectUnderTest.Get(StringValueKey, new CultureInfo(\"es-ES\"), \"iphone\");\n        //    Assert.Equal(\"texto en español\", stringValue);\n        //    stringValue = _subjectUnderTest.Get(\"InexistentKey\");\n        //    Assert.Equal(\"InexistentKey\", stringValue);\n\n        //}\n\n        ///// <summary>\n        ///// Verifies exceptions.\n        ///// </summary>\n        //[Fact]\n        //public void Verify_Exceptions()\n        //{\n        //    Assert.Throws<ArgumentNullException>(() => { _serviceProvider.GetService<ILocalization>().Get(StringValueKey, (CultureInfo)null); });\n        //    Assert.Throws<ArgumentNullException>(() => { _serviceProvider.GetService<ILocalization>().Get(null); });\n        //}\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Domain/RequestHandlerTest.cs",
    "content": "﻿using FluentValidation;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.PipelineBehaviors;\nusing Liquid.Domain.Tests.CommandHandlers.Test1;\nusing Liquid.Domain.Tests.CommandHandlers.Test2;\nusing MediatR;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.DependencyInjection.Extensions;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Logging.Configuration;\nusing Microsoft.Extensions.Logging.Console;\nusing NSubstitute;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Domain\n{\n    /// <summary>\n    /// Base Command Handler Test Class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Test.Base.TestTemplateContext{Liquid.Domain.Tests.TestEntities.TestCommandHandler}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class RequestHandlerTest\n    {\n        private IServiceProvider _serviceProvider;\n        private ILogger<LiquidTelemetryBehavior<Test1Command, Test1Response>> _logger = Substitute.For<ILogger<LiquidTelemetryBehavior<Test1Command, Test1Response>>>();\n        private ILogger<LiquidTelemetryBehavior<Test2Command, Test2Response>> _logger2 = Substitute.For<ILogger<LiquidTelemetryBehavior<Test2Command, Test2Response>>>();\n\n\n        public RequestHandlerTest()\n        {\n            var services = new ServiceCollection();\n            services.TryAddEnumerable(ServiceDescriptor.Singleton<ILoggerProvider, ConsoleLoggerProvider>());\n\n            LoggerProviderOptions.RegisterProviderOptions<ConsoleLoggerOptions, ConsoleLoggerProvider>(services);\n#pragma warning disable CS0618\n            services.Configure(new Action<ConsoleLoggerOptions>(options => options.DisableColors = false));\n\n#pragma warning restore CS0618\n            services.AddSingleton(LoggerFactory.Create(builder => { builder.AddConsole(); }));\n\n            services.AddTransient((s) => _logger);\n\n            services.AddTransient((s) => _logger2);\n\n            services.AddLiquidHandlers(true, true, GetType().Assembly);\n\n            _serviceProvider = services.AddLogging().BuildServiceProvider();\n        }\n\n        [Fact]\n        public async Task Test_WhenCommandHasntValidator_Sucess()\n        {\n            var mediator = _serviceProvider.GetRequiredService<IMediator>();\n\n            using var scopedTransaction = _serviceProvider.CreateScope();\n            var response = await mediator.Send(new Test1Command());\n\n            _logger.Received(2);\n\n            Assert.NotNull(response);\n        }\n\n        [Fact]\n        public async Task Test_WhenValidatorPassed_Sucess()\n        {\n            var mediator = _serviceProvider.GetRequiredService<IMediator>();\n\n            using var scopedTransaction2 = _serviceProvider.CreateScope();\n            var response2 = await mediator.Send(new Test2Command { Id = 1 });\n\n            Assert.NotNull(response2);\n            _logger2.Received(2);\n        }\n\n        [Fact]\n        public async Task Test_WhenValidatorThrowError_ThowException()\n        {\n            await Assert.ThrowsAsync<ValidationException>(async () =>\n            {\n                var mediator = _serviceProvider.GetRequiredService<IMediator>();\n                using var scopedTransaction = _serviceProvider.CreateScope();\n                await mediator.Send(new Test2Command { Id = -1 });\n            });\n\n            _logger2.Received(3);\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/Liquid.Core.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|AnyCPU'\">\n    <DocumentationFile></DocumentationFile>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"AutoFixture\" Version=\"4.18.1\" />\n    <PackageReference Include=\"Microsoft.Extensions.Configuration.Json\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.Extensions.Logging.Console\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Core\\Liquid.Core.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <None Update=\"appsettings.json\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"client.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"config.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n    <None Update=\"tls.ncconf\">\n      <CopyToOutputDirectory>Always</CopyToOutputDirectory>\n    </None>\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Messaging/IServiceCollectionExtensionTest.cs",
    "content": "﻿using Liquid.Core.Decorators;\nusing Liquid.Core.Extensions.DependencyInjection;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.Core.Tests.Mocks;\nusing MediatR;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing System;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Messaging\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _services;\n        private IServiceProvider _serviceProvider;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        public IServiceCollectionExtensionTest()\n        {\n            _services = new ServiceCollection();\n        }\n\n\n        [Fact]\n        public void AddLiquidWorkerService_WhenAdded_ServiceProvideCanResolveHostedService()\n        {\n            _services.AddSingleton(Substitute.For<ILiquidConsumer<EntityMock>>());\n            _services.AddLiquidWorkerService<WorkerMock, EntityMock>();\n            _serviceProvider = _services.BuildServiceProvider();\n\n            Assert.NotNull(_serviceProvider.GetService<ILiquidWorker<EntityMock>>());\n            Assert.NotNull(_serviceProvider.GetService<ILiquidConsumer<EntityMock>>());\n            Assert.NotNull(_serviceProvider.GetService<IHostedService>());\n        }\n\n        [Fact]\n        public void AddLiquidDomain_WhenAdded_ServiceProviderCanResolveMediatorService()\n        {\n            _services.AddLiquidDomain(typeof(CommandRequestMock).Assembly);\n            _serviceProvider = _services.BuildServiceProvider();\n\n            Assert.NotNull(_serviceProvider.GetService<IMediator>());\n        }\n\n        [Fact]\n        public void AddLiquidPipeline_WhenAdded_ServiceProviderCanResolveLiquidWorkerService()\n        {\n            ConfigureServices();\n\n            _services.AddSingleton<ILiquidWorker<EntityMock>, WorkerMock>();\n            _services.AddSingleton(Substitute.For<ILiquidConsumer<EntityMock>>());\n\n            _services.AddLiquidPipeline<EntityMock>();\n            _serviceProvider = _services.BuildServiceProvider();\n\n            Assert.NotNull(_serviceProvider.GetService<ILiquidWorker<EntityMock>>());\n        }\n        [Fact]\n        public void AddLiquidMessageConsumer_WhenAdded_ServiceProviderCanResolveLiquidMessagingConsumerServices()\n        {\n            ConfigureServices();\n\n            _services.AddSingleton(Substitute.For<ILiquidConsumer<EntityMock>>());\n\n            _services.AddLiquidMessageConsumer<WorkerMock, EntityMock>(typeof(CommandRequestMock).Assembly);\n\n            _serviceProvider = _services.BuildServiceProvider();\n\n            Assert.NotNull(_serviceProvider.GetService<ILiquidWorker<EntityMock>>());\n            Assert.NotNull(_serviceProvider.GetService<IHostedService>());\n            Assert.NotNull(_serviceProvider.GetService<IMediator>());\n        }\n\n        private void ConfigureServices()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _services.AddSingleton(_configProvider);\n            _services.AddSingleton(Substitute.For<IOptions<ScopedContextSettings>>());\n            _services.AddSingleton(Substitute.For<IOptions<ScopedLoggingSettings>>());\n            _services.AddSingleton(Substitute.For<IOptions<CultureSettings>>());\n            _services.AddSingleton(Substitute.For<IOptions<ScopedContextSettings>>());\n            _services.AddSingleton(Substitute.For<IOptions<ScopedLoggingSettings>>());\n            _services.AddSingleton(Substitute.For<IOptions<CultureSettings>>());\n            _services.AddSingleton(Substitute.For<ILogger<LiquidScopedLoggingDecorator<EntityMock>>>());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Messaging/LiquidBackgroundServiceTest.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Messaging\n{\n    public class LiquidBackgroundServiceTest : LiquidBackgroundService<EntityMock>\n    {\n        private static ILiquidConsumer<EntityMock> _consumer = Substitute.For<ILiquidConsumer<EntityMock>>();\n        private static IServiceProvider _serviceProvider = Substitute.For<IServiceProvider>();\n\n        public LiquidBackgroundServiceTest() : base(_serviceProvider, _consumer)\n        {\n\n        }\n\n        [Fact]\n        public void ExecuteAsync_WhenStart_ConsumerReceivedStartCall()\n        {\n            var task = base.ExecuteAsync(new CancellationToken());\n\n            _consumer.Received().RegisterMessageHandler();\n        }\n\n        [Fact]\n        public async Task ExecuteAsync_WhenStartFail_ThrowException()\n        {\n            _consumer.When(x =>\n            x.RegisterMessageHandler())\n                .Do((call) => throw new Exception());\n\n            var task = ExecuteAsync(new CancellationToken());\n\n            await Assert.ThrowsAsync<Exception>(() => task);\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenMessageProcessedSuccessfuly_WorkerReceiveCall()\n        {\n            var worker = Substitute.For<ILiquidWorker<EntityMock>>();\n\n            var sut = new LiquidBackgroundService<EntityMock>(GetProvider(worker), _consumer);\n\n            await sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>(), new CancellationToken());\n\n            await worker.Received(1).ProcessMessageAsync(Arg.Any<ConsumerMessageEventArgs<EntityMock>>(), Arg.Any<CancellationToken>());\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenMessageProcessedWithError_ThrowException()\n        {\n            var worker = Substitute.For<ILiquidWorker<EntityMock>>();\n            worker.When(x => x.ProcessMessageAsync(Arg.Any<ConsumerMessageEventArgs<EntityMock>>(), Arg.Any<CancellationToken>()))\n                .Do((call) => throw new Exception());\n\n            var sut = new LiquidBackgroundService<EntityMock>(GetProvider(worker), _consumer);\n\n            await Assert.ThrowsAsync<Exception>(() => sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>(), new CancellationToken()));\n        }\n        private static ServiceProvider GetProvider(ILiquidWorker<EntityMock> worker)\n        {\n            var services = new ServiceCollection();\n\n            services.AddSingleton(worker);\n\n            return services.BuildServiceProvider();\n        }\n\n    }\n\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Messaging/LiquidContextDecoratorTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.Core.Decorators;\nusing Liquid.Core.Exceptions;\nusing NSubstitute;\nusing System.Collections.Generic;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\nusing Liquid.Core.Tests.Mocks;\nusing Liquid.Core.Entities;\nusing Microsoft.Extensions.Options;\n\nnamespace Liquid.Core.Tests.Messaging\n{\n    public class LiquidContextDecoratorTest\n    {\n        private readonly ILiquidWorker<EntityMock> _inner;\n        private readonly ILiquidContext _context;\n        private readonly IOptions<ScopedContextSettings> _options;\n\n        public LiquidContextDecoratorTest()\n        {\n            _inner = Substitute.For<ILiquidWorker<EntityMock>>();\n            _context = new LiquidContext();\n            _options = Substitute.For<IOptions<ScopedContextSettings>>();\n\n            var settings = new ScopedContextSettings();\n            settings.Keys.Add(new ScopedKey() { KeyName = \"test\", Required = true });\n            settings.Culture = true;\n            _options.Value.Returns(settings);\n\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenHeaderHasRequiredContexKey_ContextKeyInserted()\n        {\n            var headers = new Dictionary<string, object>();\n            headers.Add(\"test\", \"sucess\");\n\n            var sut = new LiquidContextDecorator<EntityMock>(_inner, _context, _options);\n            await sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>() { Headers = headers }, new CancellationToken());\n\n            Assert.Equal(headers[\"test\"].ToString(), _context.current[\"test\"]);\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenHeaderHasntRequiredContexKey_ContextKeyInserted()\n        {\n\n            var sut = new LiquidContextDecorator<EntityMock>(_inner, _context, _options);\n\n            await Assert.ThrowsAsync<MessagingMissingContextKeysException>(() =>\n            sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>(), new CancellationToken()));\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenCultureTrue_ContextCultureCreated()\n        {\n            var headers = new Dictionary<string, object>();\n            headers.Add(\"test\", \"sucess\");\n\n            var sut = new LiquidContextDecorator<EntityMock>(_inner, _context, _options);\n            await sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>() { Headers = headers }, new CancellationToken());\n\n            Assert.Equal(_context.current[\"culture\"].ToString(), CultureInfo.CurrentCulture.Name);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Messaging/LiquidCultureDecoratorTest.cs",
    "content": "﻿using Liquid.Core.Decorators;\nusing Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing System.Globalization;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Messaging\n{\n    public class LiquidCultureDecoratorTest\n    {\n        private readonly IOptions<CultureSettings> _options;\n        private readonly ILiquidWorker<EntityMock> _inner;\n\n        public LiquidCultureDecoratorTest()\n        {\n            _inner = Substitute.For<ILiquidWorker<EntityMock>>();\n            _options = Substitute.For<IOptions<CultureSettings>>();\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_CultureSettingsIsNull_CurrentCultureNotChanged()\n        {\n            var settings = new CultureSettings();\n            _options.Value.Returns(settings);\n\n            var currentculture = CultureInfo.CurrentCulture.Name;\n\n            var sut = new LiquidCultureDecorator<EntityMock>(_inner, _options);\n\n            await sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>(), new CancellationToken());\n\n            Assert.Equal(currentculture, CultureInfo.CurrentCulture.Name);\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_CultureSettingsIsNotNull_CurrentCultureChanged()\n        {\n            var settings = new CultureSettings() { DefaultCulture = \"pt-BR\" };\n            _options.Value.Returns(settings);\n\n            var currentculture = CultureInfo.CurrentCulture.Name;\n\n            var sut = new LiquidCultureDecorator<EntityMock>(_inner, _options);\n\n            await sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>(), new CancellationToken());\n\n            Assert.NotEqual(currentculture, CultureInfo.CurrentCulture.Name);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Messaging/LiquidScopedLoggingDecoratorTest.cs",
    "content": "﻿using Liquid.Core.Decorators;\nusing Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.Logging;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Messaging\n{\n    public class LiquidScopedLoggingDecoratorTest\n    {\n        private readonly ILogger<LiquidScopedLoggingDecorator<EntityMock>> _logger;\n        private readonly IOptions<ScopedLoggingSettings> _options;\n        private readonly ILiquidWorker<EntityMock> _inner;\n\n\n        public LiquidScopedLoggingDecoratorTest()\n        {\n            _logger = Substitute.For<ILogger<LiquidScopedLoggingDecorator<EntityMock>>>();\n            _options = Substitute.For<IOptions<ScopedLoggingSettings>>();\n            _inner = Substitute.For<ILiquidWorker<EntityMock>>();\n\n            var settings = new ScopedLoggingSettings();\n            settings.Keys.Add(new ScopedKey() { KeyName = \"test\", Required = true });\n\n            _options.Value.Returns(settings);\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenHeaderHasRequiredScopedLoggingKey_ScopeCreated()\n        {\n            var headers = new Dictionary<string, object>();\n            headers.Add(\"test\", \"sucess\");\n\n            var sut = new LiquidScopedLoggingDecorator<EntityMock>(_inner, _options, _logger);\n            await sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>() { Headers = headers }, new CancellationToken());\n\n            _logger.Received().BeginScope(Arg.Any<Array>());\n        }\n\n        [Fact]\n        public async Task ProcessMessageAsync_WhenHeaderHasntRequiredScopedLoggingKey_ThrowMessagingException()\n        {\n\n            var sut = new LiquidScopedLoggingDecorator<EntityMock>(_inner, _options, _logger);\n\n            await Assert.ThrowsAsync<MessagingMissingScopedKeysException>(() =>\n           sut.ProcessMessageAsync(new ConsumerMessageEventArgs<EntityMock>(), new CancellationToken()));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/AnotherTestEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class AnotherTestEntity : LiquidEntity<int>\n    {\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/CommandHandlerMock.cs",
    "content": "﻿using MediatR;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    public class CommandHandlerMock : IRequestHandler<CommandRequestMock>\n    {\n        public async Task Handle(CommandRequestMock request, CancellationToken cancellationToken)\n        {\n            await Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/CommandRequestMock.cs",
    "content": "﻿using MediatR;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    public class CommandRequestMock : IRequest\n    {\n        public EntityMock Entity { get; set; }\n\n        public CommandRequestMock(EntityMock entity)\n        {\n            Entity = entity;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/EntityMock.cs",
    "content": "﻿namespace Liquid.Core.Tests.Mocks\n{\n    public class EntityMock\n    {\n        public int Property1 { get; set; }\n\n        public string Property2 { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/IMockService.cs",
    "content": "﻿using System.Threading.Tasks;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    public interface IMockService\n    {\n        Task<string> Get();\n        Task<string> GetError();\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/InMemoryRepository.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Linq.Expressions;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    [ExcludeFromCodeCoverage]\n    public class InMemoryRepository<TEntity, TIdentifier> : ILiquidRepository<TEntity, TIdentifier>, ILiquidDataContext where TEntity : LiquidEntity<TIdentifier>, new()\n    {\n        public ILiquidDataContext DataContext { get { return this; } }\n\n        public string Id { get; }\n\n        private Dictionary<TIdentifier, TEntity> _inMemoryRepository;\n        private Dictionary<TIdentifier, TEntity> _inMemoryTempTransactionRepository;\n\n        private bool disposedValue;\n\n        public InMemoryRepository()\n        {\n            _inMemoryRepository = new Dictionary<TIdentifier, TEntity>();\n        }\n\n        public async Task AddAsync(TEntity entity)\n        {\n            await Task.FromResult(_inMemoryRepository.TryAdd(entity.Id, entity));\n        }\n\n        public async Task<IEnumerable<TEntity>> FindAllAsync()\n        {\n            var entities = await Task.FromResult<IEnumerable<TEntity>>(_inMemoryRepository.Values);\n            return entities;\n        }\n\n        public async Task<TEntity> FindByIdAsync(TIdentifier id)\n        {\n            var entity = await Task.FromResult(_inMemoryRepository.GetValueOrDefault(id));\n            return entity;\n        }\n\n        public async Task RemoveByIdAsync(TIdentifier id)\n        {\n            await Task.FromResult(_inMemoryRepository.Remove(id));\n        }\n\n        public async Task UpdateAsync(TEntity entity)\n        {\n            await Task.FromResult(_inMemoryRepository.Remove(entity.Id));\n            await Task.FromResult(_inMemoryRepository.TryAdd(entity.Id, entity));\n        }\n\n        public async Task<IEnumerable<TEntity>> WhereAsync(Expression<Func<TEntity, bool>> whereClause)\n        {\n            var selectableCollection = _inMemoryRepository.Values.AsQueryable();\n            var entities = await Task.FromResult<IEnumerable<TEntity>>(selectableCollection.Where(whereClause));\n            return entities;\n        }\n\n        public async Task StartTransactionAsync()\n        {\n            _inMemoryTempTransactionRepository = await Task.FromResult(CloneRepository(_inMemoryRepository));\n        }\n\n        public async Task CommitAsync()\n        {\n            await Task.Run(() => { _inMemoryTempTransactionRepository = null; });\n        }\n\n        public async Task RollbackTransactionAsync()\n        {\n            _inMemoryRepository = await Task.FromResult(CloneRepository(_inMemoryTempTransactionRepository));\n        }\n\n        protected virtual void Dispose(bool disposing)\n        {\n            if (!disposedValue)\n            {\n                if (disposing)\n                {\n                    _inMemoryRepository = null;\n                    _inMemoryTempTransactionRepository = null;\n                }\n\n                disposedValue = true;\n            }\n        }\n\n        public void Dispose()\n        {\n            Dispose(disposing: true);\n            GC.SuppressFinalize(this);\n        }\n\n        private Dictionary<TIdentifier, TEntity> CloneRepository(Dictionary<TIdentifier, TEntity> repoToClone)\n        {\n            var clone = new Dictionary<TIdentifier, TEntity>();\n            foreach (var key in repoToClone.Keys)\n            {\n                clone.Add(key, repoToClone[key]);\n            }\n\n            return clone;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/MockInterceptService.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    public class MockInterceptService : IMockService\n    {\n\n        public MockInterceptService()\n        {\n\n        }\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<string> Get()\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            return \"Test\";\n        }\n\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<string> GetError()\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/MockSerializeObject.cs",
    "content": "﻿namespace Liquid.Core.Tests.Mocks\n{\n    public class MockSerializeObject\n    {\n        public MockSerializeObject()\n        {\n\n        }\n\n        public MockSerializeObject(int intProperty, string stringProperty)\n        {\n            IntProperty = intProperty;\n            StringProperty = stringProperty;\n        }\n\n        public int IntProperty { get; set; }\n\n        public string StringProperty { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/MockService.cs",
    "content": "﻿using Microsoft.Extensions.Logging;\nusing System;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    public class MockService : IMockService\n    {\n        private readonly ILogger<MockService> _logger;\n        public MockService(ILogger<MockService> logger)\n        {\n            _logger = logger;\n        }\n        public MockService()\n        {\n\n        }\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<string> Get()\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            _logger.LogInformation(\"sucess\");\n            return \"Test\";\n        }\n\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<string> GetError()\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            throw new NotImplementedException();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/MockSettings.cs",
    "content": "﻿using Liquid.Core.Attributes;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    [LiquidSectionName(\"MockSettings\")]\n    public class MockSettings\n    {\n        public string MyProperty { get; set; }\n    }\n\n    public class MockNoAttributeSettings\n    {\n        public string MyProperty { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/MockType.cs",
    "content": "﻿namespace Liquid.Core.Tests.Mocks\n{\n    internal class MockType\n    {\n        public int PropInt { get; set; }\n        public string PropString { get; set; }\n\n        public bool PropBool { get; set; }\n        public MockType()\n        {\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/TestEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class TestEntity : LiquidEntity<int>\n    {\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Mocks/WorkerMock.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Core.Tests.Mocks\n{\n    public class WorkerMock : ILiquidWorker<EntityMock>\n    {\n        public WorkerMock()\n        {\n\n        }\n\n        public Task ProcessMessageAsync(ConsumerMessageEventArgs<EntityMock> args, CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/Repository/LiquidUnitOfWorkTests.cs",
    "content": "using Liquid.Core.Exceptions;\nusing Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Core.Tests.Mocks;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing NSubstitute;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Core.Tests.Repository\n{\n    [ExcludeFromCodeCoverage]\n    public class LiquidUnitOfWorkIntegrationTests\n    {\n        private IServiceProvider _serviceProvider;\n        private ILiquidUnitOfWork _unitOfWork;\n        private ILiquidRepository<TestEntity, int> _sut;\n\n        private readonly TestEntity _entity = new TestEntity()\n        {\n            CreatedDate = DateTime.Now,\n            Active = true,\n            Id = 1242,\n            MockTitle = \"test\"\n        };\n        private readonly TestEntity _updateEntity = new TestEntity()\n        {\n            CreatedDate = DateTime.Now,\n            Active = false,\n            Id = 1242,\n            MockTitle = \"test\"\n        };\n\n        \n        public LiquidUnitOfWorkIntegrationTests()\n        {\n            var services = new ServiceCollection();\n\n            services.AddSingleton(Substitute.For<ILogger<LiquidTelemetryInterceptor>>());\n\n            services.AddScoped<ILiquidRepository<TestEntity, int>, InMemoryRepository<TestEntity, int>>();\n\n            services.AddTransient<ILiquidUnitOfWork, LiquidUnitOfWork>();\n\n            _serviceProvider = services.BuildServiceProvider();\n\n            _unitOfWork = _serviceProvider.GetService<ILiquidUnitOfWork>();\n\n            _sut = _unitOfWork.GetRepository<ILiquidRepository<TestEntity, int>, TestEntity, int>();\n        }\n\n\n        [Fact]\n        public void LiquidUnitOfWorkConstructor_WhenServiceProviderDoesntExists_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new LiquidUnitOfWork(null));\n        }\n\n        [Fact]\n        public void GetRepository_WhenRepositoryDoesntExists_ThrowException()\n        {\n            Assert.Throws<NullReferenceException>(() => _unitOfWork.GetRepository<ILiquidRepository<AnotherTestEntity, int>, AnotherTestEntity, int>());\n        }\n\n        [Fact]\n        public void GetRepository_WhenRepositoryExists_Success()\n        {\n            var serviceProvider = new ServiceCollection()\n                .AddTransient<ILiquidUnitOfWork, LiquidUnitOfWork>()\n                .AddScoped<ILiquidRepository<TestEntity, int>, InMemoryRepository<TestEntity, int>>()\n                .BuildServiceProvider();\n\n            var unitOfWorkWithRepository = new LiquidUnitOfWork(serviceProvider);\n\n            Assert.IsAssignableFrom<ILiquidRepository<TestEntity, int>>(unitOfWorkWithRepository.GetRepository<ILiquidRepository<TestEntity, int>, TestEntity, int>());\n\n            unitOfWorkWithRepository.Dispose();\n        }\n\n        [Fact]\n        public async Task AddAsync_WhenCommitTransaction_ItemAdded()\n        {\n            await _unitOfWork.StartTransactionAsync();\n\n            await _sut.AddAsync(_entity);\n\n            await _unitOfWork.CommitAsync();\n\n            var result = await _sut.FindByIdAsync(1242);\n\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public async Task AddAsync_WhenRollbackTransaction_ItemNotInserted()\n        {\n            await _unitOfWork.StartTransactionAsync();\n\n            await _sut.AddAsync(_entity);\n\n            await _unitOfWork.RollbackTransactionAsync();\n\n            var result = await _sut.FindByIdAsync(1242);\n\n            Assert.Null(result);\n        }\n\n        [Fact]\n        public async Task RemoveByIdAsync_WhenCommitTransaction_ItemDeleted()\n        {\n            await _sut.AddAsync(_entity);\n\n            await _unitOfWork.StartTransactionAsync();\n\n            await _sut.RemoveByIdAsync(_entity.Id);\n\n            await _unitOfWork.CommitAsync();\n\n            var result = await _sut.WhereAsync(e => e.Id.Equals(_entity.Id));\n\n            Assert.False(result.Any());\n        }\n\n        [Fact]\n        public async Task RemoveByIdAsync_WhenRollbackTransaction_ItemNotDeleted()\n        {\n            await _sut.AddAsync(_entity);\n\n            await _unitOfWork.StartTransactionAsync();\n\n            await _sut.RemoveByIdAsync(_entity.Id);\n\n            await _unitOfWork.RollbackTransactionAsync();\n\n            var result = await _sut.FindByIdAsync(1242);\n\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public async Task UpdateAsync_WhenCommitTransaction_ItemNotDeleted()\n        {\n            await _sut.AddAsync(_entity);\n\n            await _unitOfWork.StartTransactionAsync();\n\n            await _sut.UpdateAsync(_updateEntity);\n\n            await _unitOfWork.CommitAsync();\n\n            var result = await _sut.FindByIdAsync(1242);\n\n            Assert.Equal(_updateEntity.Active, result.Active);\n        }\n\n        [Fact]\n        public async Task UpdateAsync_WhenRollbackTransaction_ItemNotDeleted()\n        {\n            await _sut.AddAsync(_entity);\n\n            await _unitOfWork.StartTransactionAsync();\n\n            await _sut.UpdateAsync(_updateEntity);\n\n            await _unitOfWork.RollbackTransactionAsync();\n\n            var result = await _sut.FindByIdAsync(1242);\n\n            Assert.Equal(_entity.Active, result.Active);\n        }\n\n        [Fact]\n        public async Task StartTransactionAsync_WhenDataContextDoesntExists_ThrowException()\n        {\n            var serviceProvider = new ServiceCollection()\n                .AddTransient<ILiquidUnitOfWork, LiquidUnitOfWork>()\n                .BuildServiceProvider();\n\n            var unitOfWorkWithoutRepository = new LiquidUnitOfWork(serviceProvider);\n\n            await Assert.ThrowsAsync<UnitofWorkTransactionWithoutRepositoryException>(async () => await unitOfWorkWithoutRepository.StartTransactionAsync());\n\n            unitOfWorkWithoutRepository.Dispose();\n        }\n\n        [Fact]\n        public async Task CommitAsync_WhenNoTransactionIsStarted_ThrowException()\n        {\n            await Assert.ThrowsAsync<UnitOfWorkTransactionNotStartedException>(async () => await _unitOfWork.CommitAsync());\n        }\n\n        [Fact]\n        public async Task RollbackTransactionAsync_WhenNoTransactionIsStarted_ThrowException()\n        {\n            await Assert.ThrowsAsync<UnitOfWorkTransactionNotStartedException>(async () => await _unitOfWork.RollbackTransactionAsync());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/appsettings.json",
    "content": "{\n  \"MockSettings\": {\n    \"MyProperty\": \"Liquid\"\n  },\n  \"MockNoAttributeSettings\": {\n    \"MyProperty\": \"Liquid\"\n  },\n  \"liquid\": {\n    \"culture\": {\n      \"defaultCulture\": \"pt-BR\"\n    }\n  }\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/client.ncconf",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n  <configuration>\n    <ncache-server connection-retries=\"3\" retry-connection-delay=\"0\" retry-interval=\"1\" command-retries=\"3\" command-retry-interval=\"0.1\" client-request-timeout=\"90\" connection-timeout=\"5\" port=\"9800\"/>\n    <cache id=\"myReplicatedCache\" client-cache-id=\"\" client-cache-syncmode=\"optimistic\" default-readthru-provider=\"\" default-writethru-provider=\"\" load-balance=\"True\"  enable-client-logs=\"False\" log-level=\"error\">\n      <server name=\"10.0.5.1\" />\n    </cache>\n  </configuration>\n"
  },
  {
    "path": "test/Liquid.Core.Tests/config.ncconf",
    "content": "<configuration>\n  <cache-config cache-name=\"myCache\" alias=\"\" config-id=\"e097c2c0-88af-4aa2-8a8a-c6432eeaa3fe\" config-version=\"0\" store-type=\"distributed-cache\">\n    <cache-settings inproc=\"True\" last-modified=\"\" auto-start=\"False\" data-format=\"Binary\">\n      <logging enable-logs=\"True\" trace-errors=\"True\" trace-notices=\"False\" trace-warnings=\"False\" trace-debug=\"False\" log-path=\"\"/>\n      <performance-counters enable-counters=\"True\" snmp-port=\"0\"/>\n      <data-load-balancing enabled=\"False\" auto-balancing-threshold=\"60%\" auto-balancing-interval=\"30sec\"/>\n      <compression enable-compression=\"False\" threshold=\"100kb\"/>\n      <client-death-detection/>\n      <client-activity-notification enabled=\"False\" retention-period=\"5sec\"/>\n      <cache-notifications item-remove=\"False\" item-add=\"False\" item-update=\"False\"/>\n      <cleanup interval=\"15sec\"/>\n      <storage type=\"heap\" cache-size=\"1024mb\"/>\n      <eviction-policy enabled-eviction=\"True\" default-priority=\"normal\" policy=\"lru\" eviction-ratio=\"5%\"/>\n      <expiration-policy enabled=\"False\">\n        <absolute-expiration longer-enabled=\"False\" longer-value=\"0\" default-enabled=\"False\" default-value=\"0\"/>\n        <sliding-expiration longer-enabled=\"False\" longer-value=\"0\" default-enabled=\"False\" default-value=\"0\"/>\n      </expiration-policy>\n      <cache-topology topology=\"local-cache\"/>\n      <tasks-config max-tasks=\"10\" chunk-size=\"100\" communicate-stats=\"False\" queue-size=\"10\" max-avoidable-exceptions=\"10\"/>\n      <split-brain-recovery enable=\"False\" detection-interval=\"60\"/>\n    </cache-settings>\n  </cache-config>\n\n\n</configuration>"
  },
  {
    "path": "test/Liquid.Core.Tests/localization.en-US.json",
    "content": "﻿{\n  \"items\": [\n    {\n      \"key\": \"stringValueKey\",\n      \"values\": [\n        {\n          \"value\": \"English text\"\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/localization.es-ES.json",
    "content": "﻿{\n  \"items\": [\n    {\n      \"key\": \"stringValueKey\",\n      \"values\": [\n        {\n          \"value\": \"texto en español\"\n        },\n        {\n          \"channels\": \"iphone\",\n          \"value\": \"texto en español\"\n        }\n      ]\n    }\n  ]\n}"
  },
  {
    "path": "test/Liquid.Core.Tests/localization.json",
    "content": "﻿{\n  \"items\": [\n    {\n      \"key\": \"stringValueKey\",\n      \"values\": [\n        {\n          \"channels\": \"web;android\",\n          \"value\": \"Texto em português\"\n        }\n      ]\n    }\n  ]\n}\n"
  },
  {
    "path": "test/Liquid.Core.Tests/tls.ncconf",
    "content": "<tls-info>\n\t<certificate-name>certificate-name</certificate-name>\t\n\t<certificate-thumbprint>your-thumbprint</certificate-thumbprint>\t\n\t<enable>false</enable>\n\t<enable-client-server-tls>false</enable-client-server-tls>\n\t<use-mutual-tls-for-client-to-server>false</use-mutual-tls-for-client-to-server>\n</tls-info>"
  },
  {
    "path": "test/Liquid.Dataverse.Tests/DataverseClientFactoryTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing NSubstitute;\n\nnamespace Liquid.Dataverse.Tests\n{\n    public class DataverseClientFactoryTests\n    {\n        private readonly IDataverseClientFactory _sut;\n        private readonly IOptions<DataverseSettings> _options;\n\n        public DataverseClientFactoryTests()\n        {\n            _options = Substitute.For<IOptions<DataverseSettings>>();\n            _options.Value.ReturnsForAnyArgs(new DataverseSettings() { ClientId = \"4erewgewgh\", ClientSecret = \"greggrbnte\", Url = \"https://test\" });\n            _sut = new DataverseClientFactory(_options);\n        }\n\n\n        [Fact]\n        public void Ctor_WhenOptionsIsNull_ThenReturnArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new DataverseClientFactory(null));\n        }\n\n        [Fact]\n        public void Ctor_WhenOptionsExists_ThenReturnDataverseClientFactoryInstance()\n        {\n            var result = new DataverseClientFactory(_options);\n            Assert.NotNull(result);\n            Assert.IsType<DataverseClientFactory>(result);\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Dataverse.Tests/Liquid.Dataverse.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.1.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.4.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.4.3\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"3.1.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Dataverse\\Liquid.Dataverse.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Dataverse.Tests/LiquidDataverseTests.cs",
    "content": "﻿using Microsoft.Crm.Sdk.Messages;\nusing Microsoft.PowerPlatform.Dataverse.Client;\nusing Microsoft.Xrm.Sdk;\nusing Microsoft.Xrm.Sdk.Messages;\nusing Microsoft.Xrm.Sdk.Metadata;\nusing Microsoft.Xrm.Sdk.Query;\nusing NSubstitute;\nusing NSubstitute.ReceivedExtensions;\n\nnamespace Liquid.Dataverse.Tests\n{\n    public class LiquidDataverseTests\n    {\n        private readonly IOrganizationServiceAsync _client;\n        private readonly ILiquidDataverse _sut;\n        public LiquidDataverseTests()\n        {\n            var clientFactory = Substitute.For<IDataverseClientFactory>();\n            _client = Substitute.For<IOrganizationServiceAsync>();\n\n            clientFactory.GetClient().Returns(_client);\n\n            _sut = new LiquidDataverse(clientFactory);\n        }\n\n        [Fact]\n        public void Ctor_WhenClientFactoryIsNull_ThrowArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new LiquidDataverse(null));\n        }\n\n        [Fact]\n        public async Task GetById_WhenClientReturnResults_ReturnEntity()\n        {\n            _client.RetrieveAsync(Arg.Any<string>(), Arg.Any<Guid>(), Arg.Any<ColumnSet>()).Returns(new Entity());\n\n            var guidId = Guid.NewGuid();\n\n            var result = await _sut.GetById(guidId, \"entityname\");\n\n            await _client.Received(1).RetrieveAsync(\"entityname\", guidId, Arg.Any<ColumnSet>());\n            Assert.NotNull(result);\n            Assert.IsType<Entity>(result);\n        }\n\n        [Fact]\n        public async Task ListByFilter_WhenUseFilterExpression_ReturnListOfEntities()\n        {\n            _client.RetrieveMultipleAsync(Arg.Any<QueryExpression>()).Returns(new EntityCollection());\n\n            var result = await _sut.ListByFilter(\"entityname\", new FilterExpression());\n\n            Assert.NotNull(result);\n            Assert.IsType<List<Entity>>(result);\n        }\n\n        [Fact]\n        public async Task ListByFilter_WhenUseQueryExpression_ReturnListOfEntities()\n        {\n            _client.RetrieveMultipleAsync(Arg.Any<QueryExpression>()).Returns(new EntityCollection());\n\n            var result = await _sut.ListByFilter(\"entityname\", new QueryExpression());\n\n            Assert.NotNull(result);\n            Assert.IsType<List<Entity>>(result);\n        }\n\n        [Fact]\n        public async Task GetMetadata_WhenEntityExists_ReturnEntityMetadataInstance()\n        {\n            var response = new RetrieveEntityResponse();\n            response.Results[\"EntityMetadata\"] = new EntityMetadata();\n            _client.ExecuteAsync(Arg.Any<RetrieveEntityRequest>()).Returns(response);\n\n            var result = await _sut.GetMetadata(\"entityname\");\n\n            Assert.NotNull(result);\n            Assert.IsType<EntityMetadata>(result);\n        }\n\n        [Fact]\n        public async Task SetState_WhenCallResultSucessfully_ExecuteAsyncMethodCalled()\n        {\n            _client.ExecuteAsync(Arg.Any<SetStateRequest>()).Returns(new OrganizationResponse());\n\n            var entity = new EntityReference();\n\n            await _sut.SetState(entity, \"1234\", \"1212\");\n\n            await _client.Received(1).ExecuteAsync(Arg.Any<SetStateRequest>());\n        }\n\n        [Fact]\n        public async Task Upsert_WhenCallResultSucessfully_ExecuteAsyncMethodCalled()\n        {\n            _client.ExecuteAsync(Arg.Any<UpsertRequest>()).Returns(new OrganizationResponse());\n\n            var entity = new Entity();\n\n            await _sut.Upsert(entity);\n\n            await _client.Received(1).ExecuteAsync(Arg.Any<UpsertRequest>());\n        }\n\n        [Fact]\n        public async Task Update_WithOptions_UseRightOrganizationRequestType_RequestParameters()\n        {\n            _client.UpdateAsync(Arg.Any<Entity>()).Returns(Task.CompletedTask);\n\n            var updatedEntity = new Entity();\n\n            await _sut.Update(updatedEntity, true, true, true);\n\n            await _client.Received(1).ExecuteAsync(Arg.Is<UpdateRequest>(ur =>\n            ur.Parameters.ContainsKey(\"BypassCustomPluginExecution\")\n            && ur.Parameters.ContainsKey(\"SuppressCallbackRegistrationExpanderJob\")\n            && ur.Parameters.ContainsKey(\"SuppressDuplicateDetection\")\n            ));\n        }\n\n        [Fact]\n        public async Task DeleteById_WithOptions_UseRightOrganizationRequestType_RequestParameters()\n        {\n            _client.DeleteAsync(Arg.Any<string>(), Arg.Any<Guid>()).Returns(Task.CompletedTask);\n\n            var guidId = Guid.NewGuid();\n\n            await _sut.Delete(guidId, \"entityname\", true, true);\n\n            await _client.Received(1).ExecuteAsync(Arg.Is<DeleteRequest>(dr =>\n            dr.Parameters.ContainsKey(\"BypassCustomPluginExecution\")\n            ));\n        }\n\n        [Fact]\n        public async Task Create_WithOptions_UseRightOrganizationRequestType_RequestParameters()\n        {\n            _client.Execute(Arg.Any<CreateRequest>()).Returns(new CreateResponse());\n\n            var result = await _sut.Create(new Entity(), false, false, true);\n\n            _client.Received(1).Execute(Arg.Is<CreateRequest>(cr =>\n            cr.Parameters.ContainsKey(\"BypassCustomPluginExecution\")\n            && cr.Parameters.ContainsKey(\"SuppressCallbackRegistrationExpanderJob\")\n            && cr.Parameters.ContainsKey(\"SuppressDuplicateDetection\")\n            ));\n\n            Assert.IsType<Guid>(result);\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Dataverse.Tests/Usings.cs",
    "content": "global using Xunit;"
  },
  {
    "path": "test/Liquid.GenAi.OpenAi.Tests/Liquid.GenAi.OpenAi.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.14.0-preview-25107-01\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.3.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.0\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.GenAi.OpenAi\\Liquid.GenAi.OpenAi.csproj\" />\n  </ItemGroup>\n\n  <ItemGroup>\n    <Using Include=\"Xunit\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.GenAi.OpenAi.Tests/OpenAiClientFactoryTests.cs",
    "content": "using Liquid.Core.Entities;\nusing Liquid.GenAi.OpenAi.Settings;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing OpenAI.Chat;\nusing System.Reflection;\n\nnamespace Liquid.GenAi.OpenAi.Tests\n{\n    public class OpenAiClientFactoryTests\n    {\n        private readonly IOptions<OpenAiOptions> _mockOptions;\n        private readonly OpenAiClientFactory _factory;\n\n        public OpenAiClientFactoryTests()\n        {\n            _mockOptions = Substitute.For<IOptions<OpenAiOptions>>();\n            _factory = new OpenAiClientFactory(_mockOptions);\n        }\n\n        [Fact]\n        public void Constructor_ShouldThrowArgumentNullException_WhenOptionsIsNull()\n        {\n            // Act & Assert\n            Assert.Throws<ArgumentNullException>(() => new OpenAiClientFactory(null));\n        }\n\n        [Fact]\n        public void GetOpenAIClient_ShouldThrowKeyNotFoundException_WhenNoSettingsForClientId()\n        {\n            // Arrange\n            _mockOptions.Value.Returns(new OpenAiOptions\n            {\n                Settings = new List<OpenAiSettings>()\n            });\n\n            // Act & Assert\n            Assert.Throws<KeyNotFoundException>(() => _factory.GetOpenAIClient(\"invalid-client-id\"));\n        }\n\n        [Fact]\n        public void GetOpenAIClient_ShouldReturnExistingClient_WhenClientAlreadyExists()\n        {\n            // Arrange\n            var clientId = \"test-client\";\n            var chatClient = Substitute.For<ChatClient>();\n            var clientDictionary = new ClientDictionary<ChatClient>(clientId, chatClient) { Executions = 0 };\n\n            var settings = new List<OpenAiSettings>\n            {\n                new OpenAiSettings { ClientId = clientId, Url = \"https://example.com\", Key = \"test-key\", DeploymentName = \"test-deployment\" }\n            };\n\n            _mockOptions.Value.Returns(new OpenAiOptions { Settings = settings });\n\n            // Simulate an existing client\n            _factory.GetType()\n                .GetField(\"_openAiClients\", BindingFlags.NonPublic | BindingFlags.Instance)\n                ?.SetValue(_factory, new List<ClientDictionary<ChatClient>> { clientDictionary });\n\n            // Act\n            var result = _factory.GetOpenAIClient(clientId);\n\n            // Assert\n            Assert.Equal(chatClient, result);\n            Assert.Equal(1, clientDictionary.Executions);\n        }\n\n        [Fact]\n        public void GetOpenAIClient_ShouldCreateAndReturnNewClient_WhenClientDoesNotExist()\n        {\n            // Arrange\n            var clientId = \"new-client\";\n            var settings = new List<OpenAiSettings>\n            {\n                new OpenAiSettings\n                {\n                    ClientId = clientId,\n                    Url = \"https://example.com\",\n                    Key = \"test-key\",\n                    DeploymentName = \"test-deployment\",\n                    MaxRetries = 3\n                }\n            };\n\n            _mockOptions.Value.Returns(new OpenAiOptions { Settings = settings });\n\n            // Act\n            var result = _factory.GetOpenAIClient(clientId);\n\n            // Assert\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public void CreateClient_ShouldThrowArgumentNullException_WhenSettingsIsNull()\n        {            \n            // Act & Assert\n            Assert.Throws<TargetInvocationException>(() => _factory.GetType()\n                .GetMethod(\"CreateClient\", BindingFlags.NonPublic | BindingFlags.Instance)\n                ?.Invoke(_factory, new object[] { null, \"test-client\" }));\n        }\n\n        [Fact]\n        public void CreateClient_ShouldThrowArgumentNullException_WhenSettingsIsEmpty()\n        {\n            // Act & Assert\n            Assert.Throws<TargetInvocationException>(() => _factory.GetType()\n                .GetMethod(\"CreateClient\", BindingFlags.NonPublic | BindingFlags.Instance)\n                ?.Invoke(_factory, [new List<OpenAiSettings>(), \"test-client\"]));\n\n        }\n\n        [Fact]\n        public void CreateClient_ShouldCreateClients_WhenValidSettingsProvided()\n        {\n            // Arrange\n            var clientId = \"test-client\";\n            var settings = new List<OpenAiSettings>\n            {\n                new OpenAiSettings\n                {\n                    ClientId = clientId,\n                    Url = \"https://example.com\",\n                    Key = \"test-key\",\n                    DeploymentName = \"test-deployment\",\n                    MaxRetries = 3\n                }\n            };\n\n            // Act\n            var result = _factory.GetType()\n                .GetMethod(\"CreateClient\", BindingFlags.NonPublic | BindingFlags.Instance)\n                ?.Invoke(_factory, new object[] { settings, clientId });\n\n            // Assert\n            Assert.NotNull(result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/IServiceCollectionExtensionTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.Kafka.Extensions.DependencyInjection;\nusing Liquid.Messaging.Kafka.Tests.Mock;\nusing Liquid.Messaging.Kafka.Tests.Mock.HandlerMock;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing NSubstitute;\nusing System.Linq;\nusing Xunit;\nnamespace Liquid.Messaging.Kafka.Tests\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidKafkaProducer_WhenSuccessfullyInjectProducer_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidKafkaProducer<MessageMock>(\"test\");\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IKafkaFactory>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidProducer<MessageMock>) && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n        [Fact]\n        public void AddLiquidKafkaProducer_WhenSuccessfullyInjectWhitoutTelemetry_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidKafkaProducer<MessageMock>(\"test\", false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IKafkaFactory>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidProducer<MessageMock>) && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n        [Fact]\n        public void AddLiquidKafkaConsumer_WhenSuccessfullyInjectConsumer_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidKafkaConsumer<WorkerMock, MessageMock>(\"test\");\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IKafkaFactory>());\n            Assert.NotNull(provider.GetService<ILiquidWorker<MessageMock>>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IHostedService)\n            && x.ImplementationType == typeof(LiquidBackgroundService<MessageMock>)));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidConsumer<MessageMock>)\n            && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n        [Fact]\n        public void AddLiquidKafkaConsumer_WhenSuccessfullyInjectConsumerAndHandlers_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidKafkaConsumer<WorkerMediatorMock, MessageMock>(\"test\", false, typeof(MockRequest).Assembly);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IKafkaFactory>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidWorker<MessageMock>)));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IHostedService)\n            && x.ImplementationType == typeof(LiquidBackgroundService<MessageMock>)));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidConsumer<MessageMock>)\n            && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/KafkaFactoryTest.cs",
    "content": "using Liquid.Core.Exceptions;\nusing Liquid.Messaging.Kafka.Settings;\nusing Xunit;\n\nnamespace Liquid.Messaging.Kafka.Tests\n{\n    public class KafkaFactoryTest\n    {\n        private KafkaSettings _settings;\n        private readonly IKafkaFactory _sut;\n\n        public KafkaFactoryTest()\n        {\n            \n            _sut = new KafkaFactory();\n        }\n        [Fact]\n        public void GetConsumer_WhenSettingsINull_ThrowLiquidMessagingException()\n        {\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetConsumer(_settings));\n        }\n\n        [Fact]\n        public void GetProducer_WhenSettingsIsNull_ThrowLiquidMessagingException()\n        {\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetProducer(_settings));\n        }\n\n        [Fact]\n        public void GetConsumer_WhenSettingsIsNotValid_ThrowLiquidMessagingException()\n        {\n            _settings = new KafkaSettings()\n            {\n                ConnectionId = \"test\"\n            };\n\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetConsumer(_settings));\n        }\n\n        [Fact]\n        public void GetProducer_WhenSettingsIsValid_ResposeIsNotNull()\n        {\n            _settings = new KafkaSettings();\n\n            var producer = _sut.GetProducer(_settings);\n            Assert.NotNull(producer);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/KafkaProducerTest.cs",
    "content": "﻿using Confluent.Kafka;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.Kafka.Settings;\nusing Liquid.Messaging.Kafka.Tests.Mock;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Messaging.Kafka.Tests\n{\n    public class KafkaProducerTest\n    {\n        private readonly ILiquidProducer<MessageMock> _sut;\n        private IKafkaFactory _factory;\n        private IProducer<Null, string> _client;\n        private IOptions<KafkaSettings> _settings;\n\n        public KafkaProducerTest()\n        {\n            _client = Substitute.For<IProducer<Null, string>>();\n\n            _factory = Substitute.For<IKafkaFactory>();\n\n            _factory.GetProducer(Arg.Any<KafkaSettings>()).Returns(_client);\n\n            _settings = Substitute.For<IOptions<KafkaSettings>>();\n\n            _settings.Value.Returns(new KafkaSettings());\n\n            _sut = new KafkaProducer<MessageMock>(_settings, _factory);\n        }\n\n        [Fact]\n        public async Task SendMessageAsync_WhenMessageSended_ClientReceivedCall()\n        {\n            var message = new MessageMock();\n\n            await _sut.SendMessageAsync(message);\n\n            await _client.Received(1).ProduceAsync(Arg.Any<string>(), Arg.Any<Message<Null, string>>(), Arg.Any<CancellationToken>());\n        }\n\n        [Fact]\n        public async Task SendMessageAsync_WhenSendMessageFail_ThrowException()\n        {\n            var message = new MessageMock();\n\n            _client.When(x => x.ProduceAsync(Arg.Any<string>(), Arg.Any<Message<Null, string>>(), Arg.Any<CancellationToken>()))\n                .Do((call) => throw new Exception());\n\n            var task = _sut.SendMessageAsync(message);\n\n            await Assert.ThrowsAsync<MessagingProducerException>(() => task);\n        }\n\n        [Fact]\n        public async Task SendMessagesAsync_WhenMessagesSended_ClientReceivedCall()\n        {\n            var message = new MessageMock();\n            var messages = new List<MessageMock>();\n\n            messages.Add(message);\n            messages.Add(message);\n\n            await _sut.SendMessagesAsync(messages);\n\n            await _client.Received(2).ProduceAsync(Arg.Any<string>(), Arg.Any<Message<Null, string>>(), Arg.Any<CancellationToken>());\n        }\n\n        [Fact]\n        public async Task SendMessagesAsync_WhenSendMessagesFail_ThrowException()\n        {\n            var message = new MessageMock();\n            var messages = new List<MessageMock>();\n\n            messages.Add(message);\n            messages.Add(message);\n\n            _client.When(x => x.ProduceAsync(Arg.Any<string>(), Arg.Any<Message<Null, string>>(), Arg.Any<CancellationToken>()))\n                .Do((call) => throw new Exception());\n\n            var task = _sut.SendMessagesAsync(messages);\n\n            await Assert.ThrowsAsync<MessagingProducerException>(() => task);\n        }\n\n        [Fact]\n        public void Ctor_WhenRabbitMqFactoryIsNull_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new KafkaProducer<MessageMock>(_settings, null));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Liquid.Messaging.Kafka.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <None Include=\"..\\..\\logo.png\" Link=\"logo.png\">\n      <PackagePath></PackagePath>\n      <Pack>True</Pack>\n    </None>\n  </ItemGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Messaging.Kafka\\Liquid.Messaging.Kafka.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Mock/HandlerMock/MockCommandHandler.cs",
    "content": "﻿using MediatR;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.Kafka.Tests.Mock.HandlerMock\n{\n    public class MockCommandHandler : IRequestHandler<MockRequest>\n    {\n        public Task Handle(MockRequest request, CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Mock/HandlerMock/MockRequest.cs",
    "content": "﻿using MediatR;\n\nnamespace Liquid.Messaging.Kafka.Tests.Mock.HandlerMock\n{\n    public class MockRequest : IRequest\n    {\n        public MessageMock Message { get; set; }\n\n        public MockRequest(MessageMock message)\n        {\n            Message = message;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Mock/HandlerMock/MockValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace Liquid.Messaging.Kafka.Tests.Mock.HandlerMock\n{\n    public class MockValidator : AbstractValidator<MockRequest>\n    {\n        public MockValidator()\n        {\n            RuleFor(request => request.Message.TestMessageId).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Mock/MessageMock.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.Kafka.Tests.Mock\n{\n    /// <summary>\n    /// Test Message Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class MessageMock\n    {\n        /// <summary>\n        /// Gets or sets the test message identifier.\n        /// </summary>\n        /// <value>\n        /// The test message identifier.\n        /// </value>\n        public int TestMessageId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name.\n        /// </summary>\n        /// <value>\n        /// The name.\n        /// </value>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n        /// <summary>\n        /// Gets or sets the amount.\n        /// </summary>\n        /// <value>\n        /// The amount.\n        /// </value>\n        public double Amount { get; set; }\n    }\n}"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Mock/WorkerMediatorMock.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.Kafka.Tests.Mock.HandlerMock;\nusing MediatR;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.Kafka.Tests.Mock\n{\n    public class WorkerMediatorMock : ILiquidWorker<MessageMock>\n    {\n        private readonly IMediator _mediator;\n\n        public WorkerMediatorMock(IMediator mediator)\n        {\n            _mediator = mediator;\n        }\n\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<MessageMock> args, CancellationToken cancellationToken)\n        {\n            await _mediator.Send(new MockRequest(args.Data));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/Mock/WorkerMock .cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.Kafka.Tests.Mock\n{\n    public class WorkerMock : ILiquidWorker<MessageMock>\n    {\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<MessageMock> args, CancellationToken cancellationToken)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.Kafka.Tests/kafkaConsumerTest.cs",
    "content": "﻿using Confluent.Kafka;\nusing Liquid.Core.Extensions;\nusing Liquid.Core.Utils;\nusing Liquid.Core.Exceptions;\nusing Liquid.Messaging.Kafka.Settings;\nusing Liquid.Messaging.Kafka.Tests.Mock;\nusing NSubstitute;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\nusing Liquid.Core.Entities;\nusing Microsoft.Extensions.Options;\n\nnamespace Liquid.Messaging.Kafka.Tests\n{\n    public class kafkaConsumerTest : KafkaConsumer<MessageMock>\n    {\n        public static readonly IKafkaFactory _factory = Substitute.For<IKafkaFactory>();\n        public static readonly IOptions<KafkaSettings> _settings = GetOptions();\n\n        public static IOptions<KafkaSettings> GetOptions()\n        {\n            var settings = Substitute.For<IOptions<KafkaSettings>>();\n            settings.Value.Returns(new KafkaSettings());\n            return settings;\n        }\n        public kafkaConsumerTest() \n            : base(_factory, _settings)\n        {\n        }\n\n        [Fact]\n        public void RegisterMessageHandler_WhenRegisteredSucessfully_BasicConsumeReceivedCall()\n        {\n            var messageReceiver = Substitute.For<IConsumer<Ignore, string>>();\n            _factory.GetConsumer(Arg.Any<KafkaSettings>()).Returns(messageReceiver);\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n\n            RegisterMessageHandler();\n\n            Assert.True(RegisterHandleMock());\n        }\n\n        [Fact]\n        public async Task RegisterMessageHandler_WhenRegistereFail_ThrowException()\n        {\n            var messageReceiver = Substitute.For<IConsumer<Ignore, string>>();\n            _factory.GetConsumer(Arg.Any<KafkaSettings>()).Returns(messageReceiver);\n\n           await Assert.ThrowsAsync<NotImplementedException>(() => RegisterMessageHandler(new CancellationToken()));\n        }\n\n\n        [Fact]\n        public async Task MessageHandler_WhenProcessExecutedSucessfully()\n        {\n            var message = new ConsumeResult<Ignore, string>();\n\n            var entity = new MessageMock() { TestMessageId = 1 };\n\n            var messageObj = new Message<Ignore, string>();\n            messageObj.Value = entity.ToJsonString();\n\n            message.Message = messageObj;\n\n            message.Message.Headers = new Headers(); \n\n            var messageReceiver = Substitute.For<IConsumer<Ignore, string>>();\n\n            messageReceiver.Consume(Arg.Any<CancellationToken>()).Returns(message);\n\n            _factory.GetConsumer(Arg.Any<KafkaSettings>()).Returns(messageReceiver);\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n              \n\n            var sut = RegisterMessageHandler(new CancellationToken());\n\n            Assert.NotNull(sut);\n        }\n\n        [Fact]\n        public async Task MessageHandler_WhenProcessExecutionFail_ThrowException()\n        {\n            var message = new ConsumeResult<Ignore, string>();\n\n            var entity = new MessageMock() { TestMessageId = 2 };\n\n            var messageObj = new Message<Ignore, string>();\n            messageObj.Value = entity.ToJsonString();\n\n            message.Message = messageObj;\n            message.Message.Headers = new Headers();\n\n            var messageReceiver = Substitute.For<IConsumer<Ignore, string>>();\n            messageReceiver.Consume(Arg.Any<CancellationToken>()).Returns(message);\n            _factory.GetConsumer(Arg.Any<KafkaSettings>()).Returns(messageReceiver);\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n\n            ProcessErrorAsync += ProcessErrorAsyncMock;\n\n            var sut = MessageHandler(new CancellationToken());\n\n            await Assert.ThrowsAsync<MessagingConsumerException>(() => sut);\n\n        }\n\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        private async Task ProcessMessageAsyncMock(ConsumerMessageEventArgs<MessageMock> args, CancellationToken cancellationToken)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            if (args.Data.TestMessageId == 2)\n                throw new Exception();\n        }\n\n        private async Task ProcessErrorAsyncMock(ConsumerErrorEventArgs args)\n        {\n            throw args.Exception;\n        }\n\n\n        private bool RegisterHandleMock()\n        {\n            try\n            {\n                RegisterMessageHandler();\n\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/IServiceCollectionExtensionTest.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.RabbitMq.Extensions.DependencyInjection;\nusing Liquid.Messaging.RabbitMq.Tests.Mock;\nusing Liquid.Messaging.RabbitMq.Tests.Mock.HandlerMock;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Hosting;\nusing NSubstitute;\nusing System.Linq;\nusing Xunit;\n\nnamespace Liquid.Messaging.RabbitMq.Tests\n{\n    public class IServiceCollectionExtensionTest\n    {\n        private IServiceCollection _sut;\n        private IConfiguration _configProvider = Substitute.For<IConfiguration>();\n        private IConfigurationSection _configurationSection = Substitute.For<IConfigurationSection>();\n\n        private void SetCollection()\n        {\n            _configProvider.GetSection(Arg.Any<string>()).Returns(_configurationSection);\n            _sut = new ServiceCollection();\n            _sut.AddSingleton(_configProvider);\n        }\n\n        [Fact]\n        public void AddLiquidRabbitMqProducer_WhenSuccessfullyInjectProducer_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidRabbitMqProducer<MessageMock>(\"test\");\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IRabbitMqFactory>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidProducer<MessageMock>) && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n        [Fact]\n        public void AddLiquidRabbitMqProducer_WhenSuccessfullyInjectWhitoutTelemetry_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidRabbitMqProducer<MessageMock>(\"test\", false);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IRabbitMqFactory>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidProducer<MessageMock>) && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n        [Fact]\n        public void AddLiquidRabbitMqConsumer_WhenSuccessfullyInjectConsumer_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidRabbitMqConsumer<WorkerMock, MessageMock>(\"test\");\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IRabbitMqFactory>());\n            Assert.NotNull(provider.GetService<ILiquidWorker<MessageMock>>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IHostedService)\n            && x.ImplementationType == typeof(LiquidBackgroundService<MessageMock>)));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidConsumer<MessageMock>)\n            && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n        [Fact]\n        public void AddLiquidRabbitMqConsumer_WhenSuccessfullyInjectConsumerAndHandlers_GetServicesSucessfully()\n        {\n            SetCollection();\n            _sut.AddLiquidRabbitMqConsumer<WorkerMediatorMock, MessageMock>(\"test\", false, typeof(MockRequest).Assembly);\n\n            var provider = _sut.BuildServiceProvider();\n\n            Assert.NotNull(provider.GetService<IRabbitMqFactory>());\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidWorker<MessageMock>)));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(IHostedService)\n            && x.ImplementationType == typeof(LiquidBackgroundService<MessageMock>)));\n            Assert.NotNull(_sut.FirstOrDefault(x => x.ServiceType == typeof(ILiquidConsumer<MessageMock>)\n            && x.Lifetime == ServiceLifetime.Singleton));\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Liquid.Messaging.RabbitMq.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Messaging.RabbitMq\\Liquid.Messaging.RabbitMq.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Mock/HandlerMock/MockCommandHandler.cs",
    "content": "﻿using MediatR;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.RabbitMq.Tests.Mock.HandlerMock\n{\n    public class MockCommandHandler : IRequestHandler<MockRequest>\n    {\n        public Task Handle(MockRequest request, CancellationToken cancellationToken)\n        {\n            return Task.CompletedTask;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Mock/HandlerMock/MockRequest.cs",
    "content": "﻿using MediatR;\n\nnamespace Liquid.Messaging.RabbitMq.Tests.Mock.HandlerMock\n{\n    public class MockRequest : IRequest\n    {\n        public MessageMock Message { get; set; }\n\n        public MockRequest(MessageMock message)\n        {\n            Message = message;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Mock/HandlerMock/MockValidator.cs",
    "content": "﻿using FluentValidation;\n\nnamespace Liquid.Messaging.RabbitMq.Tests.Mock.HandlerMock\n{\n    public class MockValidator : AbstractValidator<MockRequest>\n    {\n        public MockValidator()\n        {\n            RuleFor(request => request.Message.TestMessageId).NotEmpty().NotNull();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Mock/MessageMock.cs",
    "content": "﻿using System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Messaging.RabbitMq.Tests.Mock\n{\n    /// <summary>\n    /// Test Message Class.\n    /// </summary>\n    [ExcludeFromCodeCoverage]\n    public class MessageMock\n    {\n        /// <summary>\n        /// Gets or sets the test message identifier.\n        /// </summary>\n        /// <value>\n        /// The test message identifier.\n        /// </value>\n        public int TestMessageId { get; set; }\n\n        /// <summary>\n        /// Gets or sets the name.\n        /// </summary>\n        /// <value>\n        /// The name.\n        /// </value>\n        public string Name { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n        /// <summary>\n        /// Gets or sets the amount.\n        /// </summary>\n        /// <value>\n        /// The amount.\n        /// </value>\n        public double Amount { get; set; }\n    }\n}"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Mock/WorkerMediatorMock.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.RabbitMq.Tests.Mock.HandlerMock;\nusing MediatR;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.RabbitMq.Tests.Mock\n{\n    public class WorkerMediatorMock : ILiquidWorker<MessageMock>\n    {\n        private readonly IMediator _mediator;\n\n        public WorkerMediatorMock(IMediator mediator)\n        {\n            _mediator = mediator;\n        }\n\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<MessageMock> args, CancellationToken cancellationToken)\n        {\n            await _mediator.Send(new MockRequest(args.Data));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/Mock/WorkerMock .cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Interfaces;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Messaging.RabbitMq.Tests.Mock\n{\n    public class WorkerMock : ILiquidWorker<MessageMock>\n    {\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task ProcessMessageAsync(ConsumerMessageEventArgs<MessageMock> args, CancellationToken cancellationToken)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            return;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/RabbitMqConsumerTest.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing Liquid.Core.Extensions;\nusing Liquid.Messaging.RabbitMq.Settings;\nusing Liquid.Messaging.RabbitMq.Tests.Mock;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing RabbitMQ.Client;\nusing RabbitMQ.Client.Events;\nusing System;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Messaging.RabbitMq.Tests\n{\n    public class RabbitMqConsumerTest : RabbitMqConsumer<MessageMock>\n    {\n        public static readonly IRabbitMqFactory _factory = Substitute.For<IRabbitMqFactory>();\n        public static IOptions<RabbitMqConsumerSettings> _settings = GetOptions();\n        public static RabbitMqConsumerSettings _settingsValue;\n        public static IOptions<RabbitMqConsumerSettings> GetOptions()\n        {\n            var settings = Substitute.For<IOptions<RabbitMqConsumerSettings>>();\n\n            _settingsValue = new RabbitMqConsumerSettings\n            {\n                CompressMessage = true,\n                Exchange = \"test\",\n                Queue = \"test\",\n                AdvancedSettings = new AdvancedSettings\n                {\n                    AutoAck = false,\n                    QueueAckModeSettings = new QueueAckModeSettings() { QueueAckMode = QueueAckModeEnum.BasicAck, Requeue = true }\n                }\n            };\n            settings.Value.Returns(_settingsValue);\n            return settings;\n        }\n\n        public RabbitMqConsumerTest()\n            : base(_factory, _settings)\n        {\n            var model = Substitute.For<IModel>();\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(model);\n        }\n\n        [Fact]\n        public void Constructor_WhenFactoryIsNull_ThrowArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new RabbitMqConsumer<MessageMock>(null, _settings));\n        }\n\n        [Fact]\n        public void Constructor_WhenSettingsIsNull_ThrowArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new RabbitMqConsumer<MessageMock>(_factory, null));\n        }\n\n        [Fact]\n        public void Constructor_WhenSettingsValueIsNull_ThrowArgumentNullException()\n        {\n            var settings = Substitute.For<IOptions<RabbitMqConsumerSettings>>();\n            settings.Value.Returns((RabbitMqConsumerSettings)null);\n            Assert.Throws<ArgumentNullException>(() => new RabbitMqConsumer<MessageMock>(_factory, settings));\n        }\n\n\n        [Fact]\n        public void RegisterMessageHandler_WhenRegisteredSucessfully_BasicConsumeReceivedCall()\n        {\n            var messageReceiver = Substitute.For<IModel>();\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(messageReceiver);\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n\n            RegisterMessageHandler();\n\n            Assert.True(RegisterHandleMock());\n        }\n\n        [Fact]\n        public async Task RegisterMessageHandler_WhenRegistereFail_ThrowException()\n        {\n            var messageReceiver = Substitute.For<IModel>();\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(messageReceiver);\n\n            await Assert.ThrowsAsync<NotImplementedException>(() => RegisterMessageHandler());\n        }\n\n\n        [Fact]\n        public async Task MessageHandler_WhenProcessExecutedSucessfully()\n        {\n            var message = new BasicDeliverEventArgs();\n\n            var entity = new MessageMock() { TestMessageId = 1 };\n\n            message.Body = entity.ToJsonBytes();\n\n            var messageReceiver = Substitute.For<IModel>();\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(messageReceiver);\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n            await RegisterMessageHandler();\n            await MessageHandler(message, new CancellationToken());\n        }\n\n        [Fact]\n        public async Task MessageHandler_CallsConsumeMessageAsync_AndAcks_WhenAutoAckIsFalse()\n        {\n            var message = new BasicDeliverEventArgs();\n            var entity = new MessageMock() { TestMessageId = 1 };\n            message.Body = entity.ToJsonBytes();\n            var messageReceiver = Substitute.For<IModel>();\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(messageReceiver);\n\n            await RegisterMessageHandler();\n\n            await MessageHandler(message, new CancellationToken());\n            messageReceiver.Received(1).BasicAck(message.DeliveryTag, false);\n\n        }\n\n        [Fact]\n        public async Task MessageHandler_CallsConsumeMessageAsync_AndNacks_WhenAutoAckIsFalse()\n        {\n            var message = new BasicDeliverEventArgs();\n            var entity = new MessageMock() { TestMessageId = 2 };\n            message.Body = entity.ToJsonBytes();\n            var messageReceiver = Substitute.For<IModel>();\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(messageReceiver);\n            \n            await RegisterMessageHandler();\n            await MessageHandler(message, new CancellationToken());\n            messageReceiver.Received(1).BasicNack(message.DeliveryTag, false, true);\n        }\n\n        [Fact]\n        public async Task MessageHandler_CallsConsumeMessageAsync_AndRejects_WhenAutoAckIsFalse()\n        {\n            var message = new BasicDeliverEventArgs();\n            var entity = new MessageMock() { TestMessageId = 2 };\n            message.Body = entity.ToJsonBytes();\n            var messageReceiver = Substitute.For<IModel>();\n            ConsumeMessageAsync += ProcessMessageAsyncMock;            \n\n            _factory.GetReceiver(Arg.Any<RabbitMqConsumerSettings>()).Returns(messageReceiver);\n\n            _settingsValue = new RabbitMqConsumerSettings\n            {\n                CompressMessage = true,\n                Exchange = \"test\",\n                Queue = \"test\",\n                AdvancedSettings = new AdvancedSettings\n                {\n                    AutoAck = false,\n                    QueueAckModeSettings = new QueueAckModeSettings() { QueueAckMode = QueueAckModeEnum.BasicReject, Requeue = true }\n                }\n            };\n\n            _settings.Value.Returns(_settingsValue);\n\n            await RegisterMessageHandler();\n\n            await MessageHandler(message, new CancellationToken());\n            messageReceiver.Received(1).BasicReject(message.DeliveryTag, true);\n        }\n        \n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        private async Task ProcessMessageAsyncMock(ConsumerMessageEventArgs<MessageMock> args, CancellationToken cancellationToken)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            if (args.Data.TestMessageId == 2)\n                throw new Exception();\n        }\n\n        private bool RegisterHandleMock()\n        {\n            try\n            {\n                RegisterMessageHandler();\n\n                return true;\n            }\n            catch\n            {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.RabbitMq.Tests/RabbitMqProducerTest.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.RabbitMq.Settings;\nusing Liquid.Messaging.RabbitMq.Tests.Mock;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing RabbitMQ.Client;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Messaging.RabbitMq.Tests\n{\n    public class RabbitMqProducerTest\n    {\n        private readonly ILiquidProducer<MessageMock> _sut;\n        private IRabbitMqFactory _factory;\n        private IModel _client;\n        private IOptions<RabbitMqProducerSettings> _settings;\n\n        public RabbitMqProducerTest()\n        {\n            _client = Substitute.For<IModel>();\n\n            _factory = Substitute.For<IRabbitMqFactory>();\n\n            _factory.GetSender(Arg.Any<RabbitMqProducerSettings>()).Returns(_client);\n\n            _settings = Substitute.For<IOptions<RabbitMqProducerSettings>>();\n\n            _settings.Value.Returns(new RabbitMqProducerSettings());\n\n            _sut = new RabbitMqProducer<MessageMock>(_factory, _settings);\n        }\n\n        [Fact]\n        public async Task SendMessageAsync_WhenMessageSended_BasicPublishReceivedCall()\n        {\n            var message = new MessageMock();\n\n            await _sut.SendMessageAsync(message);\n\n            _client.Received(1).BasicPublish(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<IBasicProperties>(), Arg.Any<ReadOnlyMemory<byte>>());\n        }\n\n        [Fact]\n        public async Task SendMessageAsync_WhenSendMessageFail_ThrowException()\n        {\n            var message = new MessageMock();\n\n            _client.When(x => x.BasicPublish(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<IBasicProperties>(), Arg.Any<ReadOnlyMemory<byte>>()))\n                .Do((call) => throw new Exception());\n\n            var task = _sut.SendMessageAsync(message);\n\n            await Assert.ThrowsAsync<MessagingProducerException>(() => task);\n        }\n\n        [Fact]\n        public async Task SendMessagesAsync_WhenMessagesSended_BasicPublishReceivedCall()\n        {\n            var message = new MessageMock();\n            var messages = new List<MessageMock>();\n\n            messages.Add(message);\n            messages.Add(message);\n\n            await _sut.SendMessagesAsync(messages);\n\n            _client.Received(2).BasicPublish(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<IBasicProperties>(), Arg.Any<ReadOnlyMemory<byte>>());\n        }\n\n        [Fact]\n        public async Task SendMessagesAsync_WhenSendMessagesFail_ThrowException()\n        {\n            var message = new MessageMock();\n            var messages = new List<MessageMock>();\n\n            messages.Add(message);\n            messages.Add(message);\n\n            _client.When(x => x.BasicPublish(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<IBasicProperties>(), Arg.Any<ReadOnlyMemory<byte>>()))\n                .Do((call) => throw new Exception());\n\n            var task = _sut.SendMessagesAsync(messages);\n\n            await Assert.ThrowsAsync<MessagingProducerException>(() => task);\n        }\n\n        [Fact]\n        public void Ctor_WhenRabbitMqFactoryIsNull_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new RabbitMqProducer<MessageMock>(null, _settings));\n        }\n\n        [Fact]\n        public void Ctor_WhenProducerSettingsIsNull_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new RabbitMqProducer<MessageMock>(_factory, null));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.ServiceBus.Tests/Liquid.Messaging.ServiceBus.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"System.Linq.Async\" Version=\"6.0.1\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Messaging.ServiceBus\\Liquid.Messaging.ServiceBus.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Messaging.ServiceBus.Tests/Mock/EntityMock.cs",
    "content": "﻿using System;\n\nnamespace Liquid.Messaging.ServiceBus.Tests.Mock\n{\n    [Serializable]\n    public class EntityMock\n    {\n        public int Id { get; set; }\n\n        public string MyProperty { get; set; }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.ServiceBus.Tests/ServiceBusConsumerTest.cs",
    "content": "using Azure.Core.Amqp;\nusing Azure.Messaging.ServiceBus;\nusing Liquid.Core.Entities;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Extensions;\nusing Liquid.Messaging.ServiceBus.Tests.Mock;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Messaging.ServiceBus.Tests\n{\n    public class ServiceBusConsumerTest : ServiceBusConsumer<EntityMock>\n    {\n        private static readonly IServiceBusFactory _factory = Substitute.For<IServiceBusFactory>();\n        private static readonly ServiceBusProcessor _processor = Substitute.For<ServiceBusProcessor>();\n        private static readonly ServiceBusReceiver _receiver = Substitute.For<ServiceBusReceiver>();\n\n        public ServiceBusConsumerTest() : base(_factory, \"test\")\n        {\n            _factory.GetProcessor(Arg.Any<string>()).Returns(_processor);\n        }\n\n        [Fact]\n        public async Task RegisterMessageHandler_WhenRegisteredSucessfully_StartProcessingReceivedCall()\n        {\n            var messageReceiver = Substitute.For<ServiceBusProcessor>();\n            _factory.GetProcessor(Arg.Any<string>()).Returns(messageReceiver);\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n\n            await RegisterMessageHandler();\n\n            await messageReceiver.Received(1).StartProcessingAsync();\n        }\n\n        [Fact]\n        public async Task RegisterMessageHandler_WhenConsumeMessageAssyncIsNull_ThrowNotImplementedException()\n        {\n            var messageReceiver = Substitute.For<ServiceBusProcessor>();\n            _factory.GetProcessor(Arg.Any<string>()).Returns(messageReceiver);\n\n            await Assert.ThrowsAsync<NotImplementedException>(() => RegisterMessageHandler());\n        }\n\n        [Fact]\n        public async Task MessageHandler_WhenProcessExecutedSucessfully()\n        {\n\n            var entity = new EntityMock() { Id = 1, MyProperty = \"test\" };\n\n            var readOnly = new ReadOnlyMemory<byte>(entity.ToJsonBytes());\n\n            var convertEntity = new List<ReadOnlyMemory<byte>>();\n\n            convertEntity.Add(readOnly);\n\n            var amqp = new AmqpAnnotatedMessage(new AmqpMessageBody(convertEntity));\n\n            BinaryData binary = default;\n\n            var message = ServiceBusReceivedMessage.FromAmqpMessage(amqp, binary);\n\n            var processMessage = new ProcessMessageEventArgs(message, _receiver, new CancellationToken());\n\n            ConsumeMessageAsync += ProcessMessageAsyncMock;\n\n            await MessageHandler(processMessage);\n        }\n\n\n        [Fact]\n        public async Task ErrorHandler_WhenProcessErrorExecuted_ThrowsMessagingConsumerException()\n        {\n\n            var processError = new ProcessErrorEventArgs(new Exception(\"teste\"), ServiceBusErrorSource.ProcessMessageCallback, \"teste\"\n                , \"testqueue\", Guid.NewGuid().ToString(), new CancellationToken());\n\n            ProcessErrorAsync += ProcessError;\n\n            await Assert.ThrowsAsync<MessagingConsumerException>(() => ErrorHandler(processError));\n        }\n\n        [Fact]\n        public void Constructor_WhenFactoryIsNull_ThrowsArgumentNullException()\n        {\n           Assert.Throws<ArgumentNullException>(() => new ServiceBusConsumer<EntityMock>(null, \"test\"));\n        }\n\n        [Fact]\n        public void Constructor_WhenSettingsNameIsNull_ThrowsArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new ServiceBusConsumer<EntityMock>(_factory, null));\n        }\n\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        private async Task ProcessMessageAsyncMock(ConsumerMessageEventArgs<EntityMock> args, CancellationToken cancellationToken)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.ServiceBus.Tests/ServiceBusFactoryTest.cs",
    "content": "﻿using Liquid.Core.Exceptions;\nusing Liquid.Messaging.ServiceBus.Settings;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Liquid.Messaging.ServiceBus.Tests\n{\n    public class ServiceBusFactoryTest\n    {\n        private readonly IOptions<ServiceBusSettings> _configuration;\n        private readonly List<ServiceBusEntitySettings> _settings;\n        private readonly IServiceBusFactory _sut;\n\n        public ServiceBusFactoryTest()\n        {\n            _configuration = Substitute.For<IOptions<ServiceBusSettings>>();\n            _settings = new List<ServiceBusEntitySettings>();\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\" });\n\n            _configuration.Value.Returns(new ServiceBusSettings() { Settings = _settings });\n            _sut = new ServiceBusFactory(_configuration);\n        }\n\n        [Fact]\n        public void Ctor_WhenOptionsValueIsNull_ThrowArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new ServiceBusFactory(Substitute.For<IOptions<ServiceBusSettings>>()));\n        }\n\n        [Fact]\n        public void GetProcessor_WhenPeekModeAndConnectionStringIsMissing_ThrowMessagingMissingConfigurationException()\n        {\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\" });\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetProcessor(\"test\"));\n\n        }\n        [Fact]\n        public void GetProcessor_WhenReceiveModeAndConnectionStringIsMissing_ThrowMessagingMissingConfigurationException()\n        {\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\", PeekLockMode = false });\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetProcessor(\"test\"));\n\n        }\n\n        [Fact]\n        public void GetReceiver_WhenPeekModeAndConnectionIsMissing_ThrowMessagingMissingConfigurationException()\n        {\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\" });\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetReceiver(\"test\"));\n\n        }\n\n        [Fact]\n        public void GetReceiver_WhenReceiveModeAndConnectionIsMissing_ThrowMessagingMissingConfigurationException()\n        {\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\", PeekLockMode = false });\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetReceiver(\"test\"));\n\n        }\n\n        [Fact]\n        public void GetSender_WhenPeekModeAndConnectionIsMissing_ThrowMessagingMissingConfigurationException()\n        {\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\" });\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetSender(\"test\"));\n\n        }\n        [Fact]\n        public void GetSender_WhenReceiveModeAndConnectionIsMissing_ThrowMessagingMissingConfigurationException()\n        {\n            _settings.Add(new ServiceBusEntitySettings { EntityPath = \"test\", PeekLockMode = false });\n            Assert.Throws<MessagingMissingConfigurationException>(() => _sut.GetSender(\"test\"));\n\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.ServiceBus.Tests/ServiceBusFactoryTests.cs",
    "content": "using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing Azure.Messaging.ServiceBus;\nusing Liquid.Core.Exceptions;\nusing Liquid.Messaging.ServiceBus;\nusing Liquid.Messaging.ServiceBus.Settings;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing Xunit;\n\nnamespace Liquid.Messaging.ServiceBus.Tests\n{\n    public class ServiceBusFactoryTests\n    {\n        private readonly ServiceBusSettings _settings;\n        private readonly IOptions<ServiceBusSettings> _options;\n\n        public ServiceBusFactoryTests()\n        {\n            _settings = new ServiceBusSettings\n            {\n                Settings = new List<ServiceBusEntitySettings>\n                {\n                    new ServiceBusEntitySettings\n                    {\n                        EntityPath = \"queue1\",\n                        ConnectionString = \"Endpoint=sb://test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key\",\n                        PeekLockMode = true,\n                        MaxConcurrentCalls = 5,\n                        Subscription = null\n                    },\n                    new ServiceBusEntitySettings\n                    {\n                        EntityPath = \"topic1\",\n                        ConnectionString = \"Endpoint=sb://test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=key\",\n                        PeekLockMode = false,\n                        MaxConcurrentCalls = 2,\n                        Subscription = \"sub1\"\n                    }\n                }\n            };\n            _options = Substitute.For<IOptions<ServiceBusSettings>>();\n            _options.Value.Returns(_settings);\n        }\n\n        [Fact]\n        public void GetSender_ReturnsSender_WhenConfigExists()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act\n            var sender = factory.GetSender(\"queue1\");\n\n            // Assert\n            Assert.NotNull(sender);\n            Assert.IsType<ServiceBusSender>(sender);\n        }\n\n        [Fact]\n        public void GetSender_ThrowsArgumentOutOfRangeException_WhenConfigMissing()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentOutOfRangeException>(() => factory.GetSender(\"notfound\"));\n            Assert.Contains(\"notfound\", ex.Message);\n        }\n\n        [Fact]\n        public void GetProcessor_ReturnsProcessor_WhenQueueConfigExists()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act\n            var processor = factory.GetProcessor(\"queue1\");\n\n            // Assert\n            Assert.NotNull(processor);\n            Assert.IsType<ServiceBusProcessor>(processor);\n        }\n\n        [Fact]\n        public void GetProcessor_ReturnsProcessor_WhenTopicConfigExists()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act\n            var processor = factory.GetProcessor(\"topic1\");\n\n            // Assert\n            Assert.NotNull(processor);\n            Assert.IsType<ServiceBusProcessor>(processor);\n        }\n\n        [Fact]\n        public void GetProcessor_ThrowsMessagingMissingConfigurationException_WhenConfigMissing()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act & Assert\n            var ex = Assert.Throws<MessagingMissingConfigurationException>(() => factory.GetProcessor(\"notfound\"));\n            Assert.Contains(\"notfound\", ex.Message);\n        }\n\n        [Fact]\n        public void GetReceiver_ReturnsReceiver_WhenConfigExists()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act\n            var receiver = factory.GetReceiver(\"queue1\");\n\n            // Assert\n            Assert.NotNull(receiver);\n            Assert.IsType<ServiceBusReceiver>(receiver);\n        }\n\n        [Fact]\n        public void GetReceiver_ThrowsArgumentOutOfRangeException_WhenConfigMissing()\n        {\n            // Arrange\n            var factory = new ServiceBusFactory(_options);\n\n            // Act & Assert\n            var ex = Assert.Throws<ArgumentOutOfRangeException>(() => factory.GetReceiver(\"notfound\"));\n            Assert.Contains(\"notfound\", ex.Message);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Messaging.ServiceBus.Tests/ServiceBusProducerTest.cs",
    "content": "﻿using Azure.Messaging.ServiceBus;\nusing Liquid.Core.Exceptions;\nusing Liquid.Core.Interfaces;\nusing Liquid.Messaging.ServiceBus.Tests.Mock;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Messaging.ServiceBus.Tests\n{\n    public class ServiceBusProducerTest\n    {\n        private readonly ILiquidProducer<EntityMock> _sut;\n        private readonly IServiceBusFactory _serviceBusFactory;\n        private readonly ServiceBusSender _client;\n        private readonly EntityMock _message;\n\n        public ServiceBusProducerTest()\n        {\n            _client = Substitute.For<ServiceBusSender>();\n\n            _serviceBusFactory = Substitute.For<IServiceBusFactory>();\n\n            _serviceBusFactory.GetSender(Arg.Any<string>()).Returns(_client);\n\n            _sut = new ServiceBusProducer<EntityMock>(_serviceBusFactory, \"test\");\n\n            _message = new EntityMock() { Id = 1, MyProperty = \"test\" };\n        }\n\n        [Fact]\n        public async Task SendAsync_WhenSingleEntitySendedSuccessfully_ClientReceivedCall()\n        {\n            var customProperties = new Dictionary<string, object>();\n            customProperties.Add(\"test\", 123);\n\n            await _sut.SendMessageAsync(_message, customProperties);\n\n            await _client.Received(1).SendMessageAsync(Arg.Any<ServiceBusMessage>());\n\n        }\n\n        [Fact]\n        public async Task SendAsync_WhenListEntitiesSendedSuccessfully_ClientReceivedCall()\n        {\n            var entities = new List<EntityMock>() { _message };\n\n            await _sut.SendMessagesAsync(entities);\n\n            await _client.Received(1).SendMessagesAsync(Arg.Any<IList<ServiceBusMessage>>());\n        }\n\n        [Fact]\n        public async Task SendAsync_WhenSingleEntitySendFailed_ThrowError()\n        {\n            _client.When(x => x.SendMessageAsync(Arg.Any<ServiceBusMessage>())).Do((call) => throw new Exception());\n\n            var sut = _sut.SendMessageAsync(_message, new Dictionary<string, object>());\n\n            await Assert.ThrowsAsync<MessagingProducerException>(() => sut);\n        }\n\n        [Fact]\n        public async Task SendAsync_WhenListEntitiesSendFailed_ThrowError()\n        {\n            var entities = new List<EntityMock>() { _message };\n\n            _client.When(x => x.SendMessagesAsync(Arg.Any<IList<ServiceBusMessage>>())).Do((call) => throw new Exception());\n\n            var sut = _sut.SendMessagesAsync(entities);\n\n            await Assert.ThrowsAsync<MessagingProducerException>(() => sut);\n        }\n\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/Configurations/MockTypeConfiguration.cs",
    "content": "﻿using Liquid.Repository.EntityFramework.Tests.Entities;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Metadata.Builders;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Data.EntityFramework.Tests.Configurations\n{\n    [ExcludeFromCodeCoverage]\n    public class MockTypeConfiguration : IEntityTypeConfiguration<MockEntity>\n    {\n        public void Configure(EntityTypeBuilder<MockEntity> builder)\n        {\n            builder.Property(o => o.Id).ValueGeneratedOnAdd();\n            builder.Property(o => o.MockTitle).IsRequired().HasMaxLength(50);\n            builder.Property(o => o.CreatedDate).IsRequired();\n            builder.Property(o => o.Active).IsRequired();\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/Entities/MockEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.EntityFramework.Tests.Entities\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class MockEntity : LiquidEntity<int>\n    {\n        /// <summary>\n        /// Gets or sets the mock identifier.\n        /// </summary>\n        /// <value>\n        /// The mock identifier.\n        /// </value>\n        public int MockId\n        {\n            get => Id;\n            set => Id = value;\n        }\n\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n\n        public MockSubEntity SubEntity { get; set; }\n\n    }\n}"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/Entities/MockSubEntity.cs",
    "content": "﻿namespace Liquid.Repository.EntityFramework.Tests.Entities\n{\n    public class MockSubEntity\n    {\n        public int Id { get; set; }\n        public string Name { get; set; }\n    }\n}"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/EntityFrameworkDataContextTests.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\nusing Microsoft.EntityFrameworkCore.Infrastructure;\nusing NSubstitute;\n\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Repository.EntityFramework.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class EntityFrameworkDataContextTests\n    {\n        private EntityFrameworkDataContext<DbContext> _sut;\n        private DbContext _client;\n        private DatabaseFacade _database;\n\n        \n        public EntityFrameworkDataContextTests()\n        {\n\n            _client = Substitute.For<DbContext>();\n\n            _database = Substitute.For<DatabaseFacade>(_client);\n\n            _client.Database.Returns(_database);\n\n            _sut = new EntityFrameworkDataContext<DbContext>(_client);\n        }\n\n        [Fact]\n        public async Task StartTransactionAsync_WhenClientExecutedSucessfuly_Success()\n        {\n            await _sut.StartTransactionAsync();\n\n            await _client.Database.Received(1).BeginTransactionAsync();\n        }\n\n        [Fact]\n        public async Task StartTransactionAsync_WhenClientThrow_ThrowException()\n        {\n            _database.When(o => o.BeginTransactionAsync()).Do((call) => throw new Exception());\n\n            var task = _sut.StartTransactionAsync();\n\n            await Assert.ThrowsAsync<Exception>(() => task);\n        }\n\n        [Fact]\n        public async Task CommitAsync_WhenClientExecutedSucessfuly_Success()\n        {\n            await _sut.CommitAsync();\n\n            await _client.Database.Received(1).CommitTransactionAsync();\n        }\n\n        [Fact]\n        public async Task CommitAsync_WhenClientExcept_ThrowException()\n        {\n            _database.When(o => o.CommitTransactionAsync()).Do((call) => throw new Exception());\n\n            var task = _sut.CommitAsync();\n\n            await Assert.ThrowsAsync<Exception>(() => task);\n        }\n\n        [Fact]\n        public async Task RollbackTransactionAsync_WhenClientExecutedSucessfuly_Success()\n        {\n            await _sut.RollbackTransactionAsync();\n\n            await _client.Database.Received(1).RollbackTransactionAsync();\n        }\n\n        [Fact]\n        public async Task RollbackTransactionAsync_WhenClientExcept_ThrowException()\n        {\n            _database.When(o => o.RollbackTransactionAsync()).Do((call) => throw new Exception());\n\n            var task = _sut.RollbackTransactionAsync();\n\n            await Assert.ThrowsAsync<Exception>(() => task);\n        }\n\n        [Fact]\n        public void Verify_Dispose()\n        {\n            _sut.Dispose();\n\n            _client.Received(1).Dispose();\n\n            // Try to dispose twice to cover all conditions on Dispose method\n            _sut.Dispose();\n        }\n\n        [Fact]\n        public void Verify_Dispose_Except()\n        {\n            _client.When(o => o.Dispose()).Do((call) => throw new Exception());\n\n            Assert.Throws<Exception>(() => _sut.Dispose());\n        }\n\n        [Fact]\n        public void EntityFrameworkDataContext_WhenCreated_DbContextIsValid()\n        {\n            Assert.NotNull(_sut.DbClient);\n            Assert.IsAssignableFrom<DbContext>(_sut.DbClient);\n        }\n\n        [Fact]\n        public void EntityFrameworkDataContext_WhenCreatedWithoutDbContext_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new EntityFrameworkDataContext<DbContext>(null));\n        }\n\n        [Fact]\n        public void EntityFrameworkDataContext_IdIsAlwaysNull()\n        {\n            Assert.Null(_sut.Id);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/EntityFrameworkRepositoryTest.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.Repository.EntityFramework.Extensions;\nusing Liquid.Repository.EntityFramework.Tests.Entities;\nusing Microsoft.EntityFrameworkCore;\nusing Microsoft.Extensions.DependencyInjection;\nusing NSubstitute;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Repository.EntityFramework.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class EntityFrameworkRepositoryTest\n    {\n        private IServiceProvider _serviceProvider;\n\n\n        public EntityFrameworkRepositoryTest()\n        {\n            var services = new ServiceCollection();\n            var databaseName = $\"TEMP_{Guid.NewGuid()}\";\n\n            services.AddLiquidEntityFramework<MockDbContext, MockEntity, int>(options => options.UseInMemoryDatabase(databaseName: databaseName));\n\n            _serviceProvider = services.BuildServiceProvider();\n\n            SeedDataAsync(_serviceProvider);\n        }\n\n        private EntityFrameworkRepository<MockEntity, int, MockDbContext> GenerateMockRepository()\n        {\n            return _serviceProvider.GetService<EntityFrameworkRepository<MockEntity, int, MockDbContext>>();\n        }\n\n        private EntityFrameworkRepository<MockEntity, int, MockDbContext> GenerateMockRepository(DbSet<MockEntity> dbSet)\n        {\n            var dbContext = Substitute.For<MockDbContext>();\n            dbContext.Set<MockEntity>().Returns(dbSet);\n\n            var dataContext = Substitute.For<IEntityFrameworkDataContext<MockDbContext>>();\n\n            dataContext.DbClient.Returns(dbContext);\n\n            return new EntityFrameworkRepository<MockEntity, int, MockDbContext>(dataContext);\n        }\n                \n        [Fact]\n        public async Task Verify_insert()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n            var entity = new MockEntity { MockTitle = \"TITLE\", Active = true, CreatedDate = DateTime.Now };\n\n            //Act\n            await mockRepository.AddAsync(entity);\n\n            //Assert\n            Assert.NotNull(entity);\n            Assert.NotEqual(default, entity.MockId);\n        }\n\n        [Fact]\n        public async Task Verify_insert_Except()\n        {\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n            dbSet.When(o => o.AddAsync(Arg.Any<MockEntity>())).Do((call) => throw new Exception());\n\n            var mockRepository = GenerateMockRepository(dbSet);\n            var entity = new MockEntity { MockTitle = \"TITLE\", Active = true, CreatedDate = DateTime.Now };\n\n            //Act\n            var task = mockRepository.AddAsync(entity);\n\n            //Assert\n            await Assert.ThrowsAsync<Exception>(() => task);\n        }\n\n        [Fact]\n        public async Task Verify_find_by_id()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n            var mockId = 1;\n\n            //Act\n            var entity = await mockRepository.FindByIdAsync(mockId);\n\n            //Assert\n            Assert.NotNull(entity);\n            Assert.Equal(mockId, entity.MockId);\n        }\n\n        [Fact]\n        public async Task Verify_find_by_id_Except()\n        {\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n            var mockRepository = GenerateMockRepository(dbSet);\n            var mockId = 1;\n\n            //Act\n            var task = mockRepository.FindByIdAsync(mockId);\n\n            //Assert\n            await Assert.ThrowsAsync<ArgumentNullException>(() => task);\n        }\n\n        [Fact]\n        public async Task Verify_where()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n            string mockTitle = \"TITLE_002\";\n\n            //Act\n            var result = await mockRepository.WhereAsync(o => o.MockTitle.Equals(mockTitle));\n\n            //Assert\n            Assert.NotNull(result);\n            Assert.NotEmpty(result);\n            Assert.True(result.All(o => o.MockTitle.Equals(mockTitle)));\n        }\n\n        [Fact]\n        public async Task Verify_where_Except()\n        {\n            //Arrange\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n            var mockRepository = GenerateMockRepository(dbSet);\n            string mockTitle = \"TITLE_002\";\n\n            //Act\n            var task = mockRepository.WhereAsync(o => o.MockTitle.Equals(mockTitle));\n\n            //Assert\n            await Assert.ThrowsAsync<ArgumentNullException>(() => task);\n        }\n\n        [Fact]\n        public async Task Verify_find_all()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n\n            //Act\n            var result = await mockRepository.FindAllAsync();\n\n            //Assert\n            Assert.NotNull(result);\n            Assert.NotEmpty(result);\n            Assert.Equal(100, result.Count());\n        }\n\n        [Fact]\n        public async Task Verify_find_all_Except()\n        {\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n\n            var mockRepository = GenerateMockRepository(dbSet);\n\n            //Act\n            var result = await mockRepository.FindAllAsync();\n\n            //Assert\n            Assert.Empty(result);\n        }             \n\n        [Fact]\n        public async Task Verify_delete()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n            var mockId = 1;\n\n            //Act\n            await mockRepository.RemoveByIdAsync(mockId);\n            var anotherEntity = await mockRepository.FindByIdAsync(mockId);\n\n            //Assert\n            Assert.Null(anotherEntity);\n        }\n\n        [Fact]\n        public async Task Verify_delete_invalid()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n            var mockId = 101;\n\n            //Act\n            await mockRepository.RemoveByIdAsync(mockId);\n            var anotherEntity = await mockRepository.FindByIdAsync(mockId);\n\n            //Assert\n            Assert.Null(anotherEntity);\n        }\n\n        [Fact]\n        public async Task Verify_delete_Except()\n        {\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n            var mockRepository = GenerateMockRepository(dbSet);\n            var mockId = 1;\n\n            //Act\n            var task = mockRepository.RemoveByIdAsync(mockId);\n\n            //Assert\n            await Assert.ThrowsAsync<InvalidOperationException>(() => task);\n        }\n\n        [Fact]\n        public async Task Verify_updates()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n            var mockId = 1;\n\n            //Act\n            var entity = await mockRepository.FindByIdAsync(mockId);\n            entity.MockTitle = $\"TITLE_001_UPDATED\";\n            await mockRepository.UpdateAsync(entity);\n            var anotherEntity = await mockRepository.FindByIdAsync(mockId);\n\n            //Assert\n            Assert.NotNull(anotherEntity);\n            Assert.Equal(\"TITLE_001_UPDATED\", anotherEntity.MockTitle);\n        }\n\n        [Fact]\n        public async Task Verify_updates_Except()\n        {\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n            var mockRepository = GenerateMockRepository(dbSet);\n            var mockId = 1;\n\n            //Act\n            var task = mockRepository.UpdateAsync(new MockEntity() { MockId = mockId });\n\n            //Assert\n            await Assert.ThrowsAsync<ArgumentNullException>(() => task);\n        }\n\n        private void SeedDataAsync(IServiceProvider serviceProvider)\n        {\n            MockDbContext dbContext = serviceProvider.GetService<MockDbContext>();\n\n            for (int i = 1; i <= 100; i++)\n            {\n                dbContext.AddAsync(new MockEntity() { MockId = i, MockTitle = $\"TITLE_{i:000}\", Active = true, CreatedDate = DateTime.Now })\n                    .GetAwaiter().GetResult();\n            }\n            dbContext.SaveChangesAsync().GetAwaiter().GetResult();\n        }\n\n        [Fact]\n        public void EntityFrameworkRepository_WhenCreatedWithoutDataContext_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new EntityFrameworkRepository<MockEntity, int, MockDbContext>(null));\n        }\n\n        [Fact]\n        public void EntityFrameworkRepository_WhenCreated_DataContextIsValid()\n        {\n            //Arrange\n            var dbSet = Substitute.For<DbSet<MockEntity>, IQueryable<MockEntity>>();\n            var mockRepository = GenerateMockRepository(dbSet);\n\n            //Act\n            var dataContext = mockRepository.DataContext;\n            var entityFrameworkDataContext = mockRepository.EntityDataContext;\n\n            //Assert\n            Assert.NotNull(dataContext);\n            Assert.IsAssignableFrom<ILiquidDataContext>(dataContext);\n\n            Assert.NotNull(entityFrameworkDataContext);\n            Assert.IsAssignableFrom<IEntityFrameworkDataContext<MockDbContext>>(entityFrameworkDataContext);\n        }\n\n        [Fact]\n        public void WhereInclude_WhenCalled_ReturnsExpected()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n\n            //Act\n            var result = mockRepository.WhereInclude(o => o.MockTitle.Equals(\"TITLE_002\"), new string[] {\"SubEntity\" });\n\n            //Assert\n            Assert.NotNull(result);\n            Assert.NotEmpty(result);\n            Assert.True(result.All(o => o.MockTitle.Equals(\"TITLE_002\")));\n        }\n\n        [Fact]\n        public void WhereInclude_WhenCalledExpressionOverload_ReturnsExpected()\n        {\n            //Arrange\n            var mockRepository = GenerateMockRepository();\n\n            //Act\n            var result = mockRepository.WhereInclude(o => o.MockTitle.Equals(\"TITLE_002\"), o => o.SubEntity);\n\n            //Assert\n            Assert.NotNull(result);\n            Assert.NotEmpty(result);\n            Assert.True(result.All(o => o.MockTitle.Equals(\"TITLE_002\")));\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/Liquid.Repository.EntityFramework.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.msbuild\" Version=\"6.0.2\"> \n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"Microsoft.EntityFrameworkCore.InMemory\" Version=\"8.0.6\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Repository.EntityFramework\\Liquid.Repository.EntityFramework.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Repository.EntityFramework.Tests/MockDbContext.cs",
    "content": "﻿using Microsoft.EntityFrameworkCore;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.EntityFramework.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class MockDbContext : DbContext\n    {\n        public MockDbContext() : base() { }\n\n        public MockDbContext(DbContextOptions<MockDbContext> options) : base(options) { }\n\n\n        protected override void OnModelCreating(ModelBuilder modelBuilder)\n        {\n            modelBuilder.ApplyConfigurationsFromAssembly(GetType().Assembly);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/IServiceCollectionExtensionsTests.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Repository.Mongo.Extensions;\nusing Liquid.Repository.Mongo.Tests.Mock;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing Microsoft.Extensions.Logging;\nusing EphemeralMongo;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing Liquid.Core.Interfaces;\nusing Xunit;\n\nnamespace Liquid.Repository.Mongo.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class IServiceCollectionExtensionsTests\n    {\n        internal const string _databaseName = \"TestDatabase\";\n\n        private IServiceCollection _services;\n        private IServiceProvider _serviceProvider;\n        private IConfiguration _configuration;\n        private IMongoRunner _runner;\n\n        public IServiceCollectionExtensionsTests()\n        {\n            var options = new MongoRunnerOptions\n            {\n                UseSingleNodeReplicaSet = false,\n                AdditionalArguments = \"--quiet\",                \n            };\n\n            _runner = MongoRunner.Run(options);\n\n            _services = new ServiceCollection();\n\n            _services.AddSingleton(Substitute.For<ILogger<LiquidTelemetryInterceptor>>());\n                        \n\n            var mongoEntityConfiguration = new Dictionary<string, string>\n            {\n                {\"MyMongoEntityOptions:Settings:1:DatabaseName\", _databaseName},\n                {\"MyMongoEntityOptions:Settings:1:ConnectionString\", _runner.ConnectionString},\n                {\"MyMongoEntityOptions:Settings:1:CollectionName\", \"ATestEntity\"},\n                {\"MyMongoEntityOptions:Settings:1:ShardKey\", \"id\"},\n                {\"MyMongoEntityOptions:Settings:2:DatabaseName\", _databaseName},\n                {\"MyMongoEntityOptions:Settings:2:ConnectionString\", _runner.ConnectionString},\n                {\"MyMongoEntityOptions:Settings:2:CollectionName\", \"AnotherTestEntity\"},\n                {\"MyMongoEntityOptions:Settings:2:ShardKey\", \"id\"},\n            };\n\n            _configuration = new ConfigurationBuilder()\n                                        .AddInMemoryCollection(mongoEntityConfiguration).Build();\n\n            _services.AddSingleton<IConfiguration>(_configuration);\n        }\n\n        [Fact]\n        public void AddLiquidMongoRepository_WhenAdded_ServicesIsFilledForTestEntity()\n        {\n            _services.AddLiquidMongoRepository<TestEntity, int>(\"MyMongoEntityOptions\",\"ATestEntity\");\n            _services.AddLiquidMongoRepository<AnotherTestEntity, int>(\"MyMongoEntityOptions\", \"AnotherTestEntity\");\n            _serviceProvider = _services.BuildServiceProvider();\n            Assert.NotNull(_serviceProvider.GetService<IMongoDataContext<TestEntity>>());\n            Assert.NotNull(_serviceProvider.GetService<ILiquidRepository<TestEntity, int>>());\n            Assert.NotNull(_serviceProvider.GetService<IMongoDataContext<AnotherTestEntity>>());\n            Assert.NotNull(_serviceProvider.GetService<ILiquidRepository<AnotherTestEntity, int>>());\n\n        }\n        \n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/Liquid.Repository.Mongo.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n\t  <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.13.0\" />\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.4\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.msbuild\" Version=\"6.0.4\">\n      <PrivateAssets>all</PrivateAssets>\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n    </PackageReference>\n\t<PackageReference Include=\"EphemeralMongo.Core\" Version=\"2.0.0\" />\n\t<PackageReference Include=\"EphemeralMongo8.runtime.linux-x64\" Version=\"2.0.0\" Condition=\"$([MSBuild]::IsOSPlatform('Linux'))\" />\n\t<PackageReference Include=\"EphemeralMongo8.runtime.osx-x64\" Version=\"2.0.0\" Condition=\"$([MSBuild]::IsOSPlatform('OSX'))\" />\n\t<PackageReference Include=\"EphemeralMongo8.runtime.win-x64\" Version=\"2.0.0\" Condition=\"$([MSBuild]::IsOSPlatform('Windows'))\" />\n\t<PackageReference Include=\"Microsoft.Extensions.Configuration\" Version=\"9.0.4\" />\n\t<PackageReference Include=\"NSubstitute\" Version=\"5.3.0\" />\n\t  <PackageReference Include=\"xunit\" Version=\"2.9.3\" />\n\t  <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"3.1.0\">\n\t\t  <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n\t\t  <PrivateAssets>all</PrivateAssets>\n\t  </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Repository.Mongo\\Liquid.Repository.Mongo.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/Mock/AnotherTestEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.Mongo.Tests.Mock\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class AnotherTestEntity : LiquidEntity<int>\n    {\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/Mock/AsyncCursorMock.cs",
    "content": "﻿using MongoDB.Driver;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.Mongo.Tests.Mock\n{\n    [ExcludeFromCodeCoverage]\n    class AsyncCursorMock<TDocument> : IAsyncCursor<TDocument>\n    {\n        public IEnumerable<TDocument> Current { get; set; }\n\n        public AsyncCursorMock(IEnumerable<TDocument> documents)\n        {\n            Current = documents;\n        }\n\n        public void Dispose()\n        {\n            Dispose(true);\n            System.GC.SuppressFinalize(this);\n        }\n\n        protected virtual void Dispose(bool disposing)\n        {\n            Current.GetEnumerator().Dispose();\n        }\n\n        public bool MoveNext(CancellationToken cancellationToken = default)\n        {\n            return Current.GetEnumerator().MoveNext();\n        }\n\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<bool> MoveNextAsync(CancellationToken cancellationToken = default)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            return Current.GetEnumerator().MoveNext();\n        }\n\n        public IEnumerable<TDocument> ToEnumerable()\n        {\n            return Current.ToList();\n        }\n    }\n}\n\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/Mock/TestEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.Mongo.Tests.Mock\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class TestEntity : LiquidEntity<int>\n    {\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/MongoClientFactoryTests.cs",
    "content": "﻿using EphemeralMongo;\nusing Liquid.Core.Settings;\nusing Liquid.Repository.Mongo.Settings;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing Xunit;\n\nnamespace Liquid.Repository.Mongo.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class MongoClientFactoryTests\n    {\n        private IMongoClientFactory _sut;\n        internal static IMongoRunner _runner;\n        internal const string _databaseName = \"TestDatabase\";\n        private IOptions<MongoDbSettings> _options;\n        public MongoClientFactoryTests()\n        {\n            var options = new MongoRunnerOptions\n            {\n                UseSingleNodeReplicaSet = false,\n                AdditionalArguments = \"--quiet\",\n            };\n\n            _runner = MongoRunner.Run(options);\n\n\n            _options = Substitute.For<IOptions<MongoDbSettings>>();\n\n            var settings = new MongoDbSettings()\n            {\n                Settings = new System.Collections.Generic.List<MongoEntitySettings>()\n                {\n                    new MongoEntitySettings()\n                    {\n                        CollectionName = \"TestEntities\",\n                        ShardKey = \"id\",\n                        ConnectionString = _runner.ConnectionString,\n                        DatabaseName = _databaseName\n                    },\n                    new MongoEntitySettings()\n                    {\n                        CollectionName = \"TestEntities2\",\n                        ShardKey = \"id\",\n                        ConnectionString = \"\",\n                        DatabaseName = $\"{_databaseName}-2\"\n                    }\n                }\n            };\n\n            _options.Value.Returns(settings);\n\n            _sut = new MongoClientFactory(_options);\n        }\n\n\n        [Fact]\n        public void MongoClientFactory_WhenSettingsIsNull_ThrowException()\n        {\n            MongoEntitySettings settings = null;\n            Assert.Throws<ArgumentNullException>(() => _sut.GetClient(null, out settings));\n        }\n\n        [Fact]\n        public void GetClient_WhenDatabaseIdsExists_ClientCreated()\n        {\n            MongoEntitySettings settings = null;\n            var result = _sut.GetClient(\"TestEntities\", out settings);\n\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public void GetClient_WhenDatabaseSettingsIsWrong_ThrowException()\n        {\n            MongoEntitySettings settings = null;\n            Assert.Throws<MongoDB.Driver.MongoConfigurationException>(() => _sut.GetClient(\"TestEntities2\", out settings));\n        }\n\n        [Fact]\n        public void Constructor_WhenSettingsIsNull_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new MongoClientFactory(null));\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/MongoDataContextTests.cs",
    "content": "﻿using Liquid.Core.Settings;\nusing Liquid.Repository.Mongo.Settings;\nusing Liquid.Repository.Mongo.Tests.Mock;\nusing MongoDB.Driver;\nusing NSubstitute;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Repository.Mongo.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class MongoDataContextTests\n    {\n        private MongoDataContext<TestEntity> _sut;\n        private IMongoClient _client;\n        private IMongoClientFactory _provider;\n\n        public MongoDataContextTests()\n        {\n            _client = Substitute.For<IMongoClient>();\n\n            var _options = new MongoEntitySettings()\n            {\n                CollectionName = \"TestEntities\",\n                ShardKey = \"id\",\n                ConnectionString = \"test connection string\",\n                DatabaseName = \"TestDatabase\"\n\n            };           \n\n            _provider = Substitute.For<IMongoClientFactory>();\n\n            _provider.GetClient(\"TestEntities\", out _).Returns(x => { x[1] = _options; return _client; });\n\n            _sut = new MongoDataContext<TestEntity>(_provider, \"TestEntities\");\n        }\n\n        [Fact]\n        public void MongoDataContext_WhenCreatedWithNullArguments_ThrowsException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new MongoDataContext<TestEntity>(null, \"TestEntities\"));\n            Assert.Throws<ArgumentNullException>(() => new MongoDataContext<TestEntity>(_provider, null));\n        }\n\n\n        [Fact]\n        public async Task StartTransaction_WhenDBInitialized_Sucess()\n        {\n            await _sut.StartTransactionAsync();\n\n            await _client.Received(1).StartSessionAsync();\n\n        }\n\n        [Fact]\n        public async Task CommitAsync_WhenTansactionIsStarted_Sucess()\n        {\n            await _sut.StartTransactionAsync();\n\n            await _sut.CommitAsync();\n\n            await _sut.ClientSessionHandle.Received().CommitTransactionAsync();\n\n        }\n\n        [Fact]\n        public async Task CommitAsync_WhenTansactionIsntStarted_ThrowException()\n        {\n            var task = _sut.CommitAsync();\n\n            await Assert.ThrowsAsync<NullReferenceException>(() => task);\n        }\n\n        [Fact]\n        public async Task RollbackAsync_WhenTansactionIsStarted_Sucess()\n        {\n\n            await _sut.StartTransactionAsync();\n            await _sut.RollbackTransactionAsync();\n\n            await _sut.ClientSessionHandle.Received().AbortTransactionAsync();\n\n        }\n\n        [Fact]\n        public async Task RollbackAsync_WhenTansactionIsntStarted_ThrowException()\n        {\n            var task = _sut.RollbackTransactionAsync();\n\n            await Assert.ThrowsAsync<NullReferenceException>(() => task);\n\n        }\n\n        [Fact]\n        public async Task Dispose_WhenTansactionIsStarted_Sucess()\n        {\n            await _sut.StartTransactionAsync();\n            _sut.ClientSessionHandle.IsInTransaction.Returns(true);\n\n            _sut.Dispose();\n\n            _sut.ClientSessionHandle.Received().AbortTransaction();\n            _sut.ClientSessionHandle.Received().Dispose();\n\n        }\n\n        [Fact]\n        public async Task Dispose_WhenTansactionIsntStarted_HandlerDisposed()\n        {\n            await _sut.StartTransactionAsync();\n            _sut.ClientSessionHandle.IsInTransaction.Returns(false);\n\n            _sut.Dispose();\n\n            _sut.ClientSessionHandle.DidNotReceive().AbortTransaction();\n            _sut.ClientSessionHandle.Received().Dispose();\n\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.Mongo.Tests/MongoRepositoryTests.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.Core.Settings;\nusing Liquid.Repository.Mongo.Settings;\nusing Liquid.Repository.Mongo.Tests.Mock;\nusing MongoDB.Driver;\nusing NSubstitute;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Linq;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.Repository.Mongo.Tests\n{\n    [ExcludeFromCodeCoverage]\n    public class MongoRepositoryTests\n    {\n        private IMongoDataContext<TestEntity> _dbDataContext;\n        private ILiquidRepository<TestEntity, int> _sut;\n        private TestEntity _entity;\n        internal static string _databaseName = \"IntegrationTest\";\n        internal static string _collectionName = \"TestEntities\";\n        private IMongoCollection<TestEntity> _collection;\n\n        public MongoRepositoryTests()\n        {\n\n            _entity = new TestEntity()\n            {\n                CreatedDate = DateTime.Now,\n                Active = true,\n                Id = 1234,\n                MockTitle = \"test\"\n            };\n\n            var _options = new MongoEntitySettings()\n            {\n                CollectionName = _collectionName,\n                ShardKey = \"id\",\n                DatabaseName = _databaseName,\n                ConnectionString = \"test connection string\"\n            };\n\n            _dbDataContext = Substitute.For<IMongoDataContext<TestEntity>>();\n            _dbDataContext.Settings.Returns(_options);\n\n            IClientSessionHandle handle = null;\n\n            _dbDataContext.ClientSessionHandle.Returns(handle, handle);\n\n            _collection = GetCollection();\n\n            _dbDataContext.Database.GetCollection<TestEntity>(_collectionName)\n                    .Returns(_collection);\n\n            _sut = new MongoRepository<TestEntity, int>(_dbDataContext);\n        }\n\n        private IMongoCollection<TestEntity> GetCollection()\n        {\n            var listEntities = new List<TestEntity>() { _entity };\n\n            var result = Substitute.For<IMongoCollection<TestEntity>>();\n\n            var cursor = new AsyncCursorMock<TestEntity>(listEntities.AsEnumerable());\n\n            result.FindAsync<TestEntity>(Arg.Any<FilterDefinition<TestEntity>>()).Returns(cursor);\n\n            return result;\n        }\n\n\n        [Fact]\n        public void MongoRepository_WhenCreatedWithNoDataContext_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new MongoRepository<TestEntity, int>(null));\n        }\n\n        [Fact]\n        public async Task ValidateCollection_WhenCollectionExists_Success()\n        {\n            await _sut.AddAsync(_entity);\n\n            _dbDataContext.Database.Received(1).GetCollection<TestEntity>(_collectionName);\n        }\n\n        [Fact]\n        public async Task AddAsync_WhenActionIsSuccessful_CallInsertOneMethod()\n        {\n\n            await _sut.AddAsync(_entity);\n\n            _dbDataContext.Database.Received(1).GetCollection<TestEntity>(_collectionName);\n\n            await _collection.Received(1).InsertOneAsync(_entity);\n        }\n\n        [Fact]\n        public async Task AddAsync_WhenClientThrowsError_ThrowException()\n        {\n            _collection.When(o => o.InsertOneAsync(Arg.Any<TestEntity>())).Do((call) => throw new Exception());\n\n            var test = _sut.AddAsync(_entity);\n\n            await Assert.ThrowsAsync<Exception>(() => test);\n        }\n\n        [Fact]\n        public async Task FindAllAsync_WhenCollectionExists_ReturnItens()\n        {\n            var result = await _sut.FindAllAsync();\n\n            _dbDataContext.Database.Received(1).GetCollection<TestEntity>(_collectionName);\n\n            Assert.NotNull(result);\n            Assert.Equal(result.FirstOrDefault(), _entity);\n\n        }\n\n        [Fact]\n        public async Task FindAllAsync_WhenClientThrowsError_ThrowException()\n        {\n            _dbDataContext.Database.When(o => o.GetCollection<TestEntity>(Arg.Any<string>())).Do((call) => throw new Exception());\n\n            var test = _sut.FindAllAsync();\n\n            await Assert.ThrowsAsync<Exception>(() => test);\n        }\n\n        [Fact]\n        public async Task FindByIdAsync_WhenItemExists_ReturnItem()\n        {\n\n            var result = await _sut.FindByIdAsync(1234);\n\n            _dbDataContext.Database.Received(1).GetCollection<TestEntity>(_collectionName);\n\n            Assert.True(result == _entity);\n\n        }\n\n        [Fact]\n        public async Task FindByIdAsync_WhenClientThrowsError_ThrowException()\n        {\n            _collection.When(o => o.FindAsync<TestEntity>(Arg.Any<FilterDefinition<TestEntity>>())).Do((call) => throw new Exception());\n\n            var test = _sut.FindByIdAsync(1234);\n\n            await Assert.ThrowsAsync<Exception>(() => test);\n\n        }\n\n        [Fact]\n        public async Task RemoveByIdAsync_WhenActionIsSuccessful_CallDeleteOneMethod()\n        {\n            await _sut.RemoveByIdAsync(_entity.Id);\n\n            _dbDataContext.Database.Received(1).GetCollection<TestEntity>(_collectionName);\n\n            await _collection.Received().DeleteOneAsync(Arg.Any<FilterDefinition<TestEntity>>());\n\n        }\n\n        [Fact]\n        public async Task RemoveByIdAsync_WhenClientThrowsError_ThrowException()\n        {\n            _collection.When(o => o.DeleteOneAsync(Arg.Any<FilterDefinition<TestEntity>>())).Do((call) => throw new Exception());\n\n            var test = _sut.RemoveByIdAsync(_entity.Id);\n\n            await Assert.ThrowsAsync<Exception>(() => test);\n        }\n\n        [Fact]\n        public async Task UpdateAsync_WhenActionIsSuccessful_CallReplaceOneMethod()\n        {\n\n            await _sut.UpdateAsync(_entity);\n\n            _dbDataContext.Database.Received().GetCollection<TestEntity>(_collectionName);\n\n            await _collection.Received().ReplaceOneAsync(Arg.Any<FilterDefinition<TestEntity>>(), _entity, Arg.Any<ReplaceOptions>());\n\n        }\n\n        [Fact]\n        public async Task UpdateAsync_WhenClientThrowsError_ThrowException()\n        {\n            _collection.When(o => o.ReplaceOneAsync(Arg.Any<FilterDefinition<TestEntity>>(), _entity, Arg.Any<ReplaceOptions>())).Do((call) => throw new Exception());\n\n            var test = _sut.UpdateAsync(_entity);\n\n            await Assert.ThrowsAsync<Exception>(() => test);\n        }\n\n        [Fact]\n        public async Task WhereAsync_WhenItensExists_ReturnItens()\n        {\n            var result = await _sut.WhereAsync(e => e.Id.Equals(_entity.Id));\n\n            _dbDataContext.Database.Received().GetCollection<TestEntity>(_collectionName);\n\n            Assert.NotNull(result);\n            Assert.Equal(result.FirstOrDefault(), _entity);\n        }\n\n        [Fact]\n        public async Task WhereAsync_WhenClientThrowsError_ThrowException()\n        {\n            _collection.When(o => o.FindAsync<TestEntity>(Arg.Any<FilterDefinition<TestEntity>>())).Do((call) => throw new Exception());\n\n            var test = _sut.WhereAsync(e => e.Id.Equals(_entity.Id));\n\n            await Assert.ThrowsAsync<Exception>(() => test);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/GlobalUsings.cs",
    "content": "global using Xunit;"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/IServiceCollectionExtensionTests.cs",
    "content": "﻿using Liquid.Core.Implementations;\nusing Liquid.Core.Interfaces;\nusing Liquid.Repository.OData.Extensions;\nusing Liquid.Repository.OData.Tests.Mock;\nusing Microsoft.Extensions.Configuration;\nusing Microsoft.Extensions.DependencyInjection;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.OData.Tests\n{\n    public class IServiceCollectionExtensionTests\n    {\n        private IServiceCollection _services;\n        private IServiceProvider _serviceProvider;\n        private IConfiguration _configuration;\n\n        public IServiceCollectionExtensionTests()\n        {\n            _services = new ServiceCollection();\n\n            var odataEntityConfiguration = new Dictionary<string, string>\n            {\n                {\"MyODataEntityOptions:Settings:1:BaseUrl\", \"http://localhost:5000\"},\n                {\"MyODataEntityOptions:Settings:1:EntityName\", \"TestEntity\"},\n                {\"MyODataEntityOptions:Settings:2:BaseUrl\", \"http://localhost:5000\"},\n                {\"MyODataEntityOptions:Settings:2:EntityName\", \"AnotherTestEntity\"},\n            };\n\n            _configuration = new ConfigurationBuilder()\n                                        .AddInMemoryCollection(odataEntityConfiguration).Build();\n\n            _services.AddSingleton<IConfiguration>(_configuration);\n        }\n\n        [Fact]\n        public void AddLiquidODataRepository_WhenAdded_ServicesIsFilledForTestEntity()\n        {\n            _services.AddLiquidOdataRepository<TestEntity, string>(\"MyODataEntityOptions\", \"TestEntity\");\n            _services.AddLiquidOdataRepository<AnotherTestEntity, int>(\"MyODataEntityOptions\", \"AnotherTestEntity\");\n            _serviceProvider = _services.BuildServiceProvider();\n            Assert.NotNull(_serviceProvider.GetService<ILiquidRepository<TestEntity, string>>());\n            Assert.NotNull(_serviceProvider.GetService<ILiquidRepository<AnotherTestEntity, int>>());\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/Liquid.Repository.OData.Tests.csproj",
    "content": "<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n    <IsTestProject>true</IsTestProject>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.Extensions.Configuration\" Version=\"8.0.0\" />\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Repository.OData\\Liquid.Repository.OData.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/Mock/AnotherTestEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.OData.Tests.Mock\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class AnotherTestEntity : LiquidEntity<int>\n    {\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/Mock/MockPeople.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.OData.Tests.Mock\n{\n    public class People : LiquidEntity<string>\n    {\n        public string UserName { get; set; }\n\n        public string FirstName { get; set; }\n\n        public string LastName { get; set; }\n\n        public string Emails { get; set; }\n\n        public string AddressInfo { get; set; }\n\n        public string Gender { get; set; }\n\n        public string Concurrency { get; set; }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/Mock/MyMockHttpMessageHandler.cs",
    "content": "﻿using System;\nusing System.Collections.Generic;\nusing System.Linq;\nusing System.Net.Http.Json;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.Repository.OData.Tests.Mock\n{\n    public class MyMockHttpMessageHandler : HttpMessageHandler\n    {\n        private readonly HttpStatusCode _statusCode;\n        private readonly object? _responseContent;\n\n        public MyMockHttpMessageHandler(HttpStatusCode statusCode, object? responseContent = null)\n        {\n            _statusCode = statusCode;\n            _responseContent = responseContent;\n        }\n\n        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\n        {\n            return await Task.FromResult(new HttpResponseMessage\n            {\n                StatusCode = _statusCode,\n                Content = JsonContent.Create(_responseContent)\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/Mock/TestEntity.cs",
    "content": "﻿using Liquid.Core.Entities;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.Repository.OData.Tests.Mock\n{\n    /// <summary>\n    /// Mock test entity class.\n    /// </summary>\n    /// <seealso>\n    ///     <cref>Liquid.Data.Entities.DataMappingBase{System.Int32}</cref>\n    /// </seealso>\n    [ExcludeFromCodeCoverage]\n    public class TestEntity : LiquidEntity<string>\n    {\n        /// <summary>\n        /// Gets or sets the mock title.\n        /// </summary>\n        /// <value>\n        /// The mock title.\n        /// </value>\n        public string MockTitle { get; set; }\n\n        /// <summary>\n        /// Gets or sets a value indicating whether this <see cref=\"MockEntity\"/> is active.\n        /// </summary>\n        /// <value>\n        ///   <c>true</c> if active; otherwise, <c>false</c>.\n        /// </value>\n        public bool Active { get; set; }\n\n        /// <summary>\n        /// Gets or sets the created date.\n        /// </summary>\n        /// <value>\n        /// The created date.\n        /// </value>\n        public DateTime CreatedDate { get; set; }\n\n    }\n}"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/ODataClientFactoryTests.cs",
    "content": "using Liquid.Core.Interfaces;\nusing Microsoft.Extensions.Options;\nusing NSubstitute;\n\nnamespace Liquid.Repository.OData.Tests\n{\n    public class ODataClientFactoryTests\n    {\n        private IODataClientFactory _sut;\n        private IOptions<ODataOptions> _options;\n        private ILiquidContext _context;\n\n        public ODataClientFactoryTests()\n        {\n            _options = Substitute.For<IOptions<ODataOptions>>();\n\n            var settings = new ODataOptions()\n            {\n                Settings = new List<ODataSettings>()\n                {\n                    new ODataSettings()\n                    {\n                        BaseUrl = \"http://localhost:5000\",\n                        EntityName = \"TestEntities\",\n                    }\n                }\n            };\n\n            _options.Value.Returns(settings);\n\n            _context = Substitute.For<ILiquidContext>();\n            _context.Get(\"OdataToken\").Returns(\"token\");\n            _context.current.ContainsKey(\"OdataToken\").Returns(true);\n\n            _sut = new ODataClientFactory(_options, _context);\n        }\n\n\n        [Fact]\n        public void ODataClientFactory_WhenEntityNameIsNotFound_ThrowException()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() => _sut.CreateODataClientAsync(\"TestEntities2\"));\n        }\n\n        [Fact]\n        public void ODataClientFactory_WhenEntityNameIsNull_ThrowException()\n        {\n            Assert.Throws<ArgumentOutOfRangeException>(() => _sut.CreateODataClientAsync(null));\n        }\n\n        [Fact]\n        public void OdataClientFactory_WhenValidateCertIsFalse_ReturnClient()\n        {\n            var client = _sut.CreateODataClientAsync(\"TestEntities\");\n\n            Assert.NotNull(client);\n        }\n\n        [Fact]\n        public void OdataClientFactory_WhenValidateCertIsTrue_ReturnClient()\n        {\n            var settings = new ODataSettings()\n            {\n                BaseUrl = \"http://localhost:5000\",\n                EntityName = \"TestEntities\",\n                ValidateCert = true\n            };\n\n            _options.Value.Returns(new ODataOptions()\n            {\n                Settings = new List<ODataSettings>() { settings }\n            });\n\n            var sut = new ODataClientFactory(_options, _context);\n\n            var client = sut.CreateODataClientAsync(\"TestEntities\");\n\n            Assert.NotNull(client);\n        }\n\n        [Fact]\n        public void OdataClientFactory_WhenTokenIsNotSet_ThrowException()\n        {\n            var context = Substitute.For<ILiquidContext>();\n\n            context.Get(\"OdataToken\").Returns(\"\");\n            context.current.ContainsKey(\"OdataToken\").Returns(true);\n\n            var sut = new ODataClientFactory(_options, context);\n\n            Assert.Throws<KeyNotFoundException>(() => sut.CreateODataClientAsync(\"TestEntities\"));\n        }\n\n        [Fact]\n        public void OdataClientFactory_WhenTokenIsNotSetInContext_ThrowException()\n        {\n            var context = Substitute.For<ILiquidContext>();\n\n            context.Get(\"OdataToken\").Returns(null);\n            context.current.ContainsKey(\"OdataToken\").Returns(false);\n\n            var sut = new ODataClientFactory(_options, context);\n\n            Assert.Throws<KeyNotFoundException>(() => sut.CreateODataClientAsync(\"TestEntities\"));\n        }\n\n        [Fact]\n        public void OdataClientFactory_WhenOptionsIsNull_ThrowException()\n        {\n            _options = null;\n\n            Assert.Throws<ArgumentNullException>(() => new ODataClientFactory(_options, _context));\n        }\n\n        [Fact]\n        public void OdataClientFactory_WhenContextIsNull_ThrowException()\n        {\n            _context = null;\n\n            Assert.Throws<ArgumentNullException>(() => new ODataClientFactory(_options, _context));\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Repository.OData.Tests/ODataRepositoryTests.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.Repository.OData.Extensions;\nusing Liquid.Repository.OData.Tests.Mock;\nusing NSubstitute;\nusing Simple.OData.Client;\nusing System.Linq.Expressions;\n\nnamespace Liquid.Repository.OData.Tests\n{\n    public class OdataRepositoryTests\n    {\n        private ILiquidRepository<People, string> _sut;\n\n        private IODataClient _client;\n\n        public OdataRepositoryTests()\n        {           \n\n            var factory = Substitute.For<IODataClientFactory>();           \n\n            _client = Substitute.For<IODataClient>();\n\n            factory.CreateODataClientAsync(Arg.Any<string>()).Returns(_client);\n\n            _sut = new ODataRepository<People, string>(factory, \"People\");\n\n        }\n\n        [Fact]\n        public void ODataRepository_WhenCreatedWithNoClientFactory_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new ODataRepository<TestEntity, string>(null, \"TestEntity\"));\n        }\n\n        [Fact]\n        public void ODataRepository_WhenCreatedWithNoEntityName_ThrowException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new ODataRepository<TestEntity, string>(Substitute.For<IODataClientFactory>(), null));\n        }\n\n        [Fact]\n        public async Task AddAsync_WhenActionIsSuccessful_CallClient()\n        {\n            var entity = new People();\n\n            await _sut.AddAsync(entity);\n\n            await _client.Received(1).For<People>().Set(entity).InsertEntryAsync();\n        }\n\n        [Fact]\n        public async Task FindAllAsync_WhenActionIsSuccessful_CallClient()\n        {\n\n            await _sut.FindAllAsync();\n\n            await _client.Received(1).For<People>().FindEntriesAsync();\n        }\n\n        [Fact]\n\n        public async Task FindByIdAsync_WhenActionIsSuccessful_CallClient()\n        {\n            await _sut.FindByIdAsync(\"id\");\n\n            await _client.Received(1).For<People>().Key(\"id\").FindEntryAsync();\n        }\n\n        [Fact]\n        public async Task RemoveByIdAsync_WhenActionIsSuccessful_CallClient()\n        {\n            await _sut.RemoveByIdAsync(\"id\");\n\n            await _client.Received(1).For<People>().Key(\"id\").DeleteEntryAsync();\n        }\n\n        [Fact]\n        public async Task UpdateAsync_WhenActionIsSuccessful_CallClient()\n        {\n            var entity = new People();\n\n            await _sut.UpdateAsync(entity);\n\n            await _client.Received(1).For<People>().Set(entity).UpdateEntryAsync();\n        }\n\n        [Fact]\n        public async Task WhereAsync_WhenActionIsSuccessful_CallClient()\n        {\n            Expression<Func<People, bool>> expression = e => e.Id.Equals(\"id\");\n\n            await _sut.WhereAsync(expression);\n\n            await _client.Received(1).For<People>().Filter(expression).FindEntriesAsync();\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Storage.AzureStorage.Tests/BlobClientFactoryTests.cs",
    "content": "using Microsoft.Extensions.Options;\nusing NSubstitute;\n\nnamespace Liquid.Storage.AzureStorage.Tests\n{\n    public class BlobClientFactoryTests\n    {\n\n        private readonly IBlobClientFactory _sut;\n        private readonly IOptions<StorageSettings> _options;\n\n        public BlobClientFactoryTests()\n        {\n            _options = Substitute.For<IOptions<StorageSettings>>();\n\n            var settings = new StorageSettings();\n            settings.Containers.Add(new ContainerSettings()\n            {\n                ContainerName = \"test\",\n                ConnectionString = \"testestestes\"\n            });\n\n            _options.Value.ReturnsForAnyArgs(settings);\n            _sut = new BlobClientFactory(_options);\n        }\n\n\n        [Fact]\n        public void Ctor_WhenOptionsIsNull_ThenReturnArgumentNullException()\n        {\n            Assert.Throws<ArgumentNullException>(() => new BlobClientFactory(null));\n        }\n\n        [Fact]\n        public void Ctor_WhenOptionsExists_ThenBlobClientFactoryInstance()\n        {\n            var result = new BlobClientFactory(_options);\n            Assert.NotNull(result);\n            Assert.IsType<BlobClientFactory>(result);\n        }\n        [Fact]\n        public void SetContainerClients_WhenOptionsNotSet_ThenThrowArgumentNullException()\n        {\n            var options = Substitute.For<IOptions<StorageSettings>>();\n            options.Value.ReturnsForAnyArgs(new StorageSettings());\n\n            var sut = new BlobClientFactory(options);\n\n            Assert.Throws<ArgumentNullException>(() => sut.SetContainerClients());\n\n        }\n\n        [Fact]\n        public void SetContainerClients_WhenContainerNameIsInvalid_ThenThrowFormatException()\n        {\n            Assert.True(_sut.Clients.Count == 0);\n            Assert.Throws<FormatException>(() => _sut.SetContainerClients());\n        }\n\n        [Fact]\n        public void GetContainerClient_WhenClientDoesntExists_ThenThrowArgumentException()\n        {\n            Assert.Throws<ArgumentException>(() => _sut.GetContainerClient(\"test\"));\n        }\n    }\n}"
  },
  {
    "path": "test/Liquid.Storage.AzureStorage.Tests/Liquid.Storage.AzureStorage.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n    <ImplicitUsings>enable</ImplicitUsings>\n    <Nullable>enable</Nullable>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.Storage.AzureStorage\\Liquid.Storage.AzureStorage.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.Storage.AzureStorage.Tests/LiquidStorageAzureTests.cs",
    "content": "﻿using Azure;\nusing Azure.Storage.Blobs;\nusing Azure.Storage.Blobs.Models;\nusing Azure.Storage.Blobs.Specialized;\nusing Azure.Storage.Sas;\nusing Liquid.Core.Entities;\nusing NSubstitute;\nusing System.Text;\n\nnamespace Liquid.Storage.AzureStorage.Tests\n{\n    public class LiquidStorageAzureTests\n    {\n        private readonly LiquidStorageAzure _sut;\n        private BlobContainerClient _blobContainerClient = Substitute.For<BlobContainerClient>();\n        private BlockBlobClient _blockBlobClient = Substitute.For<BlockBlobClient>();\n        public LiquidStorageAzureTests()\n        {\n            var clientFactory = Substitute.For<IBlobClientFactory>();\n\n            _blobContainerClient.GetBlockBlobClient(Arg.Any<string>()).Returns(_blockBlobClient);\n\n            clientFactory.GetContainerClient(Arg.Any<string>()).Returns(_blobContainerClient);\n\n            _sut = new LiquidStorageAzure(clientFactory);\n        }\n\n        [Fact]\n        public void Ctor_WhenClientFactoryIsNull_ThrowsArgumentNullException()\n        {\n            // Arrange\n            IBlobClientFactory clientFactory = null;\n            // Act & Assert\n            Assert.Throws<ArgumentNullException>(() => new LiquidStorageAzure(clientFactory));\n        }\n\n        [Fact]\n        public void Ctor_WhenClientFactoryIsNotNull_DoesNotThrow()\n        {\n            // Arrange\n            var clientFactory = Substitute.For<IBlobClientFactory>();\n            // Act & Assert\n            var exception = Record.Exception(() => new LiquidStorageAzure(clientFactory));\n            Assert.Null(exception);\n        }\n\n        [Fact]\n        public async void DeleteByTags_WhenTagsAreValid_DoesNotThrow()\n        {\n            // Arrange\n            var tags = new Dictionary<string, string>\n            {\n                { \"tag1\", \"value1\" },\n                { \"tag2\", \"value2\" }\n            };\n            var containerName = \"test-container\";\n\n            var page = Page<TaggedBlobItem>.FromValues(new List<TaggedBlobItem>\n            {\n                 BlobsModelFactory.TaggedBlobItem(\"test-blob\",\"test-container\", new Dictionary<string, string> { { \"tag1\", \"value1\" } }),\n                 BlobsModelFactory.TaggedBlobItem(\"test-blob\",\"test-container\", new Dictionary<string, string> { { \"tag2\", \"value2\" } })\n            }, continuationToken: null,Substitute.For<Response>());\n\n            var pages = AsyncPageable<TaggedBlobItem>.FromPages(new[] { page });\n\n            _blobContainerClient.FindBlobsByTagsAsync(Arg.Any<string>()).Returns(pages);\n\n            // Act & Assert\n            var exception = await Record.ExceptionAsync(() => _sut.DeleteByTags(tags, containerName));\n            Assert.Null(exception);\n        }\n\n        [Fact]\n        public async void GetAllBlobs_WhenContainerNameIsValid_ReturnsListOfLiquidBlob()\n        {\n            // Arrange\n            var containerName = \"test-container\";\n            var blobItem = BlobsModelFactory.BlobItem();\n\n            _blobContainerClient.GetBlobsAsync().Returns(AsyncPageable<BlobItem>.FromPages(new[] { Page<BlobItem>.FromValues(new[] { blobItem }, null, Substitute.For<Response>()) }));\n            _blockBlobClient.DownloadContentAsync().Returns(Response.FromValue(\n                BlobsModelFactory.BlobDownloadResult(new BinaryData(\"test-blob\")), null\n            ));\n            _blockBlobClient.GetTagsAsync().Returns(Response.FromValue(\n                BlobsModelFactory.GetBlobTagResult(new Dictionary<string, string> { { \"tag1\", \"value1\" } }), null\n            ));\n            _blockBlobClient.Uri.Returns(new Uri(\"https://test.blob.core.windows.net/test-blob\"));\n\n            // Act\n            var result = await _sut.GetAllBlobs(containerName);\n            // Assert\n            Assert.NotNull(result);\n            Assert.IsType<List<LiquidBlob>>(result);\n        }\n        [Fact]\n        public async void ReadBlobsByName_WhenBlobNameIsValid_ReturnsLiquidBlob()\n        {\n            // Arrange\n            var blobName = \"test-blob\";\n            var containerName = \"test-container\";\n\n            _blockBlobClient.DownloadContentAsync().Returns(Response.FromValue(\n                BlobsModelFactory.BlobDownloadResult(new BinaryData(\"test-blob\")), null\n            ));\n\n            _blockBlobClient.GetTagsAsync().Returns(Response.FromValue(\n                BlobsModelFactory.GetBlobTagResult(new Dictionary<string, string> { { \"tag1\", \"value1\" } }), null\n            ));\n\n            _blockBlobClient.Uri.Returns(new Uri(\"https://test.blob.core.windows.net/test-blob\"));\n\n            // Act\n            var result = await _sut.ReadBlobsByName(blobName, containerName);\n            // Assert\n            Assert.NotNull(result);\n            Assert.IsType<LiquidBlob>(result);\n        }\n\n        [Fact]\n        public async void ReadBlobsByName_WhenRequestFail_ThrowsException()\n        {\n            // Arrange\n            var blobName = \"test-blob\";\n            var containerName = \"test-container\";\n            _blockBlobClient.DownloadContentAsync().Returns(Task.FromException<Response<BlobDownloadResult>>(new Exception(\"Test exception\")));\n            // Act & Assert\n            await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() => _sut.ReadBlobsByName(blobName, containerName));\n        }\n\n        [Fact]\n        public async void ReadBlobsByName_WhenRequestFailedException_ReturnNull()\n        {\n            // Arrange\n            var blobName = \"test-blob\";\n            var containerName = \"test-container\";\n            _blockBlobClient.DownloadContentAsync().Returns(Task.FromException<Response<BlobDownloadResult>>(new RequestFailedException(0, \"BlobNotFound\", \"BlobNotFound\", new Exception())));\n            // Act\n            var result = await _sut.ReadBlobsByName(blobName, containerName);\n            // Assert\n            Assert.Null(result);\n        }\n\n        [Fact]\n        public async void UploadBlob_WhenDataIsValid_ReturnsBlobUri()\n        {\n            // Arrange\n            var data = Encoding.UTF8.GetBytes(\"test data\");\n            var name = \"test-blob\";\n            var containerName = \"test-container\";\n            var tags = new Dictionary<string, string>\n            {\n                { \"tag1\", \"value1\" },\n                { \"tag2\", \"value2\" }\n            };\n            _blockBlobClient.UploadAsync(Arg.Any<Stream>(), Arg.Any<BlobUploadOptions>()).Returns(Response.FromValue(\n                BlobsModelFactory.BlobContentInfo(ETag.All, DateTimeOffset.UtcNow, data, \"\", \"\", \"\", data.Length), null));\n\n            _blockBlobClient.Uri.Returns(new Uri(\"https://test.blob.core.windows.net/test-blob\"));\n            // Act\n            var result = await _sut.UploadBlob(data, name, containerName, tags);\n            // Assert\n            Assert.NotNull(result);\n\n        }\n\n        [Fact]\n        public async void UploadBlob_WhenDataIsNull_ThrowsArgumentNullException()\n        {\n            // Arrange\n            byte[] data = null;\n            var name = \"test-blob\";\n            var containerName = \"test-container\";\n            // Act & Assert\n            await Assert.ThrowsAsync<ArgumentNullException>(() => _sut.UploadBlob(data, name, containerName));\n        }\n\n        [Fact]\n\n        public void GetBlobSasUri_WhenBlobNameIsValid_ReturnsSasUri()\n        {\n            // Arrange\n            var blobName = \"test-blob\";\n            var containerName = \"test-container\";\n            var expiresOn = DateTimeOffset.UtcNow.AddHours(1);\n            var permissions = \"Read\";\n            _blobContainerClient.CanGenerateSasUri.Returns(true);\n            _blockBlobClient.GenerateSasUri(Arg.Any<BlobSasBuilder>()).Returns(new Uri(\"https://test.blob.core.windows.net/test-blob?sv=2020-08-04&ss=b&srt=sco&sp=r&se=2023-10-01T00:00:00Z&st=2023-09-01T00:00:00Z&spr=https,http&sig=signature\"));\n\n            // Act\n            var result = _sut.GetBlobSasUri(blobName, containerName, expiresOn, permissions);\n            // Assert\n            Assert.NotNull(result);\n        }\n\n        [Fact]\n        public void GetBlobSasUri_WhenCantGenerateSasUri_ReturnsNull()\n        {\n            // Arrange\n            var blobName = \"test-blob\";\n            var containerName = \"test-container\";\n            var expiresOn = DateTimeOffset.UtcNow.AddHours(1);\n            var permissions = \"Read\";\n            _blobContainerClient.CanGenerateSasUri.Returns(false);\n            // Act\n            var result = _sut.GetBlobSasUri(blobName, containerName, expiresOn, permissions);\n            // Assert\n            Assert.Null(result);\n        }\n\n        [Fact]\n        public async void Delete_WhenBlobNameIsValid_DoesNotThrow()\n        {\n            // Arrange\n            var blobName = \"test-blob\";\n            var containerName = \"test-container\";\n\n            var blobClient = Substitute.For<BlobClient>();\n            _blobContainerClient.GetBlobClient(Arg.Any<string>()).Returns(blobClient);\n\n            // Act & Assert\n            var exception = await Record.ExceptionAsync(() => _sut.Delete(blobName, containerName));\n\n            Assert.Null(exception);\n        }\n\n        [Fact]\n        public async void ReadBlobsByTags_WhenTagsAreValid_ReturnsListOfLiquidBlob()\n        {\n            // Arrange\n            var tags = new Dictionary<string, string>\n            {\n                { \"tag1\", \"value1\" },\n                { \"tag2\", \"value2\" }\n            };\n            var containerName = \"test-container\";\n\n            var page = Page<TaggedBlobItem>.FromValues(new List<TaggedBlobItem>\n            {\n                 BlobsModelFactory.TaggedBlobItem(\"test-blob\",\"test-container\", new Dictionary<string, string> { { \"tag1\", \"value1\" } }),\n                 BlobsModelFactory.TaggedBlobItem(\"test-blob\",\"test-container\", new Dictionary<string, string> { { \"tag2\", \"value2\" } })\n            }, continuationToken: null, Substitute.For<Response>());\n\n            var pages = AsyncPageable<TaggedBlobItem>.FromPages(new[] { page });\n\n            _blobContainerClient.FindBlobsByTagsAsync(Arg.Any<string>()).Returns(pages);\n\n            _blockBlobClient.DownloadContentAsync().Returns(Response.FromValue(\n                BlobsModelFactory.BlobDownloadResult(new BinaryData(\"test-blob\")), null\n            ));\n\n            _blockBlobClient.GetTagsAsync().Returns(Response.FromValue(\n                BlobsModelFactory.GetBlobTagResult(new Dictionary<string, string> { { \"tag1\", \"value1\" } }), null\n            ));\n\n            _blockBlobClient.Uri.Returns(new Uri(\"https://test.blob.core.windows.net/test-blob\"));\n            // Act\n            var result = await _sut.ReadBlobsByTags(tags, containerName);\n            // Assert\n            Assert.NotNull(result);\n            Assert.IsType<List<LiquidBlob>>(result);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.Storage.AzureStorage.Tests/Usings.cs",
    "content": "global using Xunit;"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/Liquid.WebApi.Http.Tests.csproj",
    "content": "﻿<Project Sdk=\"Microsoft.NET.Sdk\">\n\n  <PropertyGroup>\n    <TargetFramework>net8.0</TargetFramework>\n\n    <IsPackable>false</IsPackable>\n  </PropertyGroup>\n\n  <ItemGroup>\n    <PackageReference Include=\"Microsoft.NET.Test.Sdk\" Version=\"17.10.0\" />\n    <PackageReference Include=\"NSubstitute\" Version=\"5.1.0\" />\n    <PackageReference Include=\"xunit\" Version=\"2.8.1\" />\n    <PackageReference Include=\"xunit.runner.visualstudio\" Version=\"2.8.1\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n    <PackageReference Include=\"coverlet.collector\" Version=\"6.0.2\">\n      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>\n      <PrivateAssets>all</PrivateAssets>\n    </PackageReference>\n  </ItemGroup>\n\n  <ItemGroup>\n    <ProjectReference Include=\"..\\..\\src\\Liquid.WebApi.Http\\Liquid.WebApi.Http.csproj\" />\n  </ItemGroup>\n\n</Project>\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/LiquidControllerBaseTest.cs",
    "content": "using Liquid.WebApi.Http.UnitTests.Mocks;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing NSubstitute;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Threading.Tasks;\nusing Xunit;\n\nnamespace Liquid.WebApi.Http.UnitTests\n{\n    [ExcludeFromCodeCoverage]\n    public class LiquidControllerBaseTest\n    {\n        private TestController _sut;\n        private IMediator _mediator;\n\n        public LiquidControllerBaseTest()\n        {\n            _mediator = Substitute.For<IMediator>();\n            _sut = new TestController(_mediator);\n        }\n\n\n        [Fact]\n        public async Task ExecuteAsync_WhenIActionResultOverload_Return200()\n        {\n            var response = await _sut.GetCase1();\n\n            var result = (ObjectResult)response;\n\n            await _mediator.Received(1).Send(Arg.Any<TestCaseRequest>());\n\n            Assert.Equal(200, result.StatusCode);\n        }\n\n        [Fact]\n        public async Task ExecuteAsync_WhenGenericResultOverload_Return200()\n        {\n            var response = await _sut.GetCase2();\n\n            var result = (ObjectResult)response;\n\n            await _mediator.Received(1).Send(Arg.Any<TestCaseRequest>());\n\n            Assert.Equal(200, result.StatusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/LiquidNotificationHelperTest.cs",
    "content": "﻿using Liquid.Core.Interfaces;\nusing Liquid.WebApi.Http.Implementations;\nusing Liquid.WebApi.Http.Interfaces;\nusing Liquid.WebApi.Http.UnitTests.Mocks;\nusing NSubstitute;\nusing System.Collections.Generic;\nusing Xunit;\n\nnamespace Liquid.WebApi.Http.UnitTests\n{\n    public class LiquidNotificationHelperTest\n    {\n        private ILiquidNotificationHelper _sut;\n        private ILiquidContextNotifications _contextNotifications = Substitute.For<ILiquidContextNotifications>();\n        public LiquidNotificationHelperTest()\n        {\n            \n        }\n\n        [Fact]\n        public void IncludeMessages_WhenNotificationContextHasMessages_ResponseHasMessagesList()\n        {\n            _contextNotifications.GetNotifications().Returns(new List<string>()\n            {\n                \"test\",\n                \"case\"\n            });\n\n            _sut = new LiquidNotificationHelper(_contextNotifications);\n\n            var responseObject = new TestCaseResponse(\"With Messages\");\n\n            object response = _sut.IncludeMessages(responseObject);\n\n            var messages = response.GetType().GetProperty(\"messages\").GetValue(response);\n\n            Assert.NotNull(response.GetType().GetProperty(\"messages\").GetValue(response));\n        }\n\n        [Fact]\n        public void IncludeMessages_WhenNotificationContextHasNoMessages_ResponseWithoutMessages()\n        {\n            IList<string> notifications = default;\n\n            _contextNotifications.GetNotifications().Returns(notifications);\n\n            _sut = new LiquidNotificationHelper(_contextNotifications);\n\n            var responseObject = new TestCaseResponse(\"With Messages\");\n\n            object response = _sut.IncludeMessages(responseObject);\n\n            Assert.Null(response.GetType().GetProperty(\"messages\")?.GetValue(response));\n        }\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/Mocks/Handlers/TestCaseQueryHandler.cs",
    "content": "﻿using MediatR;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Text;\nusing System.Threading;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.UnitTests.Mocks\n{\n    [ExcludeFromCodeCoverage]\n    public class TestCaseQueryHandler : IRequestHandler<TestCaseRequest, TestCaseResponse>\n    {\n#pragma warning disable CS1998 // Async method lacks 'await' operators and will run synchronously\n        public async Task<TestCaseResponse> Handle(TestCaseRequest request, CancellationToken cancellationToken)\n#pragma warning restore CS1998 // Async method lacks 'await' operators and will run synchronously\n        {\n            var result = new TestCaseResponse(\"Successfull test.\");\n\n            return result;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/Mocks/Handlers/TestCaseRequest.cs",
    "content": "﻿using MediatR;\nusing System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.UnitTests.Mocks\n{\n    [ExcludeFromCodeCoverage]\n    public class TestCaseRequest : IRequest<TestCaseResponse>\n    {\n    }\n}\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/Mocks/Handlers/TestCaseResponse.cs",
    "content": "﻿using System.Diagnostics.CodeAnalysis;\n\nnamespace Liquid.WebApi.Http.UnitTests.Mocks\n{\n    [ExcludeFromCodeCoverage]\n    public class TestCaseResponse\n    {\n        public string MyProperty { get; set; }\n\n        public TestCaseResponse(string myProperty)\n        {\n            MyProperty = myProperty;\n        }\n    }\n}\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/Mocks/TestController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.UnitTests.Mocks\n{\n    [ExcludeFromCodeCoverage]\n    public class TestController : LiquidControllerBase\n    {\n        public TestController(IMediator mediator) : base(mediator)\n        {\n        }\n\n        \n        public async Task<IActionResult> GetCase1() => await ExecuteAsync(new TestCaseRequest(), HttpStatusCode.OK);\n\n        public async Task<IActionResult> GetCase2() => Ok(await ExecuteAsync(new TestCaseRequest()));\n\n    }\n}\n"
  },
  {
    "path": "test/Liquid.WebApi.Http.Tests/Mocks/TestNotificationController.cs",
    "content": "﻿using Liquid.WebApi.Http.Controllers;\nusing Liquid.WebApi.Http.Interfaces;\nusing MediatR;\nusing Microsoft.AspNetCore.Mvc;\nusing System;\nusing System.Collections.Generic;\nusing System.Diagnostics.CodeAnalysis;\nusing System.Net;\nusing System.Text;\nusing System.Threading.Tasks;\n\nnamespace Liquid.WebApi.Http.UnitTests.Mocks\n{\n    [ExcludeFromCodeCoverage]\n    public class TestNotificationController : LiquidControllerBase\n    {\n        private readonly ILiquidNotificationHelper _liquidNotification;\n        public TestNotificationController(IMediator mediator, ILiquidNotificationHelper liquidNotification) : base(mediator)\n        {\n            _liquidNotification = liquidNotification;\n        }\n\n\n        public async Task<IActionResult> GetCase2() => Ok(await ExecuteAsync(new TestCaseRequest()));\n\n    }\n}\n"
  }
]