diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..bfe16be
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,7 @@
+*
+!src
+!tests
+**/bin
+**/obj
+!AspNetCore.RestFramework.sln
+!scripts/*.sh
diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml
new file mode 100644
index 0000000..0d91f8d
--- /dev/null
+++ b/.github/workflows/pr.yml
@@ -0,0 +1,40 @@
+name: Validate PR
+
+on:
+ pull_request:
+ branches:
+ - main
+ paths:
+ - 'src/**'
+ - 'tests/**'
+ - '*.sln'
+ - 'Dockerfile'
+
+jobs:
+ validate:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ # Shallow clones should be disabled for a better relevancy of analysis
+ fetch-depth: 0
+ - uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: '8'
+ - name: Check if the project is well formatted
+ run: |
+ ./scripts/start-check-formatting.sh
+ - name: Install dotnet-sonarscanner
+ run: |
+ dotnet tool install --global dotnet-sonarscanner
+ - name: Build the project, run all tests, and publish the test results
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ PR_SOURCE_BRANCH: ${{ github.head_ref }}
+ PR_TARGET_BRANCH: ${{ github.base_ref }}
+ GITHUB_PR_NUMBER: ${{github.event.pull_request.number}}
+ run: |
+ set -e
+ docker compose up -d db
+ ./scripts/start-sonarcloud.sh
diff --git a/.github/workflows/publish-coverage.yml b/.github/workflows/publish-coverage.yml
new file mode 100644
index 0000000..d366daf
--- /dev/null
+++ b/.github/workflows/publish-coverage.yml
@@ -0,0 +1,33 @@
+name: Publish package and coverage report
+
+on:
+ push:
+ branches:
+ - main
+ paths:
+ - 'src/**'
+ - 'tests/**'
+ - '*.sln'
+ - 'Directory.Build.props'
+
+jobs:
+ publish-coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ # Shallow clones should be disabled for a better relevancy of analysis
+ fetch-depth: 0
+ - name: Install dotnet-sonarscanner
+ run: |
+ dotnet tool install --global dotnet-sonarscanner
+ - name: Build the project, run all tests and publish to SonarCloud
+ env:
+ SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
+ PROJECT_VERSION: ${{ github.sha }}
+ SOURCE_BRANCH_NAME: ${{ github.ref_name }}
+ run: |
+ set -e
+ docker compose up -d db
+ ./scripts/start-sonarcloud.sh
diff --git a/.github/workflows/publish-package.yml b/.github/workflows/publish-package.yml
new file mode 100644
index 0000000..5c246db
--- /dev/null
+++ b/.github/workflows/publish-package.yml
@@ -0,0 +1,29 @@
+name: Publish coverage report
+
+on:
+ push:
+ tags:
+ - '[0-9]+.[0-9]+.[0-9]+*'
+ workflow_dispatch:
+
+permissions:
+ contents: read
+
+jobs:
+ publish-coverage:
+ runs-on: ubuntu-latest
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 1
+ - name: Generate package
+ run: |
+ TAG_NAME=${GITHUB_REF#refs/tags/}
+ dotnet pack -o out -p:PackageVersion=$TAG_NAME
+ - name: Push package
+ run: |
+ dotnet nuget push out/*.nupkg \
+ --api-key ${{ secrets.PUBLIC_NUGET_API_KEY }} \
+ --source "https://api.nuget.org/v3/index.json" \
+ --skip-duplicate
diff --git a/AspNetCore.RestFramework.Core/AspNetCore.RestFramework.Core.csproj b/AspNetCore.RestFramework.Core/AspNetCore.RestFramework.Core.csproj
deleted file mode 100644
index 22b90db..0000000
--- a/AspNetCore.RestFramework.Core/AspNetCore.RestFramework.Core.csproj
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
- net6.0
- 0.0.1
- 0.0.1
-
-
-
-
-
-
-
-
-
-
diff --git a/AspNetCore.RestFramework.Sample/AspNetCore.RestFramework.Sample.csproj b/AspNetCore.RestFramework.Sample/AspNetCore.RestFramework.Sample.csproj
deleted file mode 100644
index 6ccb3ba..0000000
--- a/AspNetCore.RestFramework.Sample/AspNetCore.RestFramework.Sample.csproj
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
- net6.0
- AspNetRestFramework.Sample
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/AspNetCore.RestFramework.Sample/Context/ApplicationDbContext.cs b/AspNetCore.RestFramework.Sample/Context/ApplicationDbContext.cs
deleted file mode 100644
index c582fcf..0000000
--- a/AspNetCore.RestFramework.Sample/Context/ApplicationDbContext.cs
+++ /dev/null
@@ -1,27 +0,0 @@
-using AspNetRestFramework.Sample.Mappings;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.EntityFrameworkCore;
-
-namespace AspNetRestFramework.Sample.Context
-{
- public class ApplicationDbContext : DbContext
- {
- public ApplicationDbContext(DbContextOptions options) : base(options)
- {
- }
-
-
- public DbSet Customer { get; set; }
- public DbSet Seller { get; set; }
- public DbSet CustomerDocument { get; set; }
- public DbSet IntAsIdEntities { get; set; }
-
- protected override void OnModelCreating(ModelBuilder modelBuilder)
- {
- modelBuilder.ApplyConfiguration(new CustomerConfig());
- modelBuilder.ApplyConfiguration(new SellerConfig());
- modelBuilder.ApplyConfiguration(new CustomerDocumentConfig());
- modelBuilder.ApplyConfiguration(new IntAsIdEntityConfig());
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Controllers/CustomerDocumentsController.cs b/AspNetCore.RestFramework.Sample/Controllers/CustomerDocumentsController.cs
deleted file mode 100644
index ecb8236..0000000
--- a/AspNetCore.RestFramework.Sample/Controllers/CustomerDocumentsController.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using System;
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Filters;
-using AspNetCore.RestFramework.Core.Serializer;
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Filters;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-
-namespace AspNetRestFramework.Sample.Controllers;
-
-[Route("api/[controller]")]
-[ApiController]
-public class CustomerDocumentsController : BaseController
-{
- public CustomerDocumentsController(Serializer serializer, ApplicationDbContext context, ILogger logger) : base(serializer, context,logger)
- {
- AllowedFields = new[] {
- nameof(CustomerDocument.Document),
- nameof(CustomerDocument.DocumentType),
- nameof(CustomerDocument.CustomerId)
- };
-
- Filters.Add(new CustomerFilter());
- Filters.Add(new QueryStringFilter(AllowedFields));
- Filters.Add(new QueryStringSearchFilter(AllowedFields));
- Filters.Add(new QueryStringIdRangeFilter());
- }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Sample/Controllers/CustomersController.cs b/AspNetCore.RestFramework.Sample/Controllers/CustomersController.cs
deleted file mode 100644
index 5943fd3..0000000
--- a/AspNetCore.RestFramework.Sample/Controllers/CustomersController.cs
+++ /dev/null
@@ -1,41 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Filters;
-using Microsoft.AspNetCore.Mvc;
-using System;
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.CustomSerializers;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Filters;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.Extensions.Logging;
-
-namespace AspNetRestFramework.Sample.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class CustomersController : BaseController
- {
- public CustomersController(
- CustomerSerializer serializer,
- ApplicationDbContext dbContext,
- ILogger logger)
- : base(
- serializer,
- dbContext,
- logger)
- {
- AllowedFields = new[] {
- nameof(Customer.Id),
- nameof(Customer.Name),
- nameof(Customer.CNPJ),
- nameof(Customer.Age),
- };
-
- Filters.Add(new QueryStringFilter(AllowedFields));
- Filters.Add(new QueryStringSearchFilter(AllowedFields));
- Filters.Add(new QueryStringIdRangeFilter());
- Filters.Add(new DocumentFilter());
- Filters.Add(new CustomerDocumentIncludeFilter());
- }
- }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Sample/Controllers/IntAsIdEntitiesController.cs b/AspNetCore.RestFramework.Sample/Controllers/IntAsIdEntitiesController.cs
deleted file mode 100644
index def33e2..0000000
--- a/AspNetCore.RestFramework.Sample/Controllers/IntAsIdEntitiesController.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Filters;
-using AspNetCore.RestFramework.Core.Serializer;
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.AspNetCore.Mvc;
-using Microsoft.Extensions.Logging;
-
-namespace AspNetRestFramework.Sample.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class IntAsIdEntitiesController : BaseController
- {
- public IntAsIdEntitiesController(
- Serializer serializer,
- ApplicationDbContext context,
- ILogger logger)
- : base(
- serializer,
- context,
- new ActionOptions() { AllowPatch = false, AllowPut = false },
- logger)
- {
- AllowedFields = new[] {
- nameof(IntAsIdEntity.Id),
- nameof(IntAsIdEntity.Name),
- };
-
- Filters.Add(new QueryStringFilter(AllowedFields));
- Filters.Add(new QueryStringSearchFilter(AllowedFields));
- Filters.Add(new QueryStringIdRangeFilter());
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Controllers/SellersController.cs b/AspNetCore.RestFramework.Sample/Controllers/SellersController.cs
deleted file mode 100644
index 5f1d923..0000000
--- a/AspNetCore.RestFramework.Sample/Controllers/SellersController.cs
+++ /dev/null
@@ -1,35 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Serializer;
-using Microsoft.AspNetCore.Mvc;
-using System;
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.Extensions.Logging;
-using AspNetCore.RestFramework.Core.Filters;
-
-namespace AspNetRestFramework.Sample.Controllers
-{
- [Route("api/[controller]")]
- [ApiController]
- public class SellersController : BaseController
- {
- public SellersController(
- Serializer serializer,
- ApplicationDbContext dbContext,
- ILogger logger)
- : base(
- serializer,
- dbContext,
- logger)
- {
- AllowedFields = new[] {
- nameof(Seller.Name)
- };
-
- Filters.Add(new QueryStringFilter(AllowedFields));
- Filters.Add(new QueryStringSearchFilter(AllowedFields));
- Filters.Add(new QueryStringIdRangeFilter());
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/CustomSerializers/CustomerSerializer.cs b/AspNetCore.RestFramework.Sample/CustomSerializers/CustomerSerializer.cs
deleted file mode 100644
index 9fd7c3f..0000000
--- a/AspNetCore.RestFramework.Sample/CustomSerializers/CustomerSerializer.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System;
-using AspNetCore.RestFramework.Core.Serializer;
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-
-namespace AspNetRestFramework.Sample.CustomSerializers
-{
- public class CustomerSerializer : Serializer
- {
- public CustomerSerializer(ApplicationDbContext applicationDbContext) : base(applicationDbContext)
- {
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/DTO/CustomerDocumentDto.cs b/AspNetCore.RestFramework.Sample/DTO/CustomerDocumentDto.cs
deleted file mode 100644
index 5bc821c..0000000
--- a/AspNetCore.RestFramework.Sample/DTO/CustomerDocumentDto.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using AspNetCore.RestFramework.Core.Base;
-
-namespace AspNetRestFramework.Sample.DTO;
-
-public class CustomerDocumentDto : BaseDto
-{
- public string Document { get; set; }
- public string DocumentType { get; set; }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Sample/DTO/CustomerDto.cs b/AspNetCore.RestFramework.Sample/DTO/CustomerDto.cs
deleted file mode 100644
index 2a972b2..0000000
--- a/AspNetCore.RestFramework.Sample/DTO/CustomerDto.cs
+++ /dev/null
@@ -1,18 +0,0 @@
-using System;
-using AspNetCore.RestFramework.Core.Base;
-using System.Collections.Generic;
-
-namespace AspNetRestFramework.Sample.DTO
-{
- public class CustomerDto : BaseDto
- {
- public CustomerDto()
- {
- }
-
- public string Name { get; set; }
- public string CNPJ { get; set; }
-
- public ICollection CustomerDocuments { get; set; }
- }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Sample/DTO/IntAsIdEntityDto.cs b/AspNetCore.RestFramework.Sample/DTO/IntAsIdEntityDto.cs
deleted file mode 100644
index ca9377a..0000000
--- a/AspNetCore.RestFramework.Sample/DTO/IntAsIdEntityDto.cs
+++ /dev/null
@@ -1,9 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-
-namespace AspNetRestFramework.Sample.DTO
-{
- public class IntAsIdEntityDto : BaseDto
- {
- public string Name { get; set; }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/DTO/SellerDto.cs b/AspNetCore.RestFramework.Sample/DTO/SellerDto.cs
deleted file mode 100644
index 22d3ebf..0000000
--- a/AspNetCore.RestFramework.Sample/DTO/SellerDto.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System;
-using AspNetCore.RestFramework.Core.Base;
-
-namespace AspNetRestFramework.Sample.DTO
-{
- public class SellerDto : BaseDto
- {
- public string Name { get; set; }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/DTO/Validators/CustomerDocumentDtoValidator.cs b/AspNetCore.RestFramework.Sample/DTO/Validators/CustomerDocumentDtoValidator.cs
deleted file mode 100644
index 66b9fff..0000000
--- a/AspNetCore.RestFramework.Sample/DTO/Validators/CustomerDocumentDtoValidator.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using FluentValidation;
-
-namespace AspNetRestFramework.Sample.DTO.Validators
-{
- public class CustomerDocumentDtoValidator : AbstractValidator
- {
- public CustomerDocumentDtoValidator()
- {
- RuleFor(m => m.Document)
- .MinimumLength(3)
- .WithMessage("Name should have at least 3 characters");
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/DTO/Validators/CustomerDtoValidator.cs b/AspNetCore.RestFramework.Sample/DTO/Validators/CustomerDtoValidator.cs
deleted file mode 100644
index 97b364d..0000000
--- a/AspNetCore.RestFramework.Sample/DTO/Validators/CustomerDtoValidator.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using FluentValidation;
-using Microsoft.AspNetCore.Http;
-
-namespace AspNetRestFramework.Sample.DTO.Validators
-{
- public class CustomerDtoValidator : AbstractValidator
- {
- public CustomerDtoValidator(IHttpContextAccessor context)
- {
- RuleFor(m => m.Name)
- .MinimumLength(3)
- .WithMessage("Name should have at least 3 characters");
-
- if (context.HttpContext.Request.Method == HttpMethods.Post)
- RuleFor(m => m.CNPJ)
- .NotEqual("567")
- .WithMessage("CNPJ cannot be 567");
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/FakeData/FakeDataGenerator.cs b/AspNetCore.RestFramework.Sample/FakeData/FakeDataGenerator.cs
deleted file mode 100644
index b53992b..0000000
--- a/AspNetCore.RestFramework.Sample/FakeData/FakeDataGenerator.cs
+++ /dev/null
@@ -1,75 +0,0 @@
-using AspNetRestFramework.Sample.Models;
-using Bogus;
-using Bogus.Extensions.Brazil;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace AspNetRestFramework.Sample.FakeData
-{
- public static class FakeDataGenerator
- {
- private const int SELLERS_TO_GENERATE = 30;
- private const int CUSTOMERS_TO_GENERATE = 500;
- private const int DOCUMENTS_TO_GENERATE_MIN = 1;
- private const int DOCUMENTS_TO_GENERATE_MAX = 5;
-
- public static (IList, IList, IList) GenerateFakeData()
- {
- var sellers = Enumerable
- .Range(0, SELLERS_TO_GENERATE)
- .Select(_ => {
- var sellerFaker = new Faker()
- .RuleFor(m => m.Id, m => Guid.NewGuid())
- .RuleFor(m => m.Name, m => m.Company.CompanyName());
-
- return sellerFaker.Generate();
- })
- .ToList();
-
- var customerDocuments = new List();
-
- var customers = Enumerable
- .Range(0, CUSTOMERS_TO_GENERATE)
- .Select(_ => {
- var customerFaker = new Faker()
- .RuleFor(m => m.Id, m => Guid.NewGuid())
- .RuleFor(m => m.Name, m => m.Company.CompanyName())
- .RuleFor(m => m.Age, m => m.Random.Number(18, 99))
- .RuleFor(m => m.CNPJ, m => m.Company.Cnpj());
-
- var customer = customerFaker.Generate();
-
- var documentsToGenerate = new Faker().Random.Number(DOCUMENTS_TO_GENERATE_MIN, DOCUMENTS_TO_GENERATE_MAX);
- customerDocuments.AddRange(
- Enumerable.Range(0, documentsToGenerate)
- .Select(_ =>
- {
- var docFaker = new Faker()
- .RuleFor(m => m.Id, m => Guid.NewGuid())
- .RuleFor(m => m.CustomerId, customer.Id)
- .RuleFor(m => m.DocumentType, m => m.Random.ArrayElement(new[] { "cpf", "cnpj", "xpto", "others" }))
- .RuleFor(m => m.Document, (f, d) => {
- return d.DocumentType switch
- {
- "cpf" => f.Person.Cpf(),
- "cnpj" => f.Company.Cnpj(),
- "xpto" => $"xpto_{f.Random.Number(10000, 99999)}_{f.Random.Word()}",
- "others" => f.Address.Country(),
- _ => "invalid",
- };
- });
-
- return docFaker.Generate();
- })
- .ToList()
- );
-
- return customer;
- })
- .ToList();
-
- return (sellers, customers, customerDocuments);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Filters/CustomerDocumentIncludeFilter.cs b/AspNetCore.RestFramework.Sample/Filters/CustomerDocumentIncludeFilter.cs
deleted file mode 100644
index 33e7cde..0000000
--- a/AspNetCore.RestFramework.Sample/Filters/CustomerDocumentIncludeFilter.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Linq;
-using AspNetCore.RestFramework.Core.Filters;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.AspNetCore.Http;
-using Microsoft.EntityFrameworkCore;
-
-namespace AspNetRestFramework.Sample.Filters;
-
-public class CustomerDocumentIncludeFilter : Filter
-{
- public override IQueryable AddFilter(IQueryable query, HttpRequest request)
- {
- return query.Include(x => x.CustomerDocument);
- }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Sample/Filters/CustomerFilter.cs b/AspNetCore.RestFramework.Sample/Filters/CustomerFilter.cs
deleted file mode 100644
index 182634c..0000000
--- a/AspNetCore.RestFramework.Sample/Filters/CustomerFilter.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-using System.Linq;
-using AspNetCore.RestFramework.Core.Filters;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.AspNetCore.Http;
-using Microsoft.EntityFrameworkCore;
-
-namespace AspNetRestFramework.Sample.Filters;
-
-public class CustomerFilter : Filter
-{
- public override IQueryable AddFilter(IQueryable query, HttpRequest request)
- {
- return query.Include(x => x.Customer);
- }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Sample/Filters/DocumentFilter.cs b/AspNetCore.RestFramework.Sample/Filters/DocumentFilter.cs
deleted file mode 100644
index 5405aef..0000000
--- a/AspNetCore.RestFramework.Sample/Filters/DocumentFilter.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using AspNetCore.RestFramework.Core.Filters;
-using Microsoft.AspNetCore.Http;
-using System.Linq;
-using AspNetRestFramework.Sample.Models;
-using Microsoft.EntityFrameworkCore;
-
-namespace AspNetRestFramework.Sample.Filters
-{
- public class DocumentFilter : Filter
- {
- public override IQueryable AddFilter(IQueryable query, HttpRequest request)
- {
- var queryString = request.Query.Select(x => new { x.Key, x.Value}).ToList();
-
- var documentType = "";
-
- if (queryString.Any(x => x.Key == "cpf"))
- documentType = "cpf";
-
- if (queryString.Any(x => x.Key == "cnpj"))
- documentType = "cnpj";
-
- var document = queryString.FirstOrDefault(x => x.Key == documentType)?.Value;
- if (string.IsNullOrWhiteSpace(document))
- return query;
-
-
- return query.Where(x => x.CustomerDocument.Any(x => x.DocumentType == documentType && x.Document == document.Value.ToString()));
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Mappings/CustomerConfig.cs b/AspNetCore.RestFramework.Sample/Mappings/CustomerConfig.cs
deleted file mode 100644
index 753060a..0000000
--- a/AspNetCore.RestFramework.Sample/Mappings/CustomerConfig.cs
+++ /dev/null
@@ -1,16 +0,0 @@
-using AspNetRestFramework.Sample.Models;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
-namespace AspNetRestFramework.Sample.Mappings
-{
- public class CustomerConfig : IEntityTypeConfiguration
- {
- public void Configure(EntityTypeBuilder builder)
- {
- builder.HasKey(b => b.Id);
-
- //builder.Navigation(e => e.CustomerDocuments).AutoInclude();
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Mappings/CustomerDocumentConfig.cs b/AspNetCore.RestFramework.Sample/Mappings/CustomerDocumentConfig.cs
deleted file mode 100644
index b54cff3..0000000
--- a/AspNetCore.RestFramework.Sample/Mappings/CustomerDocumentConfig.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using AspNetRestFramework.Sample.Models;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
-namespace AspNetRestFramework.Sample.Mappings
-{
- public class CustomerDocumentConfig : IEntityTypeConfiguration
- {
- public void Configure(EntityTypeBuilder builder)
- {
- builder.HasOne(b => b.Customer)
- .WithMany(b => b.CustomerDocument)
- .HasForeignKey(b => b.CustomerId)
- .IsRequired();
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Mappings/IntAsIdEntityConfig.cs b/AspNetCore.RestFramework.Sample/Mappings/IntAsIdEntityConfig.cs
deleted file mode 100644
index d5ca99c..0000000
--- a/AspNetCore.RestFramework.Sample/Mappings/IntAsIdEntityConfig.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using AspNetRestFramework.Sample.Models;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
-namespace AspNetRestFramework.Sample.Mappings
-{
- public class IntAsIdEntityConfig : IEntityTypeConfiguration
- {
- public void Configure(EntityTypeBuilder builder)
- {
- builder.HasKey(b => b.Id);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Mappings/SellerConfig.cs b/AspNetCore.RestFramework.Sample/Mappings/SellerConfig.cs
deleted file mode 100644
index e6a0426..0000000
--- a/AspNetCore.RestFramework.Sample/Mappings/SellerConfig.cs
+++ /dev/null
@@ -1,14 +0,0 @@
-using AspNetRestFramework.Sample.Models;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Metadata.Builders;
-
-namespace AspNetRestFramework.Sample.Mappings
-{
- public class SellerConfig : IEntityTypeConfiguration
- {
- public void Configure(EntityTypeBuilder builder)
- {
- builder.HasKey(b => b.Id);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Migrations/20220504131959_InitialCreate.Designer.cs b/AspNetCore.RestFramework.Sample/Migrations/20220504131959_InitialCreate.Designer.cs
deleted file mode 100644
index 0d0256d..0000000
--- a/AspNetCore.RestFramework.Sample/Migrations/20220504131959_InitialCreate.Designer.cs
+++ /dev/null
@@ -1,101 +0,0 @@
-//
-using System;
-using AspNetRestFramework.Sample.Context;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace AspNetRestFramework.Sample.Migrations
-{
- [DbContext(typeof(ApplicationDbContext))]
- [Migration("20220504131959_InitialCreate")]
- partial class InitialCreate
- {
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "6.0.0")
- .HasAnnotation("Relational:MaxIdentifierLength", 128);
-
- SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Customer", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Age")
- .HasColumnType("int");
-
- b.Property("CNPJ")
- .HasColumnType("nvarchar(max)");
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("Customer");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.CustomerDocument", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("CustomerId")
- .HasColumnType("uniqueidentifier");
-
- b.Property("Document")
- .HasColumnType("nvarchar(max)");
-
- b.Property("DocumentType")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.HasIndex("CustomerId");
-
- b.ToTable("CustomerDocument");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Seller", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("Seller");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.CustomerDocument", b =>
- {
- b.HasOne("AspNetRestFramework.Sample.Models.Customer", "Customer")
- .WithMany("CustomerDocuments")
- .HasForeignKey("CustomerId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Customer");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Customer", b =>
- {
- b.Navigation("CustomerDocuments");
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Migrations/20220504131959_InitialCreate.cs b/AspNetCore.RestFramework.Sample/Migrations/20220504131959_InitialCreate.cs
deleted file mode 100644
index 28da324..0000000
--- a/AspNetCore.RestFramework.Sample/Migrations/20220504131959_InitialCreate.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore.Migrations;
-
-#nullable disable
-
-namespace AspNetRestFramework.Sample.Migrations
-{
- public partial class InitialCreate : Migration
- {
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.CreateTable(
- name: "Customer",
- columns: table => new
- {
- Id = table.Column(type: "uniqueidentifier", nullable: false),
- Name = table.Column(type: "nvarchar(max)", nullable: true),
- CNPJ = table.Column(type: "nvarchar(max)", nullable: true),
- Age = table.Column(type: "int", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_Customer", x => x.Id);
- });
-
- migrationBuilder.CreateTable(
- name: "Seller",
- columns: table => new
- {
- Id = table.Column(type: "uniqueidentifier", nullable: false),
- Name = table.Column(type: "nvarchar(max)", nullable: true)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_Seller", x => x.Id);
- });
-
- migrationBuilder.CreateTable(
- name: "CustomerDocument",
- columns: table => new
- {
- Id = table.Column(type: "uniqueidentifier", nullable: false),
- Document = table.Column(type: "nvarchar(max)", nullable: true),
- DocumentType = table.Column(type: "nvarchar(max)", nullable: true),
- CustomerId = table.Column(type: "uniqueidentifier", nullable: false)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_CustomerDocument", x => x.Id);
- table.ForeignKey(
- name: "FK_CustomerDocument_Customer_CustomerId",
- column: x => x.CustomerId,
- principalTable: "Customer",
- principalColumn: "Id",
- onDelete: ReferentialAction.Cascade);
- });
-
- migrationBuilder.CreateIndex(
- name: "IX_CustomerDocument_CustomerId",
- table: "CustomerDocument",
- column: "CustomerId");
- }
-
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(
- name: "CustomerDocument");
-
- migrationBuilder.DropTable(
- name: "Seller");
-
- migrationBuilder.DropTable(
- name: "Customer");
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Migrations/20220809142812_IntAsIdEntity.Designer.cs b/AspNetCore.RestFramework.Sample/Migrations/20220809142812_IntAsIdEntity.Designer.cs
deleted file mode 100644
index 1e6dd64..0000000
--- a/AspNetCore.RestFramework.Sample/Migrations/20220809142812_IntAsIdEntity.Designer.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-//
-using System;
-using AspNetRestFramework.Sample.Context;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace AspNetRestFramework.Sample.Migrations
-{
- [DbContext(typeof(ApplicationDbContext))]
- [Migration("20220809142812_IntAsIdEntity")]
- partial class IntAsIdEntity
- {
- protected override void BuildTargetModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "6.0.0")
- .HasAnnotation("Relational:MaxIdentifierLength", 128);
-
- SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Customer", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Age")
- .HasColumnType("int");
-
- b.Property("CNPJ")
- .HasColumnType("nvarchar(max)");
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("Customer");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.CustomerDocument", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("CustomerId")
- .HasColumnType("uniqueidentifier");
-
- b.Property("Document")
- .HasColumnType("nvarchar(max)");
-
- b.Property("DocumentType")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.HasIndex("CustomerId");
-
- b.ToTable("CustomerDocument");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.IntAsIdEntity", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("int");
-
- SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("IntAsIdEntities");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Seller", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("Seller");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.CustomerDocument", b =>
- {
- b.HasOne("AspNetRestFramework.Sample.Models.Customer", "Customer")
- .WithMany("CustomerDocument")
- .HasForeignKey("CustomerId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Customer");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Customer", b =>
- {
- b.Navigation("CustomerDocument");
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Migrations/20220809142812_IntAsIdEntity.cs b/AspNetCore.RestFramework.Sample/Migrations/20220809142812_IntAsIdEntity.cs
deleted file mode 100644
index 0041469..0000000
--- a/AspNetCore.RestFramework.Sample/Migrations/20220809142812_IntAsIdEntity.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using Microsoft.EntityFrameworkCore.Migrations;
-
-#nullable disable
-
-namespace AspNetRestFramework.Sample.Migrations
-{
- public partial class IntAsIdEntity : Migration
- {
- protected override void Up(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.CreateTable(
- name: "IntAsIdEntities",
- columns: table => new
- {
- Id = table.Column(type: "int", nullable: false)
- .Annotation("SqlServer:Identity", "1, 1"),
- Name = table.Column(type: "nvarchar(max)", nullable: true)
- },
- constraints: table =>
- {
- table.PrimaryKey("PK_IntAsIdEntities", x => x.Id);
- });
- }
-
- protected override void Down(MigrationBuilder migrationBuilder)
- {
- migrationBuilder.DropTable(
- name: "IntAsIdEntities");
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Migrations/ApplicationDbContextModelSnapshot.cs b/AspNetCore.RestFramework.Sample/Migrations/ApplicationDbContextModelSnapshot.cs
deleted file mode 100644
index a29aaa2..0000000
--- a/AspNetCore.RestFramework.Sample/Migrations/ApplicationDbContextModelSnapshot.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-//
-using System;
-using AspNetRestFramework.Sample.Context;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Metadata;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-
-#nullable disable
-
-namespace AspNetRestFramework.Sample.Migrations
-{
- [DbContext(typeof(ApplicationDbContext))]
- partial class ApplicationDbContextModelSnapshot : ModelSnapshot
- {
- protected override void BuildModel(ModelBuilder modelBuilder)
- {
-#pragma warning disable 612, 618
- modelBuilder
- .HasAnnotation("ProductVersion", "6.0.0")
- .HasAnnotation("Relational:MaxIdentifierLength", 128);
-
- SqlServerModelBuilderExtensions.UseIdentityColumns(modelBuilder, 1L, 1);
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Customer", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Age")
- .HasColumnType("int");
-
- b.Property("CNPJ")
- .HasColumnType("nvarchar(max)");
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("Customer");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.CustomerDocument", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("CustomerId")
- .HasColumnType("uniqueidentifier");
-
- b.Property("Document")
- .HasColumnType("nvarchar(max)");
-
- b.Property("DocumentType")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.HasIndex("CustomerId");
-
- b.ToTable("CustomerDocument");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.IntAsIdEntity", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("int");
-
- SqlServerPropertyBuilderExtensions.UseIdentityColumn(b.Property("Id"), 1L, 1);
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("IntAsIdEntities");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Seller", b =>
- {
- b.Property("Id")
- .ValueGeneratedOnAdd()
- .HasColumnType("uniqueidentifier");
-
- b.Property("Name")
- .HasColumnType("nvarchar(max)");
-
- b.HasKey("Id");
-
- b.ToTable("Seller");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.CustomerDocument", b =>
- {
- b.HasOne("AspNetRestFramework.Sample.Models.Customer", "Customer")
- .WithMany("CustomerDocument")
- .HasForeignKey("CustomerId")
- .OnDelete(DeleteBehavior.Cascade)
- .IsRequired();
-
- b.Navigation("Customer");
- });
-
- modelBuilder.Entity("AspNetRestFramework.Sample.Models.Customer", b =>
- {
- b.Navigation("CustomerDocument");
- });
-#pragma warning restore 612, 618
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Models/Customer.cs b/AspNetCore.RestFramework.Sample/Models/Customer.cs
deleted file mode 100644
index 6ff45fa..0000000
--- a/AspNetCore.RestFramework.Sample/Models/Customer.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using System;
-using System.Collections.Generic;
-
-namespace AspNetRestFramework.Sample.Models
-{
- public class Customer : BaseModel
- {
- public string Name { get; set; }
- public string CNPJ { get; set; }
- public int Age { get; set; }
-
- public ICollection CustomerDocument { get; set; }
-
- public override string[] GetFields()
- {
- return new[] { "Name", "CNPJ", "Age", "Id", "CustomerDocument", "CustomerDocument:DocumentType", "CustomerDocument:Document" };
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Models/CustomerDocument.cs b/AspNetCore.RestFramework.Sample/Models/CustomerDocument.cs
deleted file mode 100644
index 80bb88e..0000000
--- a/AspNetCore.RestFramework.Sample/Models/CustomerDocument.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using System;
-
-namespace AspNetRestFramework.Sample.Models
-{
- public class CustomerDocument : BaseModel
- {
- public string Document { get; set; }
- public string DocumentType { get; set; }
- public Guid CustomerId { get; set; }
- public Customer Customer { get; set; }
- public override string[] GetFields()
- {
- return new[] { "Id", "Document", "DocumentType", "CustomerId", "Customer", "Customer:CNPJ", "Customer:Age" };
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Models/IntAsIdEntity.cs b/AspNetCore.RestFramework.Sample/Models/IntAsIdEntity.cs
deleted file mode 100644
index a8b32de..0000000
--- a/AspNetCore.RestFramework.Sample/Models/IntAsIdEntity.cs
+++ /dev/null
@@ -1,12 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-
-namespace AspNetRestFramework.Sample.Models
-{
- public class IntAsIdEntity : BaseModel
- {
- public string Name { get; set; }
-
- public override string[] GetFields()
- => new[] { nameof(Id), nameof(Name) };
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Models/Seller.cs b/AspNetCore.RestFramework.Sample/Models/Seller.cs
deleted file mode 100644
index d83c848..0000000
--- a/AspNetCore.RestFramework.Sample/Models/Seller.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using System;
-
-namespace AspNetRestFramework.Sample.Models
-{
- public class Seller : BaseModel
- {
- public string Name { get; set; }
- public override string[] GetFields() => throw new NotImplementedException();
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Program.cs b/AspNetCore.RestFramework.Sample/Program.cs
deleted file mode 100644
index 1252170..0000000
--- a/AspNetCore.RestFramework.Sample/Program.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.FakeData;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using System;
-
-namespace AspNetRestFramework.Sample
-{
- public class Program
- {
- public static void Main(string[] args)
- {
- var app = CreateHostBuilder(args).Build();
-
- InitializeDatabase(app);
-
- app.Run();
- }
-
- public static IHostBuilder CreateHostBuilder(string[] args) =>
- Host.CreateDefaultBuilder(args)
- .ConfigureWebHostDefaults(webBuilder =>
- {
- webBuilder.UseStartup();
- });
-
- private static void InitializeDatabase(IHost app)
- {
- using (var scope = app.Services.CreateScope())
- using (var dbContext = scope.ServiceProvider.GetRequiredService())
- {
- dbContext.Database.EnsureDeleted();
- dbContext.Database.Migrate();
-
- var (sellers, customers, customerDocuments) = FakeDataGenerator.GenerateFakeData();
-
- dbContext.Seller.AddRange(sellers);
- dbContext.Customer.AddRange(customers);
- dbContext.CustomerDocument.AddRange(customerDocuments);
-
- dbContext.SaveChanges();
- }
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Properties/launchSettings.json b/AspNetCore.RestFramework.Sample/Properties/launchSettings.json
deleted file mode 100644
index 90f1d4b..0000000
--- a/AspNetCore.RestFramework.Sample/Properties/launchSettings.json
+++ /dev/null
@@ -1,31 +0,0 @@
-{
- "$schema": "http://json.schemastore.org/launchsettings.json",
- "iisSettings": {
- "windowsAuthentication": false,
- "anonymousAuthentication": true,
- "iisExpress": {
- "applicationUrl": "http://localhost:35185",
- "sslPort": 44352
- }
- },
- "profiles": {
- "IIS Express": {
- "commandName": "IISExpress",
- "launchBrowser": true,
- "launchUrl": "swagger",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- },
- "AspNetCore.RestFramework.Sample": {
- "commandName": "Project",
- "dotnetRunMessages": true,
- "launchBrowser": true,
- "launchUrl": "swagger",
- "applicationUrl": "https://localhost:5001;http://localhost:5000",
- "environmentVariables": {
- "ASPNETCORE_ENVIRONMENT": "Development"
- }
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/Startup.cs b/AspNetCore.RestFramework.Sample/Startup.cs
deleted file mode 100644
index 27b204f..0000000
--- a/AspNetCore.RestFramework.Sample/Startup.cs
+++ /dev/null
@@ -1,97 +0,0 @@
-using System;
-using AspNetCore.RestFramework.Core.Extensions;
-using AspNetCore.RestFramework.Core.Serializer;
-using AspNetRestFramework.Sample.Context;
-using AspNetRestFramework.Sample.CustomSerializers;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.DTO.Validators;
-using AspNetRestFramework.Sample.Models;
-using FluentValidation;
-using FluentValidation.AspNetCore;
-using JSM.FluentValidation.AspNet.AsyncFilter;
-using Microsoft.AspNetCore.Builder;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.Hosting;
-using Microsoft.OpenApi.Models;
-using Newtonsoft.Json;
-
-namespace AspNetRestFramework.Sample
-{
- public class Startup
- {
- public Startup(IConfiguration configuration)
- {
- Configuration = configuration;
- }
-
- public IConfiguration Configuration { get; }
-
- // This method gets called by the runtime. Use this method to add services to the container.
- public void ConfigureServices(IServiceCollection services)
- {
- services.AddSingleton();
-
- services.AddControllers()
- .AddNewtonsoftJson(config =>
- {
- config.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
- config.SerializerSettings.NullValueHandling = NullValueHandling.Ignore;
- })
- .AddModelValidationAsyncActionFilter(options =>
- {
- options.OnlyApiController = true;
- })
- .ConfigureValidationResponseFormat();
-
- services.AddHttpContextAccessor();
-
- services.AddFluentValidationAutoValidation();
- services.AddValidatorsFromAssemblyContaining();
-
- var connectionString = Configuration.GetConnectionString("DefaultConnectionString");
- services.AddDbContext(opt => opt.UseSqlServer(connectionString));
-
- services.AddScoped();
- services.AddScoped>();
- services.AddScoped>();
- services.AddScoped>();
-
- services.AddControllers();
- services.AddSwaggerGen(c =>
- {
- c.SwaggerDoc("v1", new OpenApiInfo { Title = "AspNetCore.RestFramework.Sample", Version = "v1" });
- });
- }
-
- // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
- public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
- {
- if (env.IsDevelopment())
- app.UseDeveloperExceptionPage();
-
- app.UseSwagger();
- app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "AspNetCore.RestFramework.Sample v1"));
-
- app.UseCors(c =>
- {
- c.AllowAnyHeader();
- c.AllowAnyMethod();
- c.AllowAnyOrigin();
- });
-
- app.UseHttpsRedirection();
-
- app.UseRouting();
-
- app.UseAuthorization();
-
- app.UseEndpoints(endpoints =>
- {
- endpoints.MapControllers();
- });
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Sample/appsettings.json b/AspNetCore.RestFramework.Sample/appsettings.json
deleted file mode 100644
index a225839..0000000
--- a/AspNetCore.RestFramework.Sample/appsettings.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft": "Warning",
- "Microsoft.Hosting.Lifetime": "Information",
- "Microsoft.EntityFrameworkCore.Database.Command": "Information"
- }
- },
- "AllowedHosts": "*",
- "ConnectionStrings": {
- "DefaultConnectionString": "Data Source=localhost,1433;Initial Catalog=RestFramework;User Id=sa;Password=Password1"
- }
-}
\ No newline at end of file
diff --git a/AspNetCore.RestFramework.Test/AspNetCore.RestFramework.Test.csproj b/AspNetCore.RestFramework.Test/AspNetCore.RestFramework.Test.csproj
deleted file mode 100644
index d09cefc..0000000
--- a/AspNetCore.RestFramework.Test/AspNetCore.RestFramework.Test.csproj
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- net6.0
-
- false
-
-
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
-
-
-
-
-
-
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Delete.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Delete.cs
deleted file mode 100644
index 98ed2b0..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Delete.cs
+++ /dev/null
@@ -1,58 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Errors;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Linq;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task Delete_WithObject_ShouldDeleteEntityFromDatabaseAndReturnOk()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
- dbSet.Add(customer);
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.DeleteAsync($"api/Customers/{customer.Id}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var updatedCustomer = dbSet.AsNoTracking().FirstOrDefault(x => x.Id == customer.Id);
- updatedCustomer.Should().BeNull();
- }
-
- [Fact]
- public async Task Delete_WhenEntityDoesntExist_ReturnsNotFound()
- {
- // Act
- var response = await Client.DeleteAsync($"api/Customers/{Guid.NewGuid()}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound);
- }
-
- [Fact]
- public async Task Delete_WhenEntityDoesntImplementGetFields_ReturnsBadRequest()
- {
- // Act
- var response = await Client.DeleteAsync($"api/Sellers/{Guid.NewGuid()}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var responseMessages = JsonConvert.DeserializeObject(responseData);
-
- responseMessages.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.DeleteMany.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.DeleteMany.cs
deleted file mode 100644
index a5d3ce4..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.DeleteMany.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task DeleteMany_ShouldDeleteManyEntities_AndReturnTheirIds()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { Id = Guid.Parse("35d948bd-ab3d-4446-912b-2d20c57c4935"), CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { Id = Guid.Parse("6bdc2b9e-3710-40b9-93dd-c7558b446e21"), CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { Id = Guid.Parse("22ee1df9-c543-4509-a755-e7cd5dc0045e"), CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- var expectedGuids = new[] {
- Guid.Parse("6bdc2b9e-3710-40b9-93dd-c7558b446e21"),
- Guid.Parse("22ee1df9-c543-4509-a755-e7cd5dc0045e"),
- };
-
- // Act
- var response = await Client.DeleteAsync($"api/Customers?ids=6bdc2b9e-3710-40b9-93dd-c7558b446e21&ids=22ee1df9-c543-4509-a755-e7cd5dc0045e");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var deletedIds = JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync());
- deletedIds.Should().BeEquivalentTo(expectedGuids);
-
- var entitiesWithDeletedIds = dbSet.Where(m => expectedGuids.Contains(m.Id)).AsNoTracking();
- entitiesWithDeletedIds.Should().BeEmpty();
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.GetSingle.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.GetSingle.cs
deleted file mode 100644
index 11c6419..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.GetSingle.cs
+++ /dev/null
@@ -1,77 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Errors;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Newtonsoft.Json;
-using System;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task GetSingle_WithValidParameter_ShouldReturn1Record()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer1 = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
- var customer2 = new Customer() { Id = Guid.NewGuid(), CNPJ = "456", Name = "def" };
- var customer3 = new Customer() { Id = Guid.NewGuid(), CNPJ = "789", Name = "ghi" };
-
-
- dbSet.AddRange(customer1, customer2, customer3);
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync($"api/Customers/{customer1.Id}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customer = JsonConvert.DeserializeObject(responseData);
- customer.Should().NotBeNull();
- customer.Id.Should().Be(customer1.Id);
- }
-
- [Fact]
- public async Task GetSingle_WithInValidParameter_ShouldReturn404()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer1 = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
- var customer2 = new Customer() { Id = Guid.NewGuid(), CNPJ = "456", Name = "def" };
- var customer3 = new Customer() { Id = Guid.NewGuid(), CNPJ = "789", Name = "ghi" };
-
- dbSet.AddRange(customer1, customer2, customer3);
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync($"api/Customers/{Guid.NewGuid()}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound);
- }
-
- [Fact]
- public async Task GetSingle_WithoutFields_ShouldReturnBadRequest()
- {
- // Arrange
- var dbSet = Context.Set();
- var seller1 = new Seller() { Id = Guid.NewGuid(), Name = "Test" };
-
- dbSet.Add(seller1);
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync($"api/Sellers/{seller1.Id}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var msg = JsonConvert.DeserializeObject(responseData);
- msg.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.ListPaged.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.ListPaged.cs
deleted file mode 100644
index f647bd0..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.ListPaged.cs
+++ /dev/null
@@ -1,493 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Errors;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-using System.Web;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task ListPaged_ShouldReturn200OK()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
-
- customers.Data.Count.Should().Be(3);
- }
-
- [Fact]
- public async Task ListPaged_WithQueryString_ShouldReturnSingleRecord()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?Name=ghi&CNPJ=789");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(1);
- customers.Data.First().Name.Should().Be("ghi");
- }
-
- [Fact]
- public async Task ListPaged_WithIdQueryStringFilter_ShouldReturnSingleRecord()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { Id = Guid.Parse("35d948bd-ab3d-4446-912b-2d20c57c4935"), CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?id=35d948bd-ab3d-4446-912b-2d20c57c4935");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(1);
- customers.Data.First().Name.Should().Be("abc");
- }
-
- [Fact]
- public async Task ListPaged_WithIdRangeQueryStringFilter_ShouldReturnTwoRecords()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { Id = Guid.Parse("35d948bd-ab3d-4446-912b-2d20c57c4935"), CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { Id = Guid.Parse("6bdc2b9e-3710-40b9-93dd-c7558b446e21"), CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { Id = Guid.Parse("22ee1df9-c543-4509-a755-e7cd5dc0045e"), CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?ids=6bdc2b9e-3710-40b9-93dd-c7558b446e21&ids=22ee1df9-c543-4509-a755-e7cd5dc0045e");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(2);
- customers.Data.ElementAt(0).Name.Should().Be("def");
- customers.Data.ElementAt(1).Name.Should().Be("ghi");
- }
-
- [Fact]
- public async Task ListPaged_WithIdRangeQueryStringFilterAndIdIsNotGuid_ShouldReturnTwoRecords()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new IntAsIdEntity() { Name = "abc" });
- dbSet.Add(new IntAsIdEntity() { Name = "def" });
- dbSet.Add(new IntAsIdEntity() { Name = "ghi" });
- dbSet.Add(new IntAsIdEntity() { Name = "jkl" });
- await Context.SaveChangesAsync();
-
- var entities = dbSet.Where(m => new[] { "def", "ghi" }.Contains(m.Name)).AsNoTracking().ToList();
-
- // Act
- var response = await Client.GetAsync($"api/IntAsIdEntities?ids={entities[0].Id}&ids={entities[1].Id}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(2);
- customers.Data.ElementAt(0).Name.Should().Be("def");
- customers.Data.ElementAt(1).Name.Should().Be("ghi");
- }
-
- [Fact]
- public async Task ListPaged_WithIntegerQueryString_ShouldReturnTwoRecords()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi", Age = 25 });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?Age=20");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(2);
- }
-
- [Fact]
- public async Task ListPaged_WithIntegerQueryStringAndSortDescParameter_ShouldReturnTwoRecordsSortedDesc()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "124", Name = "abc", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi", Age = 25 });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?Age=20&SortDesc=Name,CNPJ");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(3);
-
- var first = customers.Data.First();
- var second = customers.Data.Skip(1).First();
- var third = customers.Data.Skip(2).First();
-
- first.Name.Should().Be("def");
- first.CNPJ.Should().Be("456");
- second.Name.Should().Be("abc");
- second.CNPJ.Should().Be("124");
- third.Name.Should().Be("abc");
- third.CNPJ.Should().Be("123");
- }
-
- [Fact]
- public async Task ListPaged_WithIntegerQueryStringAndSortAscParameter_ShouldReturnTwoRecordsSortedAsc()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "124", Name = "abc", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc", Age = 20 });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi", Age = 25 });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?Age=20&Sort=Name,CNPJ");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(3);
-
- var first = customers.Data.First();
- var second = customers.Data.Skip(1).First();
- var third = customers.Data.Skip(2).First();
-
- first.Name.Should().Be("abc");
- first.CNPJ.Should().Be("123");
- second.Name.Should().Be("abc");
- second.CNPJ.Should().Be("124");
- third.Name.Should().Be("def");
- third.CNPJ.Should().Be("456");
- }
-
- [Fact]
- public async Task ListPaged_WithQueryStringDocumentParameter_ShouldReturnSingleRecord()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer()
- {
- CNPJ = "123",
- Name = "abc",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "XYZ"
- }, new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cpf",
- Document = "1234"
- }}
-
- });
- dbSet.Add(new Customer()
- {
- CNPJ = "456",
- Name = "def",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "LHA"
- }}
- });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
-
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?cpf=1234");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(1);
- customers.Data.First().Name.Should().Be("abc");
- }
-
- [Fact]
- public async Task ListPaged_WithQueryStringDocumentParameterAndName_ShouldReturnSingleRecord()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer()
- {
- CNPJ = "123",
- Name = "abc",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "XYZ"
- }, new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cpf",
- Document = "1234"
- }}
-
- });
- dbSet.Add(new Customer()
- {
- CNPJ = "456",
- Name = "def",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "LHA"
- }}
- });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
-
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?cpf=1234&Name=abc");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(1);
- customers.Data.First().Name.Should().Be("abc");
- }
-
- [Fact]
- public async Task ListPaged_WithQueryStringDocumentParameterAndName_ShouldReturnNoRecord()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer()
- {
- CNPJ = "123",
- Name = "abc",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "XYZ"
- }, new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cpf",
- Document = "1234"
- }}
-
- });
- dbSet.Add(new Customer()
- {
- CNPJ = "456",
- Name = "def",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "LHA"
- }}
- });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
-
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?cpf=1234&Name=ghi");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Should().BeEmpty();
- }
- [Fact]
- public async Task ListPaged_WithQueryStringCustomerParameter_ShouldReturnNoRecord()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer()
- {
- CNPJ = "123",
- Name = "abc",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "XYZ"
- }, new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cpf",
- Document = "1234"
- }}
-
- });
- dbSet.Add(new Customer()
- {
- CNPJ = "456",
- Name = "def",
- CustomerDocument = new List() { new CustomerDocument
- {
- Id = Guid.NewGuid(),
- DocumentType = "cnpj",
- Document = "LHA"
- }}
- });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
-
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?cpf=5557");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Should().BeEmpty();
- }
-
- [Fact]
- public async Task ListPaged_WithPageSize1AndPageSize3_ShouldReturn1RecordAnd3Pages()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?pageSize=3&page=1");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(3);
- customers.Total.Should().Be(3);
- }
-
- [Fact]
- public async Task ListPaged_WithPageSize1AndPageSize3_ShouldReturn1RecordAnd1Pages()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync("api/Customers?pageSize=1&page=3");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(1);
- customers.Total.Should().Be(3);
- customers.Data.First().Name.Should().Be("ghi");
- }
-
- [Theory]
- [InlineData("", 5)]
- [InlineData(" ", 5)]
- [InlineData("1a91f9ec-920b-4c92-83b0-6bf40d0209c2", 1)]
- [InlineData("10", 2)]
- [InlineData("12", 1)]
- [InlineData("%0001%", 5)]
- [InlineData("5%", 2)]
- [InlineData("%7", 2)]
- [InlineData("Agua Alta", 1)]
- [InlineData("Agua%", 2)]
- [InlineData("% Inc", 2)]
- [InlineData("aaa", 0)]
- public async Task ListPaged_WithSearchTerm_ReturnsExpectedCount(string term, int expectedCount)
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { Id = Guid.Parse("1a91f9ec-920b-4c92-83b0-6bf40d0209c2"), Age = 10, CNPJ = "76.637.568/0001-80", Name = "Agua Alta" });
- dbSet.Add(new Customer() { Id = Guid.Parse("a71bf8fa-0714-4281-8c51-23e763442919"), Age = 12, CNPJ = "24.451.215/0001-97", Name = "Agua Baixa" });
- dbSet.Add(new Customer() { Id = Guid.Parse("555b437e-3cd8-493c-b502-94cb9ba69a6b"), Age = 10, CNPJ = "81.517.224/0001-77", Name = "Bailão 12 Inc" });
- dbSet.Add(new Customer() { Id = Guid.Parse("f10ca31e-f60b-4d4e-8ca3-a754c4fda6bc"), Age = 25, CNPJ = "59.732.451/0001-66", Name = "Xablau Inc" });
- dbSet.Add(new Customer() { Id = Guid.Parse("c2710e39-f17a-469e-8994-28fd621819b4"), Age = 28, CNPJ = "55.387.453/0001-04", Name = "Problem Solver" });
- await Context.SaveChangesAsync();
-
- // Act
- var response = await Client.GetAsync($"api/Customers?search={HttpUtility.UrlEncode(term)}");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var responseData = await response.Content.ReadAsStringAsync();
- var customers = JsonConvert.DeserializeObject>>(responseData);
- customers.Data.Count.Should().Be(expectedCount);
- customers.Total.Should().Be(expectedCount);
- }
-
- [Fact]
- public async Task ListPaged_WhenEntityDoesntImplementGetFields_ReturnsBadRequest()
- {
- // Act
- var response = await Client.GetAsync("api/Sellers");
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var responseMessages = JsonConvert.DeserializeObject(responseData);
-
- responseMessages.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Patch.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Patch.cs
deleted file mode 100644
index c7f2ca2..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Patch.cs
+++ /dev/null
@@ -1,143 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Errors;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task Patch_WithFullObject_ShouldUpdateFullObject()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
- dbSet.Add(customer);
- await Context.SaveChangesAsync();
-
- var customerToUpdate = new
- {
- Id = customer.Id,
- CNPJ = "aaaa",
- Name = "eee"
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(customerToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PatchAsync($"api/Customers/{customer.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var updatedCustomer = dbSet.AsNoTracking().First(x => x.Id == customer.Id);
- updatedCustomer.Name.Should().Be(customerToUpdate.Name);
- updatedCustomer.CNPJ.Should().Be(customerToUpdate.CNPJ);
- }
-
- [Fact]
- public async Task Patch_WithPartialObject_ShouldUpdatePartialObject()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
- dbSet.Add(customer);
- await Context.SaveChangesAsync();
-
- var customerToUpdate = new
- {
- Id = customer.Id,
- CNPJ = "aaaa",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(customerToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PatchAsync($"api/Customers/{customer.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var updatedCustomer = dbSet.AsNoTracking().First(x => x.Id == customer.Id);
- updatedCustomer.Name.Should().Be(customer.Name);
- updatedCustomer.CNPJ.Should().Be(customerToUpdate.CNPJ);
- }
-
- [Fact]
- public async Task Patch_WhenEntityDoesntExist_ReturnsNotFound()
- {
- // Arrange
- var customerToUpdate = new
- {
- CNPJ = "aaaa",
- Name = "eee"
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(customerToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PatchAsync($"api/Customers/{Guid.NewGuid()}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound);
- }
-
- [Fact]
- public async Task Patch_WhenEntityDoesntImplementGetFields_ReturnsBadRequest()
- {
- // Arrange
- var seller = new SellerDto()
- {
- Id = Guid.NewGuid(),
- Name = "Seller",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(seller), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PatchAsync($"api/Sellers/{seller.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var responseMessages = JsonConvert.DeserializeObject(responseData);
-
- responseMessages.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
- }
-
- [Fact]
- public async Task Patch_WhenPatchIsNotAllowedByActionOptions_ShouldReturnMethodNotAllowed()
- {
- // Arrange
- var dbSet = Context.Set();
- var entity = new IntAsIdEntity() { Name = "abc" };
- dbSet.Add(entity);
- await Context.SaveChangesAsync();
-
- var entityToUpdate = new IntAsIdEntityDto()
- {
- Id = entity.Id,
- Name = "aaaa",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(entityToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PatchAsync($"api/IntAsIdEntities/{entity.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.MethodNotAllowed);
-
- var notUpdatedEntity = dbSet.AsNoTracking().First(x => x.Id == entity.Id);
- notUpdatedEntity.Name.Should().Be(entity.Name);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Post.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Post.cs
deleted file mode 100644
index 289ff92..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Post.cs
+++ /dev/null
@@ -1,89 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Errors;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task Post_WithValidData_ShouldInsertObject()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
-
- var content = new StringContent(JsonConvert.SerializeObject(customer), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PostAsync("api/Customers", content);
-
- // Assert
- var addedCustomer = dbSet.AsNoTracking().First(x => x.Id == customer.Id);
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.Created);
- addedCustomer.Name.Should().Be(customer.Name);
- addedCustomer.CNPJ.Should().Be(customer.CNPJ);
- }
-
- [Fact]
- public async Task Post_WithInvalidData_ShouldNotInsertObjectAndReturn400Error()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "567", Name = "ac" };
-
- var content = new StringContent(JsonConvert.SerializeObject(customer), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PostAsync("api/Customers", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var responseMessages = JsonConvert.DeserializeObject(responseData);
-
- responseMessages.Error["Name"].Should().Contain("Name should have at least 3 characters");
- responseMessages.Error["CNPJ"].Should().Contain("CNPJ cannot be 567");
-
- var customers = dbSet.AsNoTracking().ToList();
- customers.Should().BeEmpty();
- }
-
- [Fact]
- public async Task Post_WhenEntityDoesntImplementGetFields_ReturnsBadRequest()
- {
- // Arrange
- var dbSet = Context.Set();
-
- var seller = new SellerDto()
- {
- Name = "Seller",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(seller), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PostAsync("api/Sellers", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var responseMessages = JsonConvert.DeserializeObject(responseData);
-
- responseMessages.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
-
- var sellers = dbSet.AsNoTracking().ToList();
- sellers.Should().BeEmpty();
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Put.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Put.cs
deleted file mode 100644
index 9b1e8c7..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.Put.cs
+++ /dev/null
@@ -1,116 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using AspNetCore.RestFramework.Core.Errors;
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task Put_WithFullObject_ShouldUpdateFullObject()
- {
- // Arrange
- var dbSet = Context.Set();
- var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
- dbSet.Add(customer);
- await Context.SaveChangesAsync();
-
- var customerToUpdate = new
- {
- Id = customer.Id,
- CNPJ = "aaaa",
- Name = "eee"
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(customerToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PutAsync($"api/Customers/{customer.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var updatedCustomer = dbSet.AsNoTracking().First(x => x.Id == customer.Id);
- updatedCustomer.Name.Should().Be(customerToUpdate.Name);
- updatedCustomer.CNPJ.Should().Be(customerToUpdate.CNPJ);
- }
-
- [Fact]
- public async Task Put_WhenEntityDoesntExist_ReturnsNotFound()
- {
- // Arrange
- var customerToUpdate = new
- {
- CNPJ = "aaaa",
- Name = "eee"
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(customerToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PutAsync($"api/Customers/{Guid.NewGuid()}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.NotFound);
- }
-
- [Fact]
- public async Task Put_WhenEntityDoesntImplementGetFields_ReturnsBadRequest()
- {
- // Arrange
- var seller = new SellerDto()
- {
- Id = Guid.NewGuid(),
- Name = "Seller",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(seller), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PutAsync($"api/Sellers/{seller.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.BadRequest);
- var responseData = await response.Content.ReadAsStringAsync();
- var responseMessages = JsonConvert.DeserializeObject(responseData);
-
- responseMessages.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
- }
-
- [Fact]
- public async Task Put_WhenPutIsNotAllowedByActionOptions_ShouldReturnMethodNotAllowed()
- {
- // Arrange
- var dbSet = Context.Set();
- var entity = new IntAsIdEntity() { Name = "abc" };
- dbSet.Add(entity);
- Context.SaveChanges();
-
- var entityToUpdate = new IntAsIdEntityDto()
- {
- Id = entity.Id,
- Name = "aaaa",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(entityToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PutAsync($"api/IntAsIdEntities/{entity.Id}", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.MethodNotAllowed);
-
- var notUpdatedEntity = dbSet.AsNoTracking().First(x => x.Id == entity.Id);
- notUpdatedEntity.Name.Should().Be(entity.Name);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.PutMany.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.PutMany.cs
deleted file mode 100644
index 00fed5f..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.PutMany.cs
+++ /dev/null
@@ -1,79 +0,0 @@
-using AspNetRestFramework.Sample.DTO;
-using AspNetRestFramework.Sample.Models;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests
- {
- [Fact]
- public async Task PutMany_ShouldUpdateManyEntities_AndReturnTheirIds()
- {
- // Arrange
- var dbSet = Context.Set();
- dbSet.Add(new Customer() { Id = Guid.Parse("35d948bd-ab3d-4446-912b-2d20c57c4935"), CNPJ = "123", Name = "abc" });
- dbSet.Add(new Customer() { Id = Guid.Parse("6bdc2b9e-3710-40b9-93dd-c7558b446e21"), CNPJ = "456", Name = "def" });
- dbSet.Add(new Customer() { Id = Guid.Parse("22ee1df9-c543-4509-a755-e7cd5dc0045e"), CNPJ = "789", Name = "ghi" });
- await Context.SaveChangesAsync();
-
- var customerData = new CustomerDto
- {
- CNPJ = "aaaa",
- Name = "eee"
- };
-
- var expectedGuids = new[] {
- Guid.Parse("6bdc2b9e-3710-40b9-93dd-c7558b446e21"),
- Guid.Parse("22ee1df9-c543-4509-a755-e7cd5dc0045e"),
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(customerData), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PutAsync($"api/Customers?ids=6bdc2b9e-3710-40b9-93dd-c7558b446e21&ids=22ee1df9-c543-4509-a755-e7cd5dc0045e", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- var updatedIds = JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync());
- updatedIds.Should().BeEquivalentTo(expectedGuids);
-
- var updatedEntities = dbSet.Where(m => expectedGuids.Contains(m.Id)).AsNoTracking();
- updatedEntities.Should().BeEquivalentTo(
- new[] {
- new Customer() { CNPJ = "aaaa", Name = "eee" },
- new Customer() { CNPJ = "aaaa", Name = "eee" },
- },
- config => config
- .Including(m => m.CNPJ)
- .Including(m => m.Name)
- );
- }
-
- [Fact]
- public async Task PutMany_WhenPutIsNotAllowedByActionOptions_ShouldReturnMethodNotAllowed()
- {
- // Arrange
- var entityToUpdate = new IntAsIdEntityDto()
- {
- Name = "aaaa",
- };
-
- var content = new StringContent(JsonConvert.SerializeObject(entityToUpdate), Encoding.UTF8, "application/json-patch+json");
-
- // Act
- var response = await Client.PutAsync($"api/IntAsIdEntities?ids=1&ids=2", content);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.MethodNotAllowed);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.cs b/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.cs
deleted file mode 100644
index ffcb5b8..0000000
--- a/AspNetCore.RestFramework.Test/Core/BaseController/BaseControllerTests.cs
+++ /dev/null
@@ -1,31 +0,0 @@
-using AspNetCore.RestFramework.Core.Base;
-using FluentAssertions;
-using Microsoft.EntityFrameworkCore;
-using Newtonsoft.Json;
-using System;
-using System.Linq;
-using System.Net.Http;
-using System.Text;
-using System.Threading.Tasks;
-using AspNetRestFramework.Sample.Models;
-using Xunit;
-using AspNetCore.RestFramework.Core.Errors;
-
-namespace AspNetCore.RestFramework.Test.Core.BaseController
-{
- public partial class BaseControllerTests : IntegrationTestBase
- {
- [Fact]
- public async Task SwaggerJson_ShouldReturnStatus200()
- {
- // Arrange
- const string urlSwagger = "/swagger/v1/swagger.json";
-
- // Act
- var response = await Client.GetAsync(urlSwagger);
-
- // Assert
- response.StatusCode.Should().Be(System.Net.HttpStatusCode.OK);
- }
- }
-}
diff --git a/AspNetCore.RestFramework.Test/IntegrationTestBase.cs b/AspNetCore.RestFramework.Test/IntegrationTestBase.cs
deleted file mode 100644
index b572aac..0000000
--- a/AspNetCore.RestFramework.Test/IntegrationTestBase.cs
+++ /dev/null
@@ -1,52 +0,0 @@
-using AspNetRestFramework.Sample;
-using AspNetRestFramework.Sample.Context;
-using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.TestHost;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.Extensions.Configuration;
-using System;
-using System.IO;
-using System.Net.Http;
-using Xunit;
-
-namespace AspNetCore.RestFramework.Test
-{
- [Collection("Database Collection")]
- public abstract class IntegrationTestBase
- {
- protected IntegrationTestBase()
- {
- var applicationPath = Directory.GetCurrentDirectory();
-
- Server = new TestServer(new WebHostBuilder()
- .UseEnvironment("Testing")
- .UseContentRoot(applicationPath)
- .UseConfiguration(new ConfigurationBuilder()
- .SetBasePath(applicationPath)
- .AddJsonFile("appsettings.json")
- .AddEnvironmentVariables()
- .Build()
- )
- .UseStartup());
-
- Context = (ApplicationDbContext)Server.Services.GetService(typeof(ApplicationDbContext));
-
- Client = Server.CreateClient();
-
- ClearDatabase();
- }
-
- protected TestServer Server { get; }
- protected ApplicationDbContext Context { get; }
- protected HttpClient Client { get; }
-
- protected void ClearDatabase()
- {
- Context.Database.ExecuteSqlRaw(@"
- EXEC sp_msforeachtable 'ALTER TABLE ? NOCHECK CONSTRAINT all';
- EXEC sp_msforeachtable 'DELETE FROM ?';
- EXEC sp_msforeachtable 'ALTER TABLE ? CHECK CONSTRAINT all';
- ");
- }
- }
-}
diff --git a/AspNetCoreRestFramework.sln b/AspNetCore.RestFramework.sln
similarity index 78%
rename from AspNetCoreRestFramework.sln
rename to AspNetCore.RestFramework.sln
index 4d1ab94..0f8031a 100644
--- a/AspNetCoreRestFramework.sln
+++ b/AspNetCore.RestFramework.sln
@@ -3,11 +3,9 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31424.327
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.RestFramework.Sample", "AspNetCore.RestFramework.Sample\AspNetCore.RestFramework.Sample.csproj", "{1BD03AAE-F48D-4153-8DAD-964E4CD81CD4}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.RestFramework.Core.Test", "tests\AspNetCore.RestFramework.Core.Test\AspNetCore.RestFramework.Core.Test.csproj", "{5C337F78-3254-477E-9937-42FD595F9733}"
EndProject
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AspNetCore.RestFramework.Test", "AspNetCore.RestFramework.Test\AspNetCore.RestFramework.Test.csproj", "{5C337F78-3254-477E-9937-42FD595F9733}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.RestFramework.Core", "AspNetCore.RestFramework.Core\AspNetCore.RestFramework.Core.csproj", "{CA09285F-319F-459A-844D-9AF468C0ABF5}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AspNetCore.RestFramework.Core", "src\AspNetCore.RestFramework.Core\AspNetCore.RestFramework.Core.csproj", "{CA09285F-319F-459A-844D-9AF468C0ABF5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..f46ab5b
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+ true
+
+
diff --git a/Dockerfile b/Dockerfile
index bb58bee..b05377d 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,22 @@
-FROM juntossomosmais/dotnet-sonar:6.0
+ARG DOTNET_VERSION=8.0
-# Install EF Core tools
-RUN dotnet tool install --global dotnet-ef --version 6.0.2
+FROM mcr.microsoft.com/dotnet/sdk:$DOTNET_VERSION
WORKDIR /app
-COPY . ./
\ No newline at end of file
+
+# https://github.com/dotnet/dotnet-docker/issues/520
+ENV PATH="${PATH}:/root/.dotnet/tools"
+
+# Tools used during development
+RUN dotnet tool install --global dotnet-ef
+RUN dotnet tool install --global dotnet-format
+
+# Restores (downloads) all NuGet packages from all projects of the solution on a separate layer
+COPY src/AspNetCore.RestFramework.Core/*.csproj ./src/AspNetCore.RestFramework.Core/
+COPY tests/AspNetCore.RestFramework.Core.Test/*.csproj ./tests/AspNetCore.RestFramework.Core.Test/
+
+RUN dotnet restore --locked-mode src/AspNetCore.RestFramework.Core
+RUN dotnet restore --locked-mode tests/AspNetCore.RestFramework.Core.Test
+
+COPY . ./
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f311848
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2024 Juntos Somos Mais
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/README.md b/README.md
index 2bf6d2b..8d3557c 100644
--- a/README.md
+++ b/README.md
@@ -1,54 +1,34 @@
-# csharp-rest-framework
+# AspNetCore.RestFramework
-O [csharp-rest-framework](https://github.com/juntossomosmais/csharp-rest-framework), ou `AspNetCore.RestFramework.Core`, é um framework para ASP.NET desenvolvido pela Juntos Somos Mais para tornar mais prática e uniforme a criação de APIs REST.
+AspNetCore REST Framework makes you focus on business, not on boilerplate code. It's designed to follow the famous Django's slogan "The web framework for perfectionists with deadlines." 🤺
-## Sumário
+This is a copy of the convention established by [Django REST framework](https://github.com/encode/django-rest-framework), though translated to C# and adapted to the .NET Core framework.
-- [csharp-rest-framework](#csharp-rest-framework)
- - [Sumário](#sumário)
- - [Ordenação](#ordenação)
- - [Filtros](#filtros)
- - [QueryStringFilter](#querystringfilter)
- - [QueryStringIdRangeFilter](#querystringidrangefilter)
- - [QueryStringSearchFilter](#querystringsearchfilter)
- - [Implementando um filtro](#implementando-um-filtro)
- - [Erros](#erros)
- - [Validação](#validação)
- - [Serializer](#serializer)
- - [Exemplo de uso](#exemplo-de-uso)
- - [Entidade](#entidade)
- - [Entity Framework](#entity-framework)
- - [DTO](#dto)
- - [Validação](#validação-1)
- - [Include de entidades filhas/pais](#include-de-entidades-filhaspais)
- - [Controller](#controller)
- - [Dicionário](#dicionário)
+## Sorting
-## Ordenação
+In the `ListPaged` method, we use the query parameters `sort` or `sortDesc` to sort by a field. If not specified, we will always use the entity's `Id` field for ascending sorting.
-No método `ListPaged`, usamos os _query parameters_ `sort` ou `sortDesc` para fazer a ordenação por um campo. Se não for informado, usaremos sempre o campo `Id` da entidade para ordenação crescente.
+## Filters
-## Filtros
-
-Filtros são mecanismos aplicados sempre que tentamos obter os dados de uma entidade nos métodos `GetSingle` e `ListPaged`.
+Filters are mechanisms applied whenever we try to retrieve entity data in the `GetSingle` and `ListPaged` methods.
### QueryStringFilter
-O `QueryStringFilter`, talvez o mais relevante, é um filtro que faz _match_ dos campos passados nos _query parameters_ com os campos da entidade cujo filtro é permitido. Todos os filtros são criados usando como operador o _equals_ (`==`).
+The `QueryStringFilter`, perhaps the most relevant, is a filter that matches the fields passed in the query parameters with the fields of the entity whose filter is allowed. All filters are created using the equals (`==`) operator.
### QueryStringIdRangeFilter
-O `QueryStringIdRangeFilter` é um filtro cujo objetivo principal é atender o método `getMany` do React Admin, um framework utilizado em um dos nossos produtos, o Portal Admin (novo). Seu objetivo é, caso o parâmetro `ids` seja passado, filtrar as entidades pelo `Id` baseado em todos os `ids` informados nos _query parameters_.
+The `QueryStringIdRangeFilter` goal is to filter the entities by `Id` based on all the `ids` provided in the query parameters.
### QueryStringSearchFilter
-O `QueryStringSearchFilter` é um filtro que permite que seja informado um parâmetro `search` nos _query parameters_ para fazer uma busca, através de um único input, em vários campos da entidade, inclusive fazendo `LIKE` em strings.
+The `QueryStringSearchFilter` is a filter that allows a `search` parameter to be provided in the query parameters to search, through a single input, in several fields of the entity, even performing `LIKE` on strings.
-### Implementando um filtro
+### Implementing a filter
-Dado um `IQueryable` e um `HttpRequest`, você pode implementar o filtro da maneira como preferir. Basta herdar da classe base e adicionar ao seu _controller_:
+Given an `IQueryable` and an `HttpRequest`, you can implement the filter as you prefer. Just inherit from the base class and add it to your controller:
-```cs
+```csharp
public class MyFilter : AspNetCore.RestFramework.Core.Filters.Filter
{
private readonly string _forbiddenName;
@@ -65,65 +45,57 @@ public class MyFilter : AspNetCore.RestFramework.Core.Filters.Filter
}
```
-```cs
+```csharp
public class SellerController
{
public SellerController(...)
: base(...)
{
- Filters.Add(new MyFilter("Exemplo"));
+ Filters.Add(new MyFilter("Example"));
}
}
```
-## Erros
-
-Utilizamos como padrão de erros [este aqui](https://votorantimindustrial.sharepoint.com/:w:/r/sites/juntos_somos_mais/_layouts/15/Doc.aspx?sourcedoc=%7BE8895835-9397-4E19-9046-26D7168A931A%7D&file=Padr%C3%A3o%20de%20retorno%20das%20APIs.docx&action=default&mobileredirect=true), que é o padrão indicado no nosso [playbook de C#](https://github.com/juntossomosmais/playbook/blob/master/backend/csharp.md).
+## Errors
-No framework, as classes `ValidationErrors` e `UnexpectedError` já implementam esse contrato, sendo retornadas no `BaseController` em caso de erros de validação ou outra exception.
+The `ValidationErrors` and `UnexpectedError` might be returned in the `BaseController` in case of validation errors or other exceptions.
-## Validação
+## Validation
-Para validação, também conforme o playbook, devemos utilizar **FluentValidation**. Basta implementar os _validators_ dos DTOs e configurar sua aplicação com a extensão (2) `ModelStateValidationExtensions.ConfigureValidationResponseFormat` para garantir que, caso o `ModelState` seja inválido, um `ValidationErrors` seja retornado com um `400 Not Found`.
+Implement validators for the DTOs and configure your application with the extension `ModelStateValidationExtensions.ConfigureValidationResponseFormat` to ensure that in case of the `ModelState` being invalid, a `ValidationErrors` is returned. It might be necessary to add the `HttpContext` accessor to the services. Check the example below:
-Além disso
-- (1) Devemos usar o `JSM.FluentValidations.AspNet.AsyncFilter`;
-- (3) **Talvez** se faça necessário acessar o `HttpContext` nos _validators_, para isso basta adicionar o acessor aos serviços.
-
-```cs
+```csharp
services.AddControllers()
- ...
- // no final do AddControllers, adicione o seguinte:
- // 1 - JSM.FluentValidations.AspNet.AsyncFilter
+ // ...
+ // At the end of AddControllers, add the following:
.AddModelValidationAsyncActionFilter(options =>
{
options.OnlyApiController = true;
})
- // 2 - ModelStateValidationExtensions
+ // ModelStateValidationExtensions
.ConfigureValidationResponseFormat();
-
-// 3 - acessor do HttpContext
+// ...
services.AddHttpContextAccessor();
```
## Serializer
-O `Serializer` é um mecanismo utilizado pelo `BaseController` como se fosse um _service_. Nele, estão as lógicas utilizadas pelo _controller_, e este _serializer_ é injetado em cada um. Ele pode ter seus métodos sobrescritos, por exemplo, para lógicas adicionais ou diferentes em entidades específicas.
+`Serializer` is a mechanism used by the `BaseController`. Each controller has its own serializer. The serializer's methods can be overridden to add additional or different logic for specific entities. It works more or less similar to the [Django REST framework's serializers](https://www.django-rest-framework.org/api-guide/serializers/).
-## Exemplo de uso
+## Quickstart with an example
-Vamos, como exemplo, criar uma API para uma suposta entidade `Customer`.
+Let's create a CRUD API for a `Customer` entity with a `CustomerDocument` child entity.
-### Entidade
+### Entity
-Algumas características das entidades:
+Some characteristics of the entities:
-- Devemos herdar de `BaseModel`.
- - O `TPrimaryKey` é o tipo da chave primária, no marketplace costumamos usar `Guid`.
-- O `GetFields` é um método cuja implementação é obrigatória. Ele informa quais campos de uma entidade serão serializados na _response_ da API.
- - Para campos de entidades filhas ou pais, podemos usar o `:` para indicá-las para que também sejam serializadas. Nesse caso, é necessário fazer o `Include` com um filtro.
+- We should inherit from `BaseModel`.
+ - The `TPrimaryKey` is the type of the primary key. In this case, we are using `Guid`.
+- The `GetFields` method is mandatory. It informs which fields of the entity will be serialized in the API response.
+ - For fields of child or parent entities, we can use `:` to indicate them to be serialized as well. In this case, it is necessary to perform the `Include` with a filter.
-```cs
+```csharp
public class Customer : BaseModel
{
public string Name { get; set; }
@@ -141,9 +113,9 @@ public class Customer : BaseModel
### Entity Framework
-Basta adicionar a collection ao `DbContext` da aplicação:
+Add the collection to the application's `DbContext`:
-```cs
+```csharp
public class ApplicationDbContext : DbContext
{
public DbSet Customer { get; set; }
@@ -152,27 +124,25 @@ public class ApplicationDbContext : DbContext
### DTO
-No DTO, precisamos apenas herdar de `BaseDto`, parecido com a entidade, e colocar lá.
+The DTO is required to inherit from `BaseDto`, like the entity.
-```cs
+```csharp
public class CustomerDto : BaseDto
{
- public CustomerDto()
- {
- }
+ public CustomerDto() { }
public string Name { get; set; }
public string CNPJ { get; set; }
-
+
public ICollection CustomerDocuments { get; set; }
}
```
-### Validação
+### Validation
-Com o DTO criado, se necessário, devemos criar o _validator_ para ele. Abaixo, temos um exemplo bem simples dessa implementação:
+A validation is not mandatory, but it is recommended to ensure that the data is correct. The validation is done using the `FluentValidation` library.
-```cs
+```csharp
public class CustomerDtoValidator : AbstractValidator
{
public CustomerDtoValidator(IHttpContextAccessor context)
@@ -189,12 +159,11 @@ public class CustomerDtoValidator : AbstractValidator
}
```
+### Include child/parent entities
-### Include de entidades filhas/pais
+Previously, we included the `CustomerDocument` entity in the `Customer` entity. Check out the `GetFields` method in the `Customer` entity.
-Precisamos criar um filtro para dar o `Include` na entidade filha `CustomerDocument`. Simples assim:
-
-```cs
+```csharp
public class CustomerDocumentIncludeFilter : Filter
{
public override IQueryable AddFilter(IQueryable query, HttpRequest request)
@@ -206,11 +175,9 @@ public class CustomerDocumentIncludeFilter : Filter
### Controller
-Agora, basta criar o _controller_ da entidade para criar a API.
-
-Perceba que o `AllowedFields` é usado para configurar a maioria dos filtros de _query string_.
+The CRUD API is created by inheriting from the `BaseController` and passing the necessary parameters. Note how `AllowedFields` and `Filters` are set.
-```cs
+```csharp
[Route("api/[controller]")]
[ApiController]
public class CustomersController : BaseController
@@ -239,16 +206,20 @@ public class CustomersController : BaseController&2; fi }
-
-usage()
-{
- cat << USAGE >&2
-Usage:
- $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args]
- -h HOST | --host=HOST Host or IP under test
- -p PORT | --port=PORT TCP port under test
- Alternatively, you specify the host and port as host:port
- -s | --strict Only execute subcommand if the test succeeds
- -q | --quiet Don't output any status messages
- -t TIMEOUT | --timeout=TIMEOUT
- Timeout in seconds, zero for no timeout
- -- COMMAND ARGS Execute command with args after the test finishes
-USAGE
- exit 1
-}
-
-wait_for()
-{
- if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
- echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
- else
- echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout"
- fi
- WAITFORIT_start_ts=$(date +%s)
- while :
- do
- if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then
- nc -z $WAITFORIT_HOST $WAITFORIT_PORT
- WAITFORIT_result=$?
- else
- (echo > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1
- WAITFORIT_result=$?
- fi
- if [[ $WAITFORIT_result -eq 0 ]]; then
- WAITFORIT_end_ts=$(date +%s)
- echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds"
- break
- fi
- sleep 1
- done
- return $WAITFORIT_result
-}
-
-wait_for_wrapper()
-{
- # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
- if [[ $WAITFORIT_QUIET -eq 1 ]]; then
- timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
- else
- timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT &
- fi
- WAITFORIT_PID=$!
- trap "kill -INT -$WAITFORIT_PID" INT
- wait $WAITFORIT_PID
- WAITFORIT_RESULT=$?
- if [[ $WAITFORIT_RESULT -ne 0 ]]; then
- echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT"
- fi
- return $WAITFORIT_RESULT
-}
-
-# process arguments
-while [[ $# -gt 0 ]]
-do
- case "$1" in
- *:* )
- WAITFORIT_hostport=(${1//:/ })
- WAITFORIT_HOST=${WAITFORIT_hostport[0]}
- WAITFORIT_PORT=${WAITFORIT_hostport[1]}
- shift 1
- ;;
- --child)
- WAITFORIT_CHILD=1
- shift 1
- ;;
- -q | --quiet)
- WAITFORIT_QUIET=1
- shift 1
- ;;
- -s | --strict)
- WAITFORIT_STRICT=1
- shift 1
- ;;
- -h)
- WAITFORIT_HOST="$2"
- if [[ $WAITFORIT_HOST == "" ]]; then break; fi
- shift 2
- ;;
- --host=*)
- WAITFORIT_HOST="${1#*=}"
- shift 1
- ;;
- -p)
- WAITFORIT_PORT="$2"
- if [[ $WAITFORIT_PORT == "" ]]; then break; fi
- shift 2
- ;;
- --port=*)
- WAITFORIT_PORT="${1#*=}"
- shift 1
- ;;
- -t)
- WAITFORIT_TIMEOUT="$2"
- if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi
- shift 2
- ;;
- --timeout=*)
- WAITFORIT_TIMEOUT="${1#*=}"
- shift 1
- ;;
- --)
- shift
- WAITFORIT_CLI=("$@")
- break
- ;;
- --help)
- usage
- ;;
- *)
- echoerr "Unknown argument: $1"
- usage
- ;;
- esac
-done
-
-if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then
- echoerr "Error: you need to provide a host and port to test."
- usage
-fi
-
-WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15}
-WAITFORIT_STRICT=${WAITFORIT_STRICT:-0}
-WAITFORIT_CHILD=${WAITFORIT_CHILD:-0}
-WAITFORIT_QUIET=${WAITFORIT_QUIET:-0}
-
-# check to see if timeout is from busybox?
-WAITFORIT_TIMEOUT_PATH=$(type -p timeout)
-WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH)
-if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then
- WAITFORIT_ISBUSY=1
- WAITFORIT_BUSYTIMEFLAG="-t"
-
-else
- WAITFORIT_ISBUSY=0
- WAITFORIT_BUSYTIMEFLAG=""
-fi
-
-if [[ $WAITFORIT_CHILD -gt 0 ]]; then
- wait_for
- WAITFORIT_RESULT=$?
- exit $WAITFORIT_RESULT
-else
- if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then
- wait_for_wrapper
- WAITFORIT_RESULT=$?
- else
- wait_for
- WAITFORIT_RESULT=$?
- fi
-fi
-
-if [[ $WAITFORIT_CLI != "" ]]; then
- if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then
- echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess"
- exit $WAITFORIT_RESULT
- fi
- exec "${WAITFORIT_CLI[@]}"
-else
- exit
-fi
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
deleted file mode 100644
index 5f0ca6c..0000000
--- a/azure-pipelines.yml
+++ /dev/null
@@ -1,25 +0,0 @@
-trigger:
- - main
-
-pr:
- - main
-
-variables:
- - group: Main variables for all pipelines
- - group: sonar-cloud-config
-
-resources:
- repositories:
- - repository: templates
- type: github
- name: juntossomosmais/azure-pipelines-templates
- endpoint: github.com
- ref: refactor/change-folder-structure
-
-extends:
- template: dotnet/nuget_deploy_artifacts.yaml@templates
- parameters:
- SonarProject: "juntossomosmais_csharp-rest-framework"
- AzureFeedId: "7a82b4a3-6db8-4249-a7ec-9968996b9406/0d3df630-9f80-4d07-b31c-822063ea1dd0"
- AzurePackageId: "46a8a833-03d0-4d89-97f4-4ef2fc850e13"
- DotnetVersion: "6.0.x"
\ No newline at end of file
diff --git a/docker-compose.yml b/docker-compose.yml
index 28e142a..5ecb602 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,24 +1,42 @@
version: "3.6"
services:
-
- sqlserver:
- image: mcr.microsoft.com/mssql/server:latest
+ db:
+ image: "mcr.microsoft.com/mssql/server:2022-latest"
+ ports:
+ - "1433:1433"
environment:
- SA_PASSWORD: Password1
+ SA_PASSWORD: "Password1"
ACCEPT_EULA: "Y"
- ports:
- - 1433:1433
+ # Developer / Express / Standard / Enterprise / EnterpriseCore
+ MSSQL_PID: Developer
+ MSSQL_TCP_PORT: 1433
+ healthcheck:
+ test: /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U sa -P "$$SA_PASSWORD" -Q "SELECT 1" -b -o /dev/null
+ interval: 10s
+ timeout: 3s
+ retries: 10
+ start_period: 10s
integration-tests:
- container_name: csharp-rest-framework-integration-tests
build:
context: .
dockerfile: Dockerfile
depends_on:
- - sqlserver
+ db:
+ condition: service_healthy
+ volumes:
+ - .:/app
environment:
- - "ConnectionStrings__DefaultConnectionString=Data Source=sqlserver,1433;Initial Catalog=RestFramework;User Id=sa;Password=Password1"
- command:
- [
- "./Scripts/start-tests.sh"
- ]
\ No newline at end of file
+ - "ConnectionStrings__AppDbContext=Data Source=db,1433;Initial Catalog=REPLACE_ME_PROGRAMATICALLY;User Id=sa;Password=Password1;TrustServerCertificate=True"
+ command: [ "./scripts/start-tests.sh" ]
+
+ lint-formatter:
+ build:
+ context: .
+ dockerfile: Dockerfile
+ volumes:
+ - .:/app
+ # Uncomment the following line to run the checker
+ # command: [ "./scripts/start-check-formatting.sh" ]
+ # Uncomment the following line to run the formatter
+ command: [ "./scripts/start-formatter.sh" ]
diff --git a/nuget.config b/nuget.config
deleted file mode 100644
index 9311ef2..0000000
--- a/nuget.config
+++ /dev/null
@@ -1,15 +0,0 @@
-
-
-
-
-
-
-
-
-
-
diff --git a/scripts/start-check-formatting.sh b/scripts/start-check-formatting.sh
new file mode 100755
index 0000000..a40019b
--- /dev/null
+++ b/scripts/start-check-formatting.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -e
+
+dotnet format --verify-no-changes --verbosity d
diff --git a/scripts/start-formatter.sh b/scripts/start-formatter.sh
new file mode 100755
index 0000000..94acc03
--- /dev/null
+++ b/scripts/start-formatter.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+
+set -e
+
+dotnet format --verbosity d
diff --git a/scripts/start-sonarcloud.sh b/scripts/start-sonarcloud.sh
new file mode 100755
index 0000000..2f4f713
--- /dev/null
+++ b/scripts/start-sonarcloud.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+set -eu -o pipefail
+
+# You should start the scanner prior building your project and running your tests
+if [ -n "${PR_SOURCE_BRANCH:-}" ]; then
+ dotnet sonarscanner begin \
+ /d:sonar.login="$SONAR_TOKEN" \
+ /k:"juntossomosmais_AspNetCore.RestFramework" \
+ /o:"juntossomosmais" \
+ /d:sonar.host.url="https://sonarcloud.io" \
+ /d:sonar.cs.opencover.reportsPaths="**/*/coverage.opencover.xml" \
+ /d:sonar.cs.vstest.reportsPaths="**/*/*.trx" \
+ /d:sonar.pullrequest.base="$PR_TARGET_BRANCH" \
+ /d:sonar.pullrequest.branch="$PR_SOURCE_BRANCH" \
+ /d:sonar.pullrequest.key="$GITHUB_PR_NUMBER"
+else
+ dotnet sonarscanner begin \
+ /d:sonar.login="$SONAR_TOKEN" \
+ /v:"$PROJECT_VERSION" \
+ /k:"juntossomosmais_AspNetCore.RestFramework" \
+ /o:"juntossomosmais" \
+ /d:sonar.host.url="https://sonarcloud.io" \
+ /d:sonar.cs.opencover.reportsPaths="**/*/coverage.opencover.xml" \
+ /d:sonar.cs.vstest.reportsPaths="**/*/*.trx" \
+ /d:sonar.branch.name="$SOURCE_BRANCH_NAME"
+fi
+
+# Now we can run our tests as usual
+./scripts/start-tests.sh
+
+# Now we can collect the results 👍
+dotnet sonarscanner end /d:sonar.login="$SONAR_TOKEN"
diff --git a/scripts/start-tests.sh b/scripts/start-tests.sh
new file mode 100755
index 0000000..f43c81d
--- /dev/null
+++ b/scripts/start-tests.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+set -e
+
+dotnet test tests/AspNetCore.RestFramework.Core.Test \
+--configuration Release \
+--logger trx \
+--logger "console;verbosity=normal" \
+--settings "./runsettings.xml"
diff --git a/sonar-project.xml b/sonar-project.xml
index ba0c9cc..58bd90f 100644
--- a/sonar-project.xml
+++ b/sonar-project.xml
@@ -1,10 +1,9 @@
-
+
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
+ xmlns="http://www.sonarsource.com/msbuild/integration/2015/1">
http://localhost:9000
**/*/coverage.opencover.xml
**/*/*.trx
- **/Migrations/*.cs,**/Swagger/*.cs
- AspNetCore.RestFramework.Sample/**/*.cs
-
\ No newline at end of file
+ **/Migrations/*.cs
+
diff --git a/src/AspNetCore.RestFramework.Core/AspNetCore.RestFramework.Core.csproj b/src/AspNetCore.RestFramework.Core/AspNetCore.RestFramework.Core.csproj
new file mode 100644
index 0000000..8df3dfb
--- /dev/null
+++ b/src/AspNetCore.RestFramework.Core/AspNetCore.RestFramework.Core.csproj
@@ -0,0 +1,22 @@
+
+
+
+ net8.0
+
+ AspNetCore.RestFramework
+ andresantarosa,fabio_almeida100,phmonte,ricardochaves,willianantunes
+ Don't code a bunch of code to create CRUD applications. Use AspNetCore REST Framework, inspired by Django REST framework! It aims to provide a robust and flexible foundation for building RESTful APIs using ASP.NET Core.
+ https://github.com/juntossomosmais/AspNetCore.RestFramework/blob/master/LICENSE
+ https://github.com/juntossomosmais/AspNetCore.RestFramework
+ api rest drf django pagination crud
+ true
+ snupkg
+
+
+
+
+
+
+
+
+
diff --git a/AspNetCore.RestFramework.Core/Base/ActionOptions.cs b/src/AspNetCore.RestFramework.Core/Base/ActionOptions.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/ActionOptions.cs
rename to src/AspNetCore.RestFramework.Core/Base/ActionOptions.cs
diff --git a/AspNetCore.RestFramework.Core/Base/BaseController.cs b/src/AspNetCore.RestFramework.Core/Base/BaseController.cs
similarity index 99%
rename from AspNetCore.RestFramework.Core/Base/BaseController.cs
rename to src/AspNetCore.RestFramework.Core/Base/BaseController.cs
index ae1c884..5f71a7f 100644
--- a/AspNetCore.RestFramework.Core/Base/BaseController.cs
+++ b/src/AspNetCore.RestFramework.Core/Base/BaseController.cs
@@ -1,5 +1,4 @@
-using JSM.PartialJsonObject;
-using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System;
@@ -12,6 +11,7 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using AspNetCore.RestFramework.Core.Errors;
+using AspNetCore.RestFramework.Core.Helpers;
namespace AspNetCore.RestFramework.Core.Base
{
@@ -161,7 +161,7 @@ public virtual async Task Patch(
return BadRequest(new UnexpectedError(BaseMessages.ERROR_GET_FIELDS));
var data = await _serializer.PatchAsync(entity, id);
-
+
if (data == null)
return NotFound();
@@ -320,4 +320,4 @@ public virtual IQueryable GetQuerySet()
#endregion
}
-}
\ No newline at end of file
+}
diff --git a/AspNetCore.RestFramework.Core/Base/BaseDto.cs b/src/AspNetCore.RestFramework.Core/Base/BaseDto.cs
similarity index 76%
rename from AspNetCore.RestFramework.Core/Base/BaseDto.cs
rename to src/AspNetCore.RestFramework.Core/Base/BaseDto.cs
index 48af794..1e55249 100644
--- a/AspNetCore.RestFramework.Core/Base/BaseDto.cs
+++ b/src/AspNetCore.RestFramework.Core/Base/BaseDto.cs
@@ -1,6 +1,6 @@
namespace AspNetCore.RestFramework.Core.Base
{
- public abstract class BaseDto
+ public abstract class BaseDto
{
[System.Text.Json.Serialization.JsonIgnore]
public TPrimaryKey Id { get; set; }
diff --git a/AspNetCore.RestFramework.Core/Base/BaseErrorResponse.cs b/src/AspNetCore.RestFramework.Core/Base/BaseErrorResponse.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/BaseErrorResponse.cs
rename to src/AspNetCore.RestFramework.Core/Base/BaseErrorResponse.cs
diff --git a/AspNetCore.RestFramework.Core/Base/BaseFilter.cs b/src/AspNetCore.RestFramework.Core/Base/BaseFilter.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/BaseFilter.cs
rename to src/AspNetCore.RestFramework.Core/Base/BaseFilter.cs
diff --git a/AspNetCore.RestFramework.Core/Base/BaseMessages.cs b/src/AspNetCore.RestFramework.Core/Base/BaseMessages.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/BaseMessages.cs
rename to src/AspNetCore.RestFramework.Core/Base/BaseMessages.cs
diff --git a/AspNetCore.RestFramework.Core/Base/BaseModel.cs b/src/AspNetCore.RestFramework.Core/Base/BaseModel.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/BaseModel.cs
rename to src/AspNetCore.RestFramework.Core/Base/BaseModel.cs
diff --git a/AspNetCore.RestFramework.Core/Base/IBaseModel.cs b/src/AspNetCore.RestFramework.Core/Base/IBaseModel.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/IBaseModel.cs
rename to src/AspNetCore.RestFramework.Core/Base/IBaseModel.cs
diff --git a/AspNetCore.RestFramework.Core/Base/PagedBaseResponse.cs b/src/AspNetCore.RestFramework.Core/Base/PagedBaseResponse.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Base/PagedBaseResponse.cs
rename to src/AspNetCore.RestFramework.Core/Base/PagedBaseResponse.cs
diff --git a/AspNetCore.RestFramework.Core/Errors/UnexpectedError.cs b/src/AspNetCore.RestFramework.Core/Errors/UnexpectedError.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Errors/UnexpectedError.cs
rename to src/AspNetCore.RestFramework.Core/Errors/UnexpectedError.cs
diff --git a/AspNetCore.RestFramework.Core/Errors/ValidationErrors.cs b/src/AspNetCore.RestFramework.Core/Errors/ValidationErrors.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Errors/ValidationErrors.cs
rename to src/AspNetCore.RestFramework.Core/Errors/ValidationErrors.cs
diff --git a/AspNetCore.RestFramework.Core/Extensions/ModelStateValidationExtensions.cs b/src/AspNetCore.RestFramework.Core/Extensions/ModelStateValidationExtensions.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Extensions/ModelStateValidationExtensions.cs
rename to src/AspNetCore.RestFramework.Core/Extensions/ModelStateValidationExtensions.cs
diff --git a/AspNetCore.RestFramework.Core/Filters/Filter.cs b/src/AspNetCore.RestFramework.Core/Filters/Filter.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Filters/Filter.cs
rename to src/AspNetCore.RestFramework.Core/Filters/Filter.cs
diff --git a/AspNetCore.RestFramework.Core/Filters/FilterBuilder.cs b/src/AspNetCore.RestFramework.Core/Filters/FilterBuilder.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Filters/FilterBuilder.cs
rename to src/AspNetCore.RestFramework.Core/Filters/FilterBuilder.cs
diff --git a/AspNetCore.RestFramework.Core/Filters/QueryStringFilter.cs b/src/AspNetCore.RestFramework.Core/Filters/QueryStringFilter.cs
similarity index 99%
rename from AspNetCore.RestFramework.Core/Filters/QueryStringFilter.cs
rename to src/AspNetCore.RestFramework.Core/Filters/QueryStringFilter.cs
index 7f2f151..fbbe55f 100644
--- a/AspNetCore.RestFramework.Core/Filters/QueryStringFilter.cs
+++ b/src/AspNetCore.RestFramework.Core/Filters/QueryStringFilter.cs
@@ -47,7 +47,7 @@ private static Expression> GetColumnEquality(string property
* */
var obj = Expression.Parameter(typeof(TEntity), "obj");
-
+
var objProperty = Expression.PropertyOrField(obj, property);
object convertedValue;
diff --git a/AspNetCore.RestFramework.Core/Filters/QueryStringIdRangeFilter.cs b/src/AspNetCore.RestFramework.Core/Filters/QueryStringIdRangeFilter.cs
similarity index 97%
rename from AspNetCore.RestFramework.Core/Filters/QueryStringIdRangeFilter.cs
rename to src/AspNetCore.RestFramework.Core/Filters/QueryStringIdRangeFilter.cs
index 4d3228f..6e7e22d 100644
--- a/AspNetCore.RestFramework.Core/Filters/QueryStringIdRangeFilter.cs
+++ b/src/AspNetCore.RestFramework.Core/Filters/QueryStringIdRangeFilter.cs
@@ -13,12 +13,12 @@ public override IQueryable AddFilter(IQueryable query, HttpReq
var idsFilter = request.Query.FirstOrDefault(m => m.Key.Equals("ids", StringComparison.OrdinalIgnoreCase));
var ids = idsFilter.Value.Select(ConvertToPrimaryKeyType).ToList();
- if (ids.Count> 0)
+ if (ids.Count > 0)
query = query.Where(m => ids.Contains(m.Id));
return query;
}
-
+
private static TPrimaryKey ConvertToPrimaryKeyType(string value)
{
try
diff --git a/AspNetCore.RestFramework.Core/Filters/QueryStringSearchFilter.cs b/src/AspNetCore.RestFramework.Core/Filters/QueryStringSearchFilter.cs
similarity index 99%
rename from AspNetCore.RestFramework.Core/Filters/QueryStringSearchFilter.cs
rename to src/AspNetCore.RestFramework.Core/Filters/QueryStringSearchFilter.cs
index e3f726f..ac42860 100644
--- a/AspNetCore.RestFramework.Core/Filters/QueryStringSearchFilter.cs
+++ b/src/AspNetCore.RestFramework.Core/Filters/QueryStringSearchFilter.cs
@@ -26,7 +26,7 @@ public override IQueryable AddFilter(IQueryable query, HttpReq
var parameter = Expression.Parameter(typeof(TEntity), "obj");
var expressions = new List();
-
+
foreach (var field in _allowedFields)
{
if (TryGetColumnFilter(field, searchFilter.Value, parameter, out Expression expression))
diff --git a/AspNetCore.RestFramework.Core/Filters/SortFilter.cs b/src/AspNetCore.RestFramework.Core/Filters/SortFilter.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Filters/SortFilter.cs
rename to src/AspNetCore.RestFramework.Core/Filters/SortFilter.cs
diff --git a/src/AspNetCore.RestFramework.Core/Helpers/PartialJsonObject.cs b/src/AspNetCore.RestFramework.Core/Helpers/PartialJsonObject.cs
new file mode 100644
index 0000000..c3ece53
--- /dev/null
+++ b/src/AspNetCore.RestFramework.Core/Helpers/PartialJsonObject.cs
@@ -0,0 +1,278 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Linq.Expressions;
+
+namespace AspNetCore.RestFramework.Core.Helpers
+{
+ [JsonConverter(typeof(PartialJsonObjectConverter))]
+ public class PartialJsonObject : PartialJsonObject where T : class
+ {
+ [JsonIgnore]
+ private T _instance;
+ [JsonIgnore]
+ public T Instance => _instance ?? (_instance = ToObject());
+
+ [JsonIgnore]
+ private Dictionary _cache = new Dictionary();
+
+ public PartialJsonObject(JObject jsonObject)
+ {
+ JsonObject = jsonObject;
+ }
+
+ public PartialJsonObject(string json)
+ {
+ JsonObject = JObject.Parse(json);
+ }
+
+ public bool IsSet(Expression> expPath)
+ {
+ var paths = ExpressionToPathParser.ParseExpressionToPaths(expPath.Body).ToArray();
+
+ return IsSet(paths);
+ }
+
+ public override bool IsSet(string path)
+ {
+ return IsSet(path.Split('.'));
+ }
+
+ public override bool IsSet(params string[] paths)
+ {
+ var path = string.Join(".", paths).ToLower();
+
+ if (_cache.TryGetValue(path, out var isSet))
+ {
+ return isSet;
+ }
+
+ isSet = TryGetFullPath(JsonObject, paths, 0, out var _);
+
+ _cache[path] = isSet;
+
+ if (isSet && paths.Length > 1)
+ {
+ for (var i = 1; i < paths.Length; i++)
+ {
+ path = string.Join(".", paths.Take(i)).ToLower();
+
+ _cache[path] = true;
+ }
+ }
+
+ return isSet;
+ }
+
+ ///
+ /// Get the value if set, if not get the default value
+ ///
+ /// Type of the return value
+ /// Value path
+ /// Default value. This is returned in case if the searched field was not found
+ /// If the field has a populated value, it returns the field and if not, returns the default value
+ public R GetIfSet(Expression> path, R defaultValue = default)
+ {
+ return IsSet(path) ? path.Compile()(Instance) : defaultValue;
+ }
+
+ public PartialJsonObject Add(Expression> expPath)
+ {
+ var path = GetMemberPath(expPath).ToLower();
+
+ _cache.Remove(path);
+ _cache.Add(path, true);
+
+ return this;
+ }
+
+ public PartialJsonObject Remove(Expression> expPath)
+ {
+ var path = GetMemberPath(expPath).ToLower();
+
+ _cache.Remove(path);
+ _cache.Add(path, false);
+
+ return this;
+ }
+
+ public string GetJSONPath(Expression> expPath)
+ {
+ var paths = ExpressionToPathParser.ParseExpressionToPaths(expPath.Body).ToArray();
+
+ return GetJSONPath(paths);
+ }
+
+ public string GetJSONPath(params string[] paths)
+ {
+ if (TryGetFullPath(JsonObject, paths, 0, out var fullPath))
+ {
+ return fullPath;
+ }
+
+ return string.Join(".", paths);
+ }
+
+ public void ClearCache() => _cache.Clear();
+
+ public void CopyTo(T obj)
+ {
+ JsonConvert.PopulateObject(JsonObject.ToString(), obj);
+ }
+
+ public T ToObject()
+ {
+ return JsonObject.ToObject();
+ }
+
+ public static implicit operator T(PartialJsonObject partialJsonObject)
+ => partialJsonObject.Instance;
+
+ public static string GetMemberPath(Expression> expPath)
+ {
+ return string.Join(".", ExpressionToPathParser.ParseExpressionToPaths(expPath.Body));
+ }
+
+ private static bool TryGetFullPath(JToken token, string[] paths, int pathIndex, out string fullPath)
+ {
+ var path = paths[pathIndex];
+ if (token is JArray array)
+ {
+ int arrayIndex;
+
+ if (path == "$last")
+ arrayIndex = array.Count - 1;
+ else if (!int.TryParse(path, out arrayIndex))
+ arrayIndex = -1;
+
+ if (arrayIndex >= 0 &&
+ arrayIndex < array.Count)
+ {
+ pathIndex++;
+ if (pathIndex < paths.Length)
+ {
+ return TryGetFullPath(array[arrayIndex], paths, pathIndex, out fullPath);
+ }
+
+ fullPath = $"{token.Path}[{arrayIndex}]";
+ return true;
+ }
+ }
+ else if (token is JObject obj)
+ {
+ var val = obj.GetValue(path, StringComparison.OrdinalIgnoreCase);
+
+ if (val != null)
+ {
+ pathIndex++;
+ if (pathIndex < paths.Length)
+ {
+ return TryGetFullPath(val, paths, pathIndex, out fullPath);
+ }
+
+ fullPath = val.Path;
+ return true;
+ }
+ }
+
+ fullPath = null;
+ return false;
+ }
+ }
+
+ public abstract class PartialJsonObject
+ {
+ [JsonIgnore]
+ public JObject JsonObject { get; internal set; }
+
+ public abstract bool IsSet(string path);
+
+ public abstract bool IsSet(params string[] paths);
+ }
+
+ internal class ExpressionToPathParser
+ {
+ internal static IEnumerable ParseExpressionToPaths(Expression expressionBody)
+ {
+ if (expressionBody is MethodCallExpression methodExpr)
+ {
+ foreach (var p in ParseMethodCallExpressionToPaths(methodExpr))
+ yield return p;
+ }
+ else if (expressionBody is BinaryExpression binaryExpr &&
+ binaryExpr.NodeType == ExpressionType.ArrayIndex)
+ {
+ foreach (var p in ParseExpressionToPaths(binaryExpr.Left))
+ yield return p;
+
+ yield return GetExpressionCompiledValue(binaryExpr.Right).ToString();
+ }
+ else if (expressionBody is MemberExpression propExpr)
+ {
+ foreach (var p in ParseExpressionToPaths(propExpr.Expression))
+ yield return p;
+
+ yield return propExpr.Member.Name;
+ }
+ }
+
+ internal static IEnumerable ParseMethodCallExpressionToPaths(MethodCallExpression expression)
+ {
+ if (expression.Method.DeclaringType == typeof(Enumerable) &&
+ (expression.Method.Name == nameof(Enumerable.ElementAt) ||
+ expression.Method.Name == nameof(Enumerable.ElementAtOrDefault) ||
+ (expression.Method.Name == nameof(Enumerable.First) && expression.Arguments.Count == 1) ||
+ (expression.Method.Name == nameof(Enumerable.FirstOrDefault) && expression.Arguments.Count == 1) ||
+ (expression.Method.Name == nameof(Enumerable.Last) && expression.Arguments.Count == 1) ||
+ (expression.Method.Name == nameof(Enumerable.LastOrDefault) && expression.Arguments.Count == 1)))
+ {
+ foreach (var p in ParseExpressionToPaths(expression.Arguments[0]))
+ yield return p;
+
+ if (expression.Method.Name == nameof(Enumerable.First) ||
+ expression.Method.Name == nameof(Enumerable.FirstOrDefault))
+ yield return "0";
+ else if (expression.Method.Name == nameof(Enumerable.Last) ||
+ expression.Method.Name == nameof(Enumerable.LastOrDefault))
+ yield return "$last";
+ else
+ yield return GetExpressionCompiledValue(expression.Arguments[1]).ToString();
+ }
+ else if (expression.Method.DeclaringType.IsGenericType &&
+ expression.Method.DeclaringType == typeof(List<>).MakeGenericType(expression.Method.DeclaringType.GenericTypeArguments[0]) &&
+ expression.Method.Name == "get_Item")
+ {
+ foreach (var p in ParseExpressionToPaths(expression.Object))
+ yield return p;
+
+ yield return GetExpressionCompiledValue(expression.Arguments[0]).ToString();
+ }
+ }
+
+ private static object GetExpressionCompiledValue(Expression expression)
+ {
+ if (expression is ConstantExpression constExpr)
+ return constExpr.Value;
+ else
+ return Expression.Lambda(expression).Compile().DynamicInvoke();
+ }
+ }
+
+ internal class PartialJsonObjectConverter : JsonConverter
+ {
+ public override bool CanConvert(Type objectType) => typeof(PartialJsonObject).IsAssignableFrom(objectType);
+
+ public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
+ {
+ var obj = JObject.Load(reader);
+
+ return Activator.CreateInstance(objectType, obj);
+ }
+
+ public override bool CanWrite => false;
+
+ public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
+ }
+}
diff --git a/AspNetCore.RestFramework.Core/Serializer/JsonTransform.cs b/src/AspNetCore.RestFramework.Core/Serializer/JsonTransform.cs
similarity index 100%
rename from AspNetCore.RestFramework.Core/Serializer/JsonTransform.cs
rename to src/AspNetCore.RestFramework.Core/Serializer/JsonTransform.cs
diff --git a/AspNetCore.RestFramework.Core/Serializer/Serializer.cs b/src/AspNetCore.RestFramework.Core/Serializer/Serializer.cs
similarity index 97%
rename from AspNetCore.RestFramework.Core/Serializer/Serializer.cs
rename to src/AspNetCore.RestFramework.Core/Serializer/Serializer.cs
index c33c26c..83c2838 100644
--- a/AspNetCore.RestFramework.Core/Serializer/Serializer.cs
+++ b/src/AspNetCore.RestFramework.Core/Serializer/Serializer.cs
@@ -1,11 +1,11 @@
-using JSM.PartialJsonObject;
-using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AspNetCore.RestFramework.Core.Base;
+using AspNetCore.RestFramework.Core.Helpers;
namespace AspNetCore.RestFramework.Core.Serializer
{
@@ -35,7 +35,7 @@ public Serializer(TContext applicationDbContext)
query = query.Skip(skip * pageSize).Take(pageSize);
var data = await query.ToListAsync();
-
+
return (total, data);
}
@@ -84,10 +84,10 @@ public virtual async Task PutAsync(TOrigin origin, TPrimaryKey ent
return null;
var stringDeserialized = JsonConvert.SerializeObject(origin);
-
+
dynamic stringDeserializedDynamic = JsonConvert.DeserializeObject(stringDeserialized);
stringDeserializedDynamic.Id = entityId;
-
+
JsonConvert.PopulateObject(stringDeserializedDynamic.ToString(), destinationObject);
_dbContext.Update(destinationObject);
await _dbContext.SaveChangesAsync();
@@ -117,7 +117,7 @@ public virtual async Task> PutManyAsync(TOrigin origin, IList
public virtual async Task DeleteAsync(TPrimaryKey entityId)
{
var data = await GetFromDB(entityId);
-
+
if (data == null)
return null;
@@ -136,7 +136,7 @@ public virtual async Task> DeleteManyAsync(IList
return deletedObjects.Select(m => m.Id).ToList();
}
-
+
public async Task GetFromDB(TPrimaryKey id, IQueryable query)
{
var key = id.ToString();
diff --git a/src/AspNetCore.RestFramework.Core/packages.lock.json b/src/AspNetCore.RestFramework.Core/packages.lock.json
new file mode 100644
index 0000000..203b468
--- /dev/null
+++ b/src/AspNetCore.RestFramework.Core/packages.lock.json
@@ -0,0 +1,819 @@
+{
+ "version": 1,
+ "dependencies": {
+ "net8.0": {
+ "Microsoft.AspNetCore.Http.Abstractions": {
+ "type": "Direct",
+ "requested": "[2.*, )",
+ "resolved": "2.2.0",
+ "contentHash": "Nxs7Z1q3f1STfLYKJSVXCs1iBl+Ya6E8o4Oy1bCxJ/rNI44E/0f6tbsrVqAWfB7jlnJfyaAtIalBVxPKUPQb4Q==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Features": "2.2.0",
+ "System.Text.Encodings.Web": "4.5.0"
+ }
+ },
+ "Microsoft.AspNetCore.Mvc.Core": {
+ "type": "Direct",
+ "requested": "[2.*, )",
+ "resolved": "2.2.5",
+ "contentHash": "/8sr8ixIUD57UFwUntha9bOwex7/AkZfdk1f9oNJG1Ek7p/uuKVa7fuHmYZpQOf35Oxrt+2Ku4WPwMSbNxOuWg==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Authentication.Core": "2.2.0",
+ "Microsoft.AspNetCore.Authorization.Policy": "2.2.0",
+ "Microsoft.AspNetCore.Hosting.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.Http": "2.2.0",
+ "Microsoft.AspNetCore.Http.Extensions": "2.2.0",
+ "Microsoft.AspNetCore.Mvc.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.ResponseCaching.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.Routing": "2.2.0",
+ "Microsoft.AspNetCore.Routing.Abstractions": "2.2.0",
+ "Microsoft.Extensions.DependencyInjection": "2.2.0",
+ "Microsoft.Extensions.DependencyModel": "2.1.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.2.0",
+ "System.Diagnostics.DiagnosticSource": "4.5.0",
+ "System.Threading.Tasks.Extensions": "4.5.1"
+ }
+ },
+ "Microsoft.EntityFrameworkCore": {
+ "type": "Direct",
+ "requested": "[8.*, )",
+ "resolved": "8.0.8",
+ "contentHash": "iK+jrJzkfbIxutB7or808BPmJtjUEi5O+eSM7cLDwsyde6+3iOujCSfWnrHrLxY3u+EQrJD+aD8DJ6ogPA2Rtw==",
+ "dependencies": {
+ "Microsoft.EntityFrameworkCore.Abstractions": "8.0.8",
+ "Microsoft.EntityFrameworkCore.Analyzers": "8.0.8",
+ "Microsoft.Extensions.Caching.Memory": "8.0.0",
+ "Microsoft.Extensions.Logging": "8.0.0"
+ }
+ },
+ "Microsoft.AspNetCore.Authentication.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "VloMLDJMf3n/9ic5lCBOa42IBYJgyB1JhzLsL68Zqg+2bEPWfGBj/xCJy/LrKTArN0coOcZp3wyVTZlx0y9pHQ==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Options": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Authentication.Core": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "XlVJzJ5wPOYW+Y0J6Q/LVTEyfS4ssLXmt60T0SPP+D8abVhBTl+cgw2gDHlyKYIkcJg7btMVh383NDkMVqD/fg==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Authentication.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.Http": "2.2.0",
+ "Microsoft.AspNetCore.Http.Extensions": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Authorization": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "/L0W8H3jMYWyaeA9gBJqS/tSWBegP9aaTM0mjRhxTttBY9z4RVDRYJ2CwPAmAXIuPr3r1sOw+CS8jFVRGHRezQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Logging.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Options": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Authorization.Policy": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "aJCo6niDRKuNg2uS2WMEmhJTooQUGARhV2ENQ2tO5443zVHUo19MSgrgGo9FIrfD+4yKPF8Q+FF33WkWfPbyKw==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Authentication.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.Authorization": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Hosting.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "ubycklv+ZY7Kutdwuy1W4upWcZ6VFR8WUXU7l7B2+mvbDBBPAcfpi+E+Y5GFe+Q157YfA3C49D2GCjAZc7Mobw==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Hosting.Server.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.Http.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Hosting.Abstractions": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Hosting.Server.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "1PMijw8RMtuQF60SsD/JlKtVfvh4NORAhF4wjysdABhlhTrYmtgssqyncR0Stq5vqtjplZcj6kbT4LRTglt9IQ==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Features": "2.2.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Http": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "YogBSMotWPAS/X5967pZ+yyWPQkThxhmzAwyCHCSSldzYBkW5W5d6oPfBaPqQOnSHYTpSOSOkpZoAce0vwb6+A==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Abstractions": "2.2.0",
+ "Microsoft.AspNetCore.WebUtilities": "2.2.0",
+ "Microsoft.Extensions.ObjectPool": "2.2.0",
+ "Microsoft.Extensions.Options": "2.2.0",
+ "Microsoft.Net.Http.Headers": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Http.Extensions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "2DgZ9rWrJtuR7RYiew01nGRzuQBDaGHGmK56Rk54vsLLsCdzuFUPqbDTJCS1qJQWTbmbIQ9wGIOjpxA1t0l7/w==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Abstractions": "2.2.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0",
+ "Microsoft.Net.Http.Headers": "2.2.0",
+ "System.Buffers": "4.5.0"
+ }
+ },
+ "Microsoft.AspNetCore.Http.Features": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "ziFz5zH8f33En4dX81LW84I6XrYXKf9jg6aM39cM+LffN9KJahViKZ61dGMSO2gd3e+qe5yBRwsesvyqlZaSMg==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Mvc.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "ET6uZpfVbGR1NjCuLaLy197cQ3qZUjzl7EG5SL4GfJH/c9KRE89MMBrQegqWsh0w1iRUB/zQaK0anAjxa/pz4g==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Routing.Abstractions": "2.2.0",
+ "Microsoft.Net.Http.Headers": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.ResponseCaching.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "CIHWEKrHzZfFp7t57UXsueiSA/raku56TgRYauV/W1+KAQq6vevz60zjEKaazt3BI76zwMz3B4jGWnCwd8kwQw==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Routing": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "jAhDBy0wryOnMhhZTtT9z63gJbvCzFuLm8yC6pHzuVu9ZD1dzg0ltxIwT4cfwuNkIL/TixdKsm3vpVOpG8euWQ==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Extensions": "2.2.0",
+ "Microsoft.AspNetCore.Routing.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.2.0",
+ "Microsoft.Extensions.ObjectPool": "2.2.0",
+ "Microsoft.Extensions.Options": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.Routing.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "lRRaPN7jDlUCVCp9i0W+PB0trFaKB0bgMJD7hEJS9Uo4R9MXaMC8X2tJhPLmeVE3SGDdYI4QNKdVmhNvMJGgPQ==",
+ "dependencies": {
+ "Microsoft.AspNetCore.Http.Abstractions": "2.2.0"
+ }
+ },
+ "Microsoft.AspNetCore.WebUtilities": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "9ErxAAKaDzxXASB/b5uLEkLgUWv1QbeVxyJYEHQwMaxXOeFFVkQxiq8RyfVcifLU7NR0QY0p3acqx4ZpYfhHDg==",
+ "dependencies": {
+ "Microsoft.Net.Http.Headers": "2.2.0",
+ "System.Text.Encodings.Web": "4.5.0"
+ }
+ },
+ "Microsoft.CSharp": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "17h8b5mXa87XYKrrVqdgZ38JefSUqLChUQpXgSnpzsM0nDOhE40FTeNWOJ/YmySGV6tG6T8+hjz6vxbknHJr6A==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Dynamic.Runtime": "4.0.11",
+ "System.Globalization": "4.0.11",
+ "System.Linq": "4.1.0",
+ "System.Linq.Expressions": "4.1.0",
+ "System.ObjectModel": "4.0.12",
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Extensions": "4.0.1",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Reflection.TypeExtensions": "4.1.0",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Runtime.InteropServices": "4.1.0",
+ "System.Threading": "4.0.11"
+ }
+ },
+ "Microsoft.DotNet.PlatformAbstractions": {
+ "type": "Transitive",
+ "resolved": "2.1.0",
+ "contentHash": "9KPDwvb/hLEVXYruVHVZ8BkebC8j17DmPb56LnqRF74HqSPLjCkrlFUjOtFpQPA2DeADBRTI/e69aCfRBfrhxw==",
+ "dependencies": {
+ "System.AppContext": "4.1.0",
+ "System.Collections": "4.0.11",
+ "System.IO": "4.1.0",
+ "System.IO.FileSystem": "4.0.1",
+ "System.Reflection.TypeExtensions": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Runtime.InteropServices": "4.1.0",
+ "System.Runtime.InteropServices.RuntimeInformation": "4.0.0"
+ }
+ },
+ "Microsoft.EntityFrameworkCore.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.8",
+ "contentHash": "9mMQkZsfL1c2iifBD8MWRmwy59rvsVtR9NOezJj7+g1j4P7g49MJHd8k8faC/v7d5KuHkQ6KOQiSItvoRt9PXA=="
+ },
+ "Microsoft.EntityFrameworkCore.Analyzers": {
+ "type": "Transitive",
+ "resolved": "8.0.8",
+ "contentHash": "OlAXMU+VQgLz5y5/SBkLvAa9VeiR3dlJqgIebEEH2M2NGA3evm68/Tv7SLWmSxwnEAtA3nmDEZF2pacK6eXh4Q=="
+ },
+ "Microsoft.Extensions.Caching.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "3KuSxeHoNYdxVYfg2IRZCThcrlJ1XJqIXkAWikCsbm5C/bCjv7G0WoKDyuR98Q+T607QT2Zl5GsbGRkENcV2yQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Caching.Memory": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "7pqivmrZDzo1ADPkRwjy+8jtRKWRCPag9qPI+p7sgu7Q4QreWhcvbiWXsbhP+yY8XSiDvZpu2/LWdBv7PnmOpQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Caching.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Options": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "2.2.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "V8S3bsm50ig6JSyrbcJJ8bW2b9QLGouz+G1miK3UTaOWmMtFwNNNzUf4AleyDWUmTrWMLNnFSLEQtxmxgNQnNQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
+ },
+ "Microsoft.Extensions.DependencyModel": {
+ "type": "Transitive",
+ "resolved": "2.1.0",
+ "contentHash": "nS2XKqi+1A1umnYNLX2Fbm/XnzCxs5i+zXVJ3VC6r9t2z0NZr9FLnJN4VQpKigdcWH/iFTbMuX6M6WQJcTjVIg==",
+ "dependencies": {
+ "Microsoft.DotNet.PlatformAbstractions": "2.1.0",
+ "Newtonsoft.Json": "9.0.1",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Dynamic.Runtime": "4.0.11",
+ "System.Linq": "4.1.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "EcnaSsPTqx2MGnHrmWOD0ugbuuqVT8iICqSqPzi45V5/MA1LjUNb0kwgcxBGqizV1R+WeBK7/Gw25Jzkyk9bIw==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "2.2.0"
+ }
+ },
+ "Microsoft.Extensions.Hosting.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "+k4AEn68HOJat5gj1TWa6X28WlirNQO9sPIIeQbia+91n03esEtMSSoekSTpMjUzjqtJWQN3McVx0GvSPFHF/Q==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "2.2.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "2.2.0",
+ "Microsoft.Extensions.Logging.Abstractions": "2.2.0"
+ }
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "tvRkov9tAJ3xP51LCv3FJ2zINmv1P8Hi8lhhtcKGqM+ImiTCC84uOPEI4z8Cdq2C3o9e+Aa0Gw0rmrsJD77W+w==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "8.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Options": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.ObjectPool": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "gA8H7uQOnM5gb+L0uTNjViHYr+hRDqCdfugheGo/MxQnuHzmhhzCBTIPm19qL1z1Xe0NEMabfcOBGv9QghlZ8g=="
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "JOVOfqpnqlVLUzINQ2fox8evY2SKLYJ3BV8QDe/Jyp21u1T7r45x/R/5QdteURMR5r01GxeJSBBUOCOyaNXA3g==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
+ },
+ "Microsoft.Net.Http.Headers": {
+ "type": "Transitive",
+ "resolved": "2.2.0",
+ "contentHash": "iZNkjYqlo8sIOI0bQfpsSoMTmB/kyvmV2h225ihyZT33aTp48ZpF6qYnXxzSXmHt8DpBAwBTX+1s1UFLbYfZKg==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "2.2.0",
+ "System.Buffers": "4.5.0"
+ }
+ },
+ "Microsoft.NETCore.Platforms": {
+ "type": "Transitive",
+ "resolved": "1.0.1",
+ "contentHash": "2G6OjjJzwBfNOO8myRV/nFrbTw5iA+DEm0N+qUqhrOmaVtn4pC77h38I1jsXGw5VH55+dPfQsqHD0We9sCl9FQ=="
+ },
+ "Microsoft.NETCore.Targets": {
+ "type": "Transitive",
+ "resolved": "1.0.1",
+ "contentHash": "rkn+fKobF/cbWfnnfBOQHKVKIOpxMZBvlSHkqDWgBpwGDcLRduvs3D9OLGeV6GWGvVwNlVi2CBbTjuPmtHvyNw=="
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "9.0.1",
+ "contentHash": "U82mHQSKaIk+lpSVCbWYKNavmNH1i5xrExDEquU1i6I5pV6UMOqRnJRSlKO3cMPfcpp0RgDY+8jUXHdQ4IfXvw==",
+ "dependencies": {
+ "Microsoft.CSharp": "4.0.1",
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Dynamic.Runtime": "4.0.11",
+ "System.Globalization": "4.0.11",
+ "System.IO": "4.1.0",
+ "System.Linq": "4.1.0",
+ "System.Linq.Expressions": "4.1.0",
+ "System.ObjectModel": "4.0.12",
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Extensions": "4.0.1",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Runtime.Serialization.Primitives": "4.1.1",
+ "System.Text.Encoding": "4.0.11",
+ "System.Text.Encoding.Extensions": "4.0.11",
+ "System.Text.RegularExpressions": "4.1.0",
+ "System.Threading": "4.0.11",
+ "System.Threading.Tasks": "4.0.11",
+ "System.Xml.ReaderWriter": "4.0.11",
+ "System.Xml.XDocument": "4.0.11"
+ }
+ },
+ "runtime.native.System": {
+ "type": "Transitive",
+ "resolved": "4.0.0",
+ "contentHash": "QfS/nQI7k/BLgmLrw7qm7YBoULEvgWnPI+cYsbfCVFTW8Aj+i8JhccxcFMu1RWms0YZzF+UHguNBK4Qn89e2Sg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1"
+ }
+ },
+ "System.AppContext": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "3QjO4jNV7PdKkmQAVp9atA+usVnKRwI3Kx1nMwJ93T0LcQfx7pKAYk0nKz5wn1oP5iqlhZuy6RXOFdhr7rDwow==",
+ "dependencies": {
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "pL2ChpaRRWI/p4LXyy4RgeWlYF2sgfj/pnVMvBqwNFr5cXg7CXNnWZWxrOONLg8VGdFB8oB+EG2Qw4MLgTOe+A=="
+ },
+ "System.Collections": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "YUJGz6eFKqS0V//mLt25vFGrrCvOnsXjlvFQs+KimpwNxug9x0Pzy4PlFMU3Q2IzqAa9G2L4LsK3+9vCBK7oTg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Diagnostics.Debug": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "w5U95fVKHY4G8ASs/K5iK3J5LY+/dLFd4vKejsnI/ZhBsWS9hQakfx3Zr7lRWKg4tAw9r4iktyvsTagWkqYCiw==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "eIHRELiYDQvsMToML81QFkXEEYXUSUT2F28t1SGrevWqP+epFdw80SyAXIKTXOHrIEXReFOEnEr7XlGiC2GgOg=="
+ },
+ "System.Diagnostics.Tools": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "xBfJ8pnd4C17dWaC9FM6aShzbJcRNMChUMD42I6772KGGrqaFdumwhn9OdM68erj1ueNo3xdQ1EwiFjK5k8p0g==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Dynamic.Runtime": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "db34f6LHYM0U0JpE+sOmjar27BnqTVkbLJhgfwMpTdgTigG/Hna3m2MYVwnFzGGKnEJk2UXFuoVTr8WUbU91/A==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Globalization": "4.0.11",
+ "System.Linq": "4.1.0",
+ "System.Linq.Expressions": "4.1.0",
+ "System.ObjectModel": "4.0.12",
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Emit": "4.0.1",
+ "System.Reflection.Emit.ILGeneration": "4.0.1",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Reflection.TypeExtensions": "4.1.0",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Threading": "4.0.11"
+ }
+ },
+ "System.Globalization": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "B95h0YLEL2oSnwF/XjqSWKnwKOy/01VWkNlsCeMTFJLLabflpGV26nK164eRs5GiaRSBGpOxQ3pKoSnnyZN5pg==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.IO": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "3KlTJceQc3gnGIaHZ7UBZO26SHL1SHE4ddrmiwumFnId+CEHP+O8r386tZKaE6zlk5/mF8vifMBzHj9SaXN+mQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Text.Encoding": "4.0.11",
+ "System.Threading.Tasks": "4.0.11"
+ }
+ },
+ "System.IO.FileSystem": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "IBErlVq5jOggAD69bg1t0pJcHaDbJbWNUZTPI96fkYWzwYbN6D9wRHMULLDd9dHsl7C2YsxXL31LMfPI1SWt8w==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.IO": "4.1.0",
+ "System.IO.FileSystem.Primitives": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Handles": "4.0.1",
+ "System.Text.Encoding": "4.0.11",
+ "System.Threading.Tasks": "4.0.11"
+ }
+ },
+ "System.IO.FileSystem.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "kWkKD203JJKxJeE74p8aF8y4Qc9r9WQx4C0cHzHPrY3fv/L/IhWnyCHaFJ3H1QPOH6A93whlQ2vG5nHlBDvzWQ==",
+ "dependencies": {
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Linq": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "bQ0iYFOQI0nuTnt+NQADns6ucV4DUvMdwN6CbkB1yj8i7arTGiTN5eok1kQwdnnNWSDZfIUySQY+J3d5KjWn0g==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0"
+ }
+ },
+ "System.Linq.Expressions": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "I+y02iqkgmCAyfbqOmSDOgqdZQ5tTj80Akm5BPSS8EeB0VGWdy6X1KCoYe8Pk6pwDoAKZUOdLVxnTJcExiv5zw==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Globalization": "4.0.11",
+ "System.IO": "4.1.0",
+ "System.Linq": "4.1.0",
+ "System.ObjectModel": "4.0.12",
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Emit": "4.0.1",
+ "System.Reflection.Emit.ILGeneration": "4.0.1",
+ "System.Reflection.Emit.Lightweight": "4.0.1",
+ "System.Reflection.Extensions": "4.0.1",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Reflection.TypeExtensions": "4.1.0",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Threading": "4.0.11"
+ }
+ },
+ "System.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "4.0.12",
+ "contentHash": "tAgJM1xt3ytyMoW4qn4wIqgJYm7L7TShRZG4+Q4Qsi2PCcj96pXN7nRywS9KkB3p/xDUjc2HSwP9SROyPYDYKQ==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Threading": "4.0.11"
+ }
+ },
+ "System.Reflection": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "JCKANJ0TI7kzoQzuwB/OoJANy1Lg338B6+JVacPl4TpUwi3cReg3nMLplMq2uqYfHFQpKIlHAUVAJlImZz/4ng==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.IO": "4.1.0",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Reflection.Emit": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "P2wqAj72fFjpP6wb9nSfDqNBMab+2ovzSDzUZK7MVIm54tBJEPr9jWfSjjoTpPwj1LeKcmX3vr0ttyjSSFM47g==",
+ "dependencies": {
+ "System.IO": "4.1.0",
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Emit.ILGeneration": "4.0.1",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Reflection.Emit.ILGeneration": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "Ov6dU8Bu15Bc7zuqttgHF12J5lwSWyTf1S+FJouUXVMSqImLZzYaQ+vRr1rQ0OZ0HqsrwWl4dsKHELckQkVpgA==",
+ "dependencies": {
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Reflection.Emit.Lightweight": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "sSzHHXueZ5Uh0OLpUQprhr+ZYJrLPA2Cmr4gn0wj9+FftNKXx8RIMKvO9qnjk2ebPYUjZ+F2ulGdPOsvj+MEjA==",
+ "dependencies": {
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Emit.ILGeneration": "4.0.1",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Reflection.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "GYrtRsZcMuHF3sbmRHfMYpvxZoIN2bQGrYGerUiWLEkqdEUQZhH3TRSaC/oI4wO0II1RKBPlpIa1TOMxIcOOzQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Reflection": "4.1.0",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Reflection.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "4inTox4wTBaDhB7V3mPvp9XlCbeGYWVEM9/fXALd52vNEAVisc1BoVWQPuUuD0Ga//dNbA/WeMy9u9mzLxGTHQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Reflection.TypeExtensions": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "tsQ/ptQ3H5FYfON8lL4MxRk/8kFyE0A+tGPXmVP967cT/gzLHYxIejIYSxp4JmIeFHVP78g/F2FE1mUUTbDtrg==",
+ "dependencies": {
+ "System.Reflection": "4.1.0",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Resources.ResourceManager": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "TxwVeUNoTgUOdQ09gfTjvW411MF+w9MBYL7AtNVc+HtBCFlutPLhUCdZjNkjbhj3bNQWMdHboF0KIWEOjJssbA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Globalization": "4.0.11",
+ "System.Reflection": "4.1.0",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Runtime": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "v6c/4Yaa9uWsq+JMhnOFewrYkgdNHNG2eMKuNqRn8P733rNXeRCGvV5FkkjBXn2dbVkPXOsO0xjsEeM1q2zC0g==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1"
+ }
+ },
+ "System.Runtime.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "CUOHjTT/vgP0qGW22U4/hDlOqXmcPq5YicBaXdUR2UiUoLwBT+olO6we4DVbq57jeX5uXH2uerVZhf0qGj+sVQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Runtime.Handles": {
+ "type": "Transitive",
+ "resolved": "4.0.1",
+ "contentHash": "nCJvEKguXEvk2ymk1gqj625vVnlK3/xdGzx0vOKicQkoquaTBJTP13AIYkocSUwHCLNBwUbXTqTWGDxBTWpt7g==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Runtime.InteropServices": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "16eu3kjHS633yYdkjwShDHZLRNMKVi/s0bY8ODiqJ2RfMhDMAwxZaUaWVnZ2P71kr/or+X9o/xFWtNqz8ivieQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Reflection": "4.1.0",
+ "System.Reflection.Primitives": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Handles": "4.0.1"
+ }
+ },
+ "System.Runtime.InteropServices.RuntimeInformation": {
+ "type": "Transitive",
+ "resolved": "4.0.0",
+ "contentHash": "hWPhJxc453RCa8Z29O91EmfGeZIHX1ZH2A8L6lYQVSaKzku2DfArSfMEb1/MYYzPQRJZeu0c9dmYeJKxW5Fgng==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "System.Reflection": "4.1.0",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.InteropServices": "4.1.0",
+ "System.Threading": "4.0.11",
+ "runtime.native.System": "4.0.0"
+ }
+ },
+ "System.Runtime.Serialization.Primitives": {
+ "type": "Transitive",
+ "resolved": "4.1.1",
+ "contentHash": "HZ6Du5QrTG8MNJbf4e4qMO3JRAkIboGT5Fk804uZtg3Gq516S7hAqTm2UZKUHa7/6HUGdVy3AqMQKbns06G/cg==",
+ "dependencies": {
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Text.Encoding": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "U3gGeMlDZXxCEiY4DwVLSacg+DFWCvoiX+JThA/rvw37Sqrku7sEFeVBBBMBnfB6FeZHsyDx85HlKL19x0HtZA==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Text.Encoding.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "jtbiTDtvfLYgXn8PTfWI+SiBs51rrmO4AAckx4KR6vFK9Wzf6tI8kcRdsYQNwriUeQ1+CtQbM1W4cMbLXnj/OQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Text.Encoding": "4.0.11"
+ }
+ },
+ "System.Text.Encodings.Web": {
+ "type": "Transitive",
+ "resolved": "4.5.0",
+ "contentHash": "Xg4G4Indi4dqP1iuAiMSwpiWS54ZghzR644OtsRCm/m/lBMG8dUBhLVN7hLm8NNrNTR+iGbshCPTwrvxZPlm4g=="
+ },
+ "System.Text.RegularExpressions": {
+ "type": "Transitive",
+ "resolved": "4.1.0",
+ "contentHash": "i88YCXpRTjCnoSQZtdlHkAOx4KNNik4hMy83n0+Ftlb7jvV6ZiZWMpnEZHhjBp6hQVh8gWd/iKNPzlPF7iyA2g==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Globalization": "4.0.11",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Threading": "4.0.11"
+ }
+ },
+ "System.Threading": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "N+3xqIcg3VDKyjwwCGaZ9HawG9aC6cSDI+s7ROma310GQo8vilFZa86hqKppwTHleR/G0sfOzhvgnUxWCR/DrQ==",
+ "dependencies": {
+ "System.Runtime": "4.1.0",
+ "System.Threading.Tasks": "4.0.11"
+ }
+ },
+ "System.Threading.Tasks": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "k1S4Gc6IGwtHGT8188RSeGaX86Qw/wnrgNLshJvsdNUOPP9etMmo8S07c+UlOAx4K/xLuN9ivA1bD0LVurtIxQ==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.0.1",
+ "Microsoft.NETCore.Targets": "1.0.1",
+ "System.Runtime": "4.1.0"
+ }
+ },
+ "System.Threading.Tasks.Extensions": {
+ "type": "Transitive",
+ "resolved": "4.5.1",
+ "contentHash": "WSKUTtLhPR8gllzIWO2x6l4lmAIfbyMAiTlyXAis4QBDonXK4b4S6F8zGARX4/P8wH3DH+sLdhamCiHn+fTU1A=="
+ },
+ "System.Xml.ReaderWriter": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "ZIiLPsf67YZ9zgr31vzrFaYQqxRPX9cVHjtPSnmx4eN6lbS/yEyYNr2vs1doGDEscF0tjCZFsk9yUg1sC9e8tg==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Globalization": "4.0.11",
+ "System.IO": "4.1.0",
+ "System.IO.FileSystem": "4.0.1",
+ "System.IO.FileSystem.Primitives": "4.0.1",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Runtime.InteropServices": "4.1.0",
+ "System.Text.Encoding": "4.0.11",
+ "System.Text.Encoding.Extensions": "4.0.11",
+ "System.Text.RegularExpressions": "4.1.0",
+ "System.Threading.Tasks": "4.0.11",
+ "System.Threading.Tasks.Extensions": "4.0.0"
+ }
+ },
+ "System.Xml.XDocument": {
+ "type": "Transitive",
+ "resolved": "4.0.11",
+ "contentHash": "Mk2mKmPi0nWaoiYeotq1dgeNK1fqWh61+EK+w4Wu8SWuTYLzpUnschb59bJtGywaPq7SmTuPf44wrXRwbIrukg==",
+ "dependencies": {
+ "System.Collections": "4.0.11",
+ "System.Diagnostics.Debug": "4.0.11",
+ "System.Diagnostics.Tools": "4.0.1",
+ "System.Globalization": "4.0.11",
+ "System.IO": "4.1.0",
+ "System.Reflection": "4.1.0",
+ "System.Resources.ResourceManager": "4.0.1",
+ "System.Runtime": "4.1.0",
+ "System.Runtime.Extensions": "4.1.0",
+ "System.Text.Encoding": "4.0.11",
+ "System.Threading": "4.0.11",
+ "System.Xml.ReaderWriter": "4.0.11"
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/AspNetCore.RestFramework.Core.Test/AspNetCore.RestFramework.Core.Test.csproj b/tests/AspNetCore.RestFramework.Core.Test/AspNetCore.RestFramework.Core.Test.csproj
new file mode 100644
index 0000000..8294512
--- /dev/null
+++ b/tests/AspNetCore.RestFramework.Core.Test/AspNetCore.RestFramework.Core.Test.csproj
@@ -0,0 +1,31 @@
+
+
+
+ net8.0
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/tests/AspNetCore.RestFramework.Core.Test/Base/BaseControllerTests.cs b/tests/AspNetCore.RestFramework.Core.Test/Base/BaseControllerTests.cs
new file mode 100644
index 0000000..d0f0eb0
--- /dev/null
+++ b/tests/AspNetCore.RestFramework.Core.Test/Base/BaseControllerTests.cs
@@ -0,0 +1,1094 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+using System.Web;
+using AspNetCore.RestFramework.Core.Base;
+using AspNetCore.RestFramework.Core.Errors;
+using AspNetCore.RestFramework.Core.Test.Support;
+using FluentAssertions;
+using Microsoft.AspNetCore.Mvc.Testing;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using Newtonsoft.Json;
+using Xunit;
+
+namespace AspNetCore.RestFramework.Core.Test.Base;
+
+public class BaseControllerTests
+{
+ public class Delete : IntegrationTests
+ {
+ private readonly WebApplicationFactory _factory = new();
+
+ [Fact]
+ public async Task Delete_WithObject_ShouldDeleteEntityFromDatabaseAndReturnOk()
+ {
+ // Arrange
+ var client = _factory.CreateClient();
+ var context = _factory.Services.GetRequiredService();
+ var dbSet = context.Set();
+ var customer = new Customer() { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
+ dbSet.Add(customer);
+ await context.SaveChangesAsync();
+
+ // Act
+ var response = await client.DeleteAsync($"api/Customers/{customer.Id}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+ var updatedCustomer = dbSet.AsNoTracking().FirstOrDefault(x => x.Id == customer.Id);
+ updatedCustomer.Should().BeNull();
+ }
+
+ [Fact]
+ public async Task Delete_WhenEntityDoesntExist_ReturnsNotFound()
+ {
+ // Act
+ var response = await Client.DeleteAsync($"api/Customers/{Guid.NewGuid()}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.NotFound);
+ }
+
+ [Fact]
+ public async Task Delete_WhenEntityDoesntImplementGetFields_ReturnsBadRequest()
+ {
+ // Act
+ var response = await Client.DeleteAsync($"api/Sellers/{Guid.NewGuid()}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.BadRequest);
+ var responseData = await response.Content.ReadAsStringAsync();
+ var responseMessages = JsonConvert.DeserializeObject(responseData);
+
+ responseMessages.Error["msg"].Should().Be(BaseMessages.ERROR_GET_FIELDS);
+ }
+ }
+
+ public class DeleteMany : IntegrationTests
+ {
+ [Fact]
+ public async Task DeleteMany_ShouldDeleteManyEntities_AndReturnTheirIds()
+ {
+ // Arrange
+ var dbSet = Context.Set();
+ dbSet.Add(new Customer()
+ { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" });
+ var expectedToBeDeletedOne = Guid.NewGuid();
+ dbSet.Add(new Customer()
+ { Id = expectedToBeDeletedOne, CNPJ = "456", Name = "def" });
+ var expectedToBeDeletedTwo = Guid.NewGuid();
+ dbSet.Add(new Customer()
+ { Id = expectedToBeDeletedTwo, CNPJ = "789", Name = "ghi" });
+ await Context.SaveChangesAsync();
+ // Act
+ var url = $"api/Customers?ids={expectedToBeDeletedOne}&ids={expectedToBeDeletedTwo}";
+ var response = await Client.DeleteAsync(url);
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+ var deletedIds = JsonConvert.DeserializeObject>(await response.Content.ReadAsStringAsync());
+ var expectedGuids = new List { expectedToBeDeletedOne, expectedToBeDeletedTwo };
+ deletedIds.Should().BeEquivalentTo(expectedGuids);
+
+ var entitiesWithDeletedIds = dbSet.Where(m => expectedGuids.Contains(m.Id)).AsNoTracking();
+ entitiesWithDeletedIds.Should().BeEmpty();
+ }
+ }
+
+ public class GetSingle : IntegrationTests
+ {
+ [Fact]
+ public async Task GetSingle_WithValidParameter_ShouldReturn1Record()
+ {
+ // Arrange
+ var dbSet = Context.Set();
+ var customer1 = new Customer { Id = Guid.NewGuid(), CNPJ = "123", Name = "abc" };
+ var customer2 = new Customer { Id = Guid.NewGuid(), CNPJ = "456", Name = "def" };
+ var customer3 = new Customer { Id = Guid.NewGuid(), CNPJ = "789", Name = "ghi" };
+
+
+ dbSet.AddRange(customer1, customer2, customer3);
+ await Context.SaveChangesAsync();
+
+ // Act
+ var response = await Client.GetAsync($"api/Customers/{customer1.Id}");
+
+ // Assert
+ response.StatusCode.Should().Be(HttpStatusCode.OK);
+ var responseData = await response.Content.ReadAsStringAsync();
+ var customer = JsonConvert.DeserializeObject(responseData);
+ customer.Should().NotBeNull();
+ customer.Id.Should().Be(customer1.Id);
+ }
+
+ [Fact]
+ public async Task GetSingle_WithInValidParameter_ShouldReturn404()
+ {
+ // Arrange
+ var dbSet = Context.Set