Skip to content

Commit

Permalink
Added sample applications. (#347)
Browse files Browse the repository at this point in the history
  • Loading branch information
fiseni authored Jul 21, 2023
1 parent c8c5a87 commit 60d3239
Show file tree
Hide file tree
Showing 64 changed files with 870 additions and 1,206 deletions.
42 changes: 21 additions & 21 deletions Ardalis.Specification.sln
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31612.314
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.SampleApp.Core", "sample\Ardalis.SampleApp.Core\Ardalis.SampleApp.Core.csproj", "{CAAAD1EF-5375-4B71-92CB-237692D60262}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.SampleApp.Web", "sample\Ardalis.SampleApp.Web\Ardalis.SampleApp.Web.csproj", "{EB3F4056-691C-4D22-903B-A2467D93D552}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.SampleApp.Infrastructure", "sample\Ardalis.SampleApp.Infrastructure\Ardalis.SampleApp.Infrastructure.csproj", "{C2EC4331-4C8A-4121-A68C-4C96A7D40A98}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification", "Specification\src\Ardalis.Specification\Ardalis.Specification.csproj", "{5FF21FE4-19B9-4BD2-958D-EAFEDE72D7F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Specification.UnitTests", "Specification\tests\Ardalis.Specification.UnitTests\Ardalis.Specification.UnitTests.csproj", "{85D42214-D223-4F13-9A19-9CFA0D3C1981}"
Expand Down Expand Up @@ -45,24 +39,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specification.EntityFramewo
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Specification.EntityFramework6", "Specification.EntityFramework6", "{327AEBD6-C8A6-4851-BA42-632F8014CFC5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Sample.Domain", "sample\Ardalis.Sample.Domain\Ardalis.Sample.Domain.csproj", "{4386E123-F4CA-4607-BD8F-8EB11D92458C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Sample.App1", "sample\Ardalis.Sample.App1\Ardalis.Sample.App1.csproj", "{EBABFB82-50D0-41A2-AEAC-F0E2C103ED08}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Ardalis.Sample.App2", "sample\Ardalis.Sample.App2\Ardalis.Sample.App2.csproj", "{ECBFDD7F-E60F-48C4-8279-DD6B3B03D27A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CAAAD1EF-5375-4B71-92CB-237692D60262}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CAAAD1EF-5375-4B71-92CB-237692D60262}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CAAAD1EF-5375-4B71-92CB-237692D60262}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CAAAD1EF-5375-4B71-92CB-237692D60262}.Release|Any CPU.Build.0 = Release|Any CPU
{EB3F4056-691C-4D22-903B-A2467D93D552}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB3F4056-691C-4D22-903B-A2467D93D552}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB3F4056-691C-4D22-903B-A2467D93D552}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB3F4056-691C-4D22-903B-A2467D93D552}.Release|Any CPU.Build.0 = Release|Any CPU
{C2EC4331-4C8A-4121-A68C-4C96A7D40A98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2EC4331-4C8A-4121-A68C-4C96A7D40A98}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2EC4331-4C8A-4121-A68C-4C96A7D40A98}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2EC4331-4C8A-4121-A68C-4C96A7D40A98}.Release|Any CPU.Build.0 = Release|Any CPU
{5FF21FE4-19B9-4BD2-958D-EAFEDE72D7F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5FF21FE4-19B9-4BD2-958D-EAFEDE72D7F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5FF21FE4-19B9-4BD2-958D-EAFEDE72D7F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -87,20 +75,32 @@ Global
{4BEB4DC4-DE33-4DF1-8A2F-CE76C1D72A4A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4BEB4DC4-DE33-4DF1-8A2F-CE76C1D72A4A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4BEB4DC4-DE33-4DF1-8A2F-CE76C1D72A4A}.Release|Any CPU.Build.0 = Release|Any CPU
{4386E123-F4CA-4607-BD8F-8EB11D92458C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4386E123-F4CA-4607-BD8F-8EB11D92458C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4386E123-F4CA-4607-BD8F-8EB11D92458C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4386E123-F4CA-4607-BD8F-8EB11D92458C}.Release|Any CPU.Build.0 = Release|Any CPU
{EBABFB82-50D0-41A2-AEAC-F0E2C103ED08}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EBABFB82-50D0-41A2-AEAC-F0E2C103ED08}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EBABFB82-50D0-41A2-AEAC-F0E2C103ED08}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EBABFB82-50D0-41A2-AEAC-F0E2C103ED08}.Release|Any CPU.Build.0 = Release|Any CPU
{ECBFDD7F-E60F-48C4-8279-DD6B3B03D27A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{ECBFDD7F-E60F-48C4-8279-DD6B3B03D27A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ECBFDD7F-E60F-48C4-8279-DD6B3B03D27A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ECBFDD7F-E60F-48C4-8279-DD6B3B03D27A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CAAAD1EF-5375-4B71-92CB-237692D60262} = {1FCFDF4F-D0E2-4E30-8ABC-FE6DC3628228}
{EB3F4056-691C-4D22-903B-A2467D93D552} = {1FCFDF4F-D0E2-4E30-8ABC-FE6DC3628228}
{C2EC4331-4C8A-4121-A68C-4C96A7D40A98} = {1FCFDF4F-D0E2-4E30-8ABC-FE6DC3628228}
{5FF21FE4-19B9-4BD2-958D-EAFEDE72D7F8} = {9CA909ED-E3A6-4D76-A4F3-250E93942813}
{85D42214-D223-4F13-9A19-9CFA0D3C1981} = {9CA909ED-E3A6-4D76-A4F3-250E93942813}
{5EB4ADA4-5258-4964-BD7D-11D4F926E344} = {B19F2F64-4B22-48C2-B2F8-7672F84F758D}
{5AFD1454-E625-451D-A615-CEB7BB09AA65} = {B19F2F64-4B22-48C2-B2F8-7672F84F758D}
{37EC09C7-702D-4539-B98D-F67B15E1E6CE} = {327AEBD6-C8A6-4851-BA42-632F8014CFC5}
{4BEB4DC4-DE33-4DF1-8A2F-CE76C1D72A4A} = {327AEBD6-C8A6-4851-BA42-632F8014CFC5}
{4386E123-F4CA-4607-BD8F-8EB11D92458C} = {1FCFDF4F-D0E2-4E30-8ABC-FE6DC3628228}
{EBABFB82-50D0-41A2-AEAC-F0E2C103ED08} = {1FCFDF4F-D0E2-4E30-8ABC-FE6DC3628228}
{ECBFDD7F-E60F-48C4-8279-DD6B3B03D27A} = {1FCFDF4F-D0E2-4E30-8ABC-FE6DC3628228}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C153A625-42F7-49A7-B99A-6A78B4B866B2}
Expand Down
22 changes: 22 additions & 0 deletions sample/Ardalis.Sample.App1/Ardalis.Sample.App1.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.9" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Specification.EntityFrameworkCore\src\Ardalis.Specification.EntityFrameworkCore\Ardalis.Specification.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\Ardalis.Sample.Domain\Ardalis.Sample.Domain.csproj" />
</ItemGroup>

</Project>
145 changes: 145 additions & 0 deletions sample/Ardalis.Sample.App1/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
using Ardalis.Sample.Domain;
using Ardalis.Sample.Domain.Specs;
using Ardalis.Specification;
using Ardalis.Specification.EntityFrameworkCore;
using AutoMapper;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DbConnection");
builder.Services.AddDbContext<AppDbContext>(options => options.UseSqlServer(connectionString));
builder.Services.AddScoped(typeof(IRepository<>), typeof(Repository<>));
builder.Services.AddScoped(typeof(IReadRepository<>), typeof(ReadRepository<>));

builder.Services.AddAutoMapper(typeof(MappingProfile).Assembly);
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHttpsRedirection();


app.MapGet("/customers", async (IReadRepository<Customer> repo, IMapper mapper, CancellationToken cancellationToken) =>
{
var spec = new CustomerSpec();
var customers = await repo.ListAsync(spec, cancellationToken);
var customersDto = mapper.Map<List<CustomerDto>>(customers);
return Results.Ok(customersDto);
});

app.MapGet("/customers/{id}", async (IReadRepository<Customer> repo, IMapper mapper, int id, CancellationToken cancellationToken) =>
{
var spec = new CustomerByIdSpec(id);
var customer = await repo.FirstOrDefaultAsync(spec, cancellationToken);
if (customer is null) return Results.NotFound();
var customerDto = mapper.Map<CustomerDto>(customer);
return Results.Ok(customerDto);
});

app.MapPost("/customers", async (IRepository<Customer> repo, IMapper mapper, CustomerCreateDto customerCreateDto, CancellationToken cancellationToken) =>
{
var customer = new Customer
{
Name = customerCreateDto.Name,
Age = customerCreateDto.Age,
Addresses = customerCreateDto.Addresses.Select(a => new Address { Street = a.Street }).ToList()
};
await repo.AddAsync(customer, cancellationToken);
var customerDto = mapper.Map<CustomerDto>(customer);
return Results.Ok(customerDto);
});

app.MapPut("/customers/{id}", async (IRepository<Customer> repo, IMapper mapper, int id, CustomerUpdateDto customerUpdate, CancellationToken cancellationToken) =>
{
var spec = new CustomerByIdSpec(id);
var customer = await repo.FirstOrDefaultAsync(spec, cancellationToken);
if (customer is null) return Results.NotFound();
customer.Name = customerUpdate.Name;
customer.Age = customerUpdate.Age;
await repo.UpdateAsync(customer, cancellationToken);
var customerDto = mapper.Map<CustomerDto>(customer);
return Results.Ok(customerDto);
});

await app.InitializeDbAsync();
app.Run();

public record AddressDto(int Id, string Street, int CustomerId);
public record AddressCreateDto(string Street);
public record CustomerDto(int Id, string Name, int Age, List<AddressDto> Addresses);
public record CustomerCreateDto(string Name, int Age, List<AddressCreateDto> Addresses);
public record CustomerUpdateDto(string Name, int Age);

public class AppDbContext : DbContext
{
public DbSet<Customer> Customers => Set<Customer>();
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
}

public interface IRepository<T> : IRepositoryBase<T> where T : class, IAggregateRoot
{
}
public interface IReadRepository<T> : IReadRepositoryBase<T> where T : class
{
}
public class Repository<T> : RepositoryBase<T>, IRepository<T> where T : class, IAggregateRoot
{
public Repository(AppDbContext dbContext) : base(dbContext)
{
}
}
public class ReadRepository<T> : RepositoryBase<T>, IReadRepository<T> where T : class
{
public ReadRepository(AppDbContext dbContext) : base(dbContext)
{
}
}

public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Address, AddressDto>();
CreateMap<Customer, CustomerDto>();
}
}

public static class WebApplicationExtensions
{
public static async Task InitializeDbAsync(this WebApplication app)
{
using var scope = app.Services.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<AppDbContext>();
await dbContext.Database.EnsureDeletedAsync();
await dbContext.Database.EnsureCreatedAsync();
var customers = new List<Customer>()
{
new()
{
Name = "Customer1",
Age = 20,
Addresses = new()
{
new() { Street = "Street1_1" },
new() { Street = "Street1_2" }
}
},
new()
{
Name = "Customer2",
Age = 30,
Addresses = new()
{
new() { Street = "Street2_1" },
new() { Street = "Street3_2" }
}
}
};
dbContext.Customers.AddRange(customers);
await dbContext.SaveChangesAsync();
}
}
8 changes: 8 additions & 0 deletions sample/Ardalis.Sample.App1/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
}
}
12 changes: 12 additions & 0 deletions sample/Ardalis.Sample.App1/appsettings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"ConnectionStrings": {
"DbConnection": "Server=(localdb)\\mssqllocaldb;Database=SpecificationSampleApp1;Trusted_Connection=True;TrustServerCertificate=Yes"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
13 changes: 13 additions & 0 deletions sample/Ardalis.Sample.App2/AppSpecificationEvaluator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
using Ardalis.Specification.EntityFrameworkCore;

namespace Ardalis.Sample.App2;

public class AppSpecificationEvaluator : SpecificationEvaluator
{
public static AppSpecificationEvaluator Instance { get; } = new AppSpecificationEvaluator();

public AppSpecificationEvaluator() : base()
{
Evaluators.Add(QueryTagEvaluator.Instance);
}
}
22 changes: 22 additions & 0 deletions sample/Ardalis.Sample.App2/Ardalis.Sample.App2.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="7.0.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="7.0.9" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\..\Specification.EntityFrameworkCore\src\Ardalis.Specification.EntityFrameworkCore\Ardalis.Specification.EntityFrameworkCore.csproj" />
<ProjectReference Include="..\Ardalis.Sample.Domain\Ardalis.Sample.Domain.csproj" />
</ItemGroup>

</Project>
24 changes: 24 additions & 0 deletions sample/Ardalis.Sample.App2/IReadRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using Ardalis.Sample.Domain.Filters;
using Ardalis.Specification;

namespace Ardalis.Sample.App2;

public interface IReadRepository<T> where T : class
{
Task<T?> FindAsync<TId>(TId id, CancellationToken cancellationToken = default) where TId : notnull;
Task<T?> FirstOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<TResult?> FirstOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);
Task<T?> SingleOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<TResult?> SingleOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);
Task<List<T>> ListAsync(CancellationToken cancellationToken = default);
Task<List<T>> ListAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<List<TResult>> ListAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);
Task<int> CountAsync(CancellationToken cancellationToken = default);
Task<int> CountAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<bool> AnyAsync(CancellationToken cancellationToken = default);
Task<bool> AnyAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);

Task<TResult?> ProjectToFirstOrDefaultAsync<TResult>(ISpecification<T> specification, CancellationToken cancellationToken);
Task<List<TResult>> ProjectToListAsync<TResult>(ISpecification<T> specification, CancellationToken cancellationToken);
Task<PagedResponse<TResult>> ProjectToListAsync<TResult>(ISpecification<T> specification, BaseFilter filter, CancellationToken cancellationToken);
}
27 changes: 27 additions & 0 deletions sample/Ardalis.Sample.App2/IRepository.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using Ardalis.Sample.Domain;
using Ardalis.Specification;

namespace Ardalis.Sample.App2;

public interface IRepository<T> where T : class, IAggregateRoot
{
Task<T> AddAsync(T entity, CancellationToken cancellationToken = default);
Task<IEnumerable<T>> AddRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);
Task UpdateAsync(T entity, CancellationToken cancellationToken = default);
Task DeleteAsync(T entity, CancellationToken cancellationToken = default);
Task DeleteRangeAsync(IEnumerable<T> entities, CancellationToken cancellationToken = default);
Task<int> SaveChangesAsync(CancellationToken cancellationToken = default);

Task<T?> FindAsync<TId>(TId id, CancellationToken cancellationToken = default) where TId : notnull;
Task<T?> FirstOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<TResult?> FirstOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);
Task<T?> SingleOrDefaultAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<TResult?> SingleOrDefaultAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);
Task<List<T>> ListAsync(CancellationToken cancellationToken = default);
Task<List<T>> ListAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<List<TResult>> ListAsync<TResult>(ISpecification<T, TResult> specification, CancellationToken cancellationToken = default);
Task<int> CountAsync(CancellationToken cancellationToken = default);
Task<int> CountAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
Task<bool> AnyAsync(CancellationToken cancellationToken = default);
Task<bool> AnyAsync(ISpecification<T> specification, CancellationToken cancellationToken = default);
}
14 changes: 14 additions & 0 deletions sample/Ardalis.Sample.App2/PagedResponse.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
namespace Ardalis.Sample.App2;

public class PagedResponse<T>
{
public Pagination Pagination { get; }
public List<T> Data { get; }

public PagedResponse(List<T> data, Pagination pagination)
{
Data = data;
Pagination = pagination;
}
}

Loading

0 comments on commit 60d3239

Please sign in to comment.