Skip to content

Commit 8884f7d

Browse files
Merge pull request #142 from AntonioFalcao/release
updating
2 parents 30af862 + dd2781d commit 8884f7d

File tree

10 files changed

+138
-131
lines changed

10 files changed

+138
-131
lines changed

Directory.Build.props

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@
1010
<Microsoft_DependencyInjection_Version>5.0.0</Microsoft_DependencyInjection_Version>
1111

1212
<!--EF Core-->
13-
<Microsoft_EntityFrameworkCore_Version>5.0.2</Microsoft_EntityFrameworkCore_Version>
13+
<Microsoft_EntityFrameworkCore_Version>5.0.3</Microsoft_EntityFrameworkCore_Version>
1414

1515
<!--GraphQL-->
1616
<GraphQL_Server_Version>4.4.1</GraphQL_Server_Version>
1717
<GraphQL_Client_Version>3.2.1</GraphQL_Client_Version>
1818
<GraphQL_Version>3.3.2</GraphQL_Version>
1919

2020
<!--AutoMapper-->
21-
<AutoMapper_DependencyInjection_Version>8.1.0</AutoMapper_DependencyInjection_Version>
21+
<AutoMapper_DependencyInjection_Version>8.1.1</AutoMapper_DependencyInjection_Version>
2222
<AutoMapper_Version>10.1.1</AutoMapper_Version>
2323

2424
<!--Others-->

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Dotnet5.GraphQL3.WebApplication
22

3-
This project exemplify the implementation and **Dockerization** of a simple Razor Web MVC Core consuming a full **GraphQL 3** Web API, build in a **.NET 5** multi-layer project, considering development best practices, like **SOLID** and **DRY**, applying **Domain-Driven** concepts in a **Hexagonal Architecture**.
3+
This project exemplify the implementation and **dockerization** of a simple Razor Web MVC Core consuming a full **GraphQL 3** Web API, build in a **.NET 5** multi-layer project, considering development best practices, like **SOLID**, **KISS** and **DRY**, applying **Domain-Driven** concepts in a **Hexagonal Architecture**.
44

55
|WebAPI|
66
|:----:|

src/Dotnet5.GraphQL3.Domain.Abstractions/Extensions/DependencyInjection/ServiceCollectionExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ public static IServiceCollection AddBuilders(this IServiceCollection services)
1313
.FromApplicationDependencies(assembly
1414
=> assembly.FullName?.StartsWith(assembly.GetEntryAssemblySuffix()) ?? default)
1515
.AddClasses(filter
16-
=> filter.AssignableToAny(typeof(IBuilder<,>)))
16+
=> filter.AssignableTo(typeof(IBuilder<,>)))
1717
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
1818
.AsImplementedInterfaces()
1919
.WithScopedLifetime());
Lines changed: 23 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,24 @@
1-
using Dotnet5.GraphQL3.CrossCutting.Extensions;
2-
using Dotnet5.GraphQL3.Repositories.Abstractions.UnitsOfWork;
3-
using Microsoft.Extensions.DependencyInjection;
4-
using Scrutor;
5-
6-
namespace Dotnet5.GraphQL3.Repositories.Abstractions.Extensions.DependencyInjection
7-
{
8-
public static class ServiceCollectionExtensions
9-
{
10-
public static IServiceCollection AddRepositories(this IServiceCollection services)
11-
=> services.Scan(selector
12-
=> selector
13-
.FromApplicationDependencies(assembly
14-
=> assembly.FullName?.StartsWith(assembly.GetEntryAssemblySuffix()) ?? default)
15-
.AddClasses(filter
16-
=> filter.AssignableToAny(typeof(IRepository<,>)))
17-
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
18-
.AsImplementedInterfaces()
19-
.WithScopedLifetime());
20-
21-
public static IServiceCollection AddUnitOfWork(this IServiceCollection services)
22-
=> services.AddScoped<IUnitOfWork, UnitOfWork>();
23-
}
1+
using Dotnet5.GraphQL3.CrossCutting.Extensions;
2+
using Dotnet5.GraphQL3.Repositories.Abstractions.UnitsOfWork;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Scrutor;
5+
6+
namespace Dotnet5.GraphQL3.Repositories.Abstractions.Extensions.DependencyInjection
7+
{
8+
public static class ServiceCollectionExtensions
9+
{
10+
public static IServiceCollection AddRepositories(this IServiceCollection services)
11+
=> services.Scan(selector
12+
=> selector
13+
.FromApplicationDependencies(assembly
14+
=> assembly.FullName?.StartsWith(assembly.GetEntryAssemblySuffix()) ?? default)
15+
.AddClasses(filter
16+
=> filter.AssignableTo(typeof(IRepository<,>)))
17+
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
18+
.AsImplementedInterfaces()
19+
.WithScopedLifetime());
20+
21+
public static IServiceCollection AddUnitOfWork(this IServiceCollection services)
22+
=> services.AddScoped<IUnitOfWork, UnitOfWork>();
23+
}
2424
}

src/Dotnet5.GraphQL3.Services.Abstractions/Extensions/DependencyInjection/ServiceCollectionExtensions.cs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -12,35 +12,31 @@ namespace Dotnet5.GraphQL3.Services.Abstractions.Extensions.DependencyInjection
1212
public static class ServiceCollectionExtensions
1313
{
1414
public static IServiceCollection AddApplicationServices(this IServiceCollection services)
15-
=> services.Scan(selector
16-
=> selector
17-
.FromApplicationDependencies(assembly
18-
=> assembly.FullName?.StartsWith(GetAssemblySuffix()) ?? default)
19-
.AddClasses(filter
20-
=> filter.AssignableToAny(typeof(IService<,,>)))
21-
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
22-
.AsImplementedInterfaces()
23-
.WithScopedLifetime());
15+
=> services.Scan(selector
16+
=> selector.FromApplicationDependencies(assembly
17+
=> assembly.FullName?.StartsWith(GetAssemblySuffix()) ?? default)
18+
.AddClasses(filter
19+
=> filter.AssignableTo(typeof(IService<,,>)))
20+
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
21+
.AsImplementedInterfaces()
22+
.WithScopedLifetime());
2423

2524
public static IServiceCollection AddMessageServices(this IServiceCollection services)
26-
=> services.Scan(selector
27-
=> selector
28-
.FromApplicationDependencies(assembly
29-
=> assembly.FullName?.StartsWith(GetAssemblySuffix()) ?? default)
30-
.AddClasses(filter
31-
=> filter.AssignableToAny(typeof(IMessageService<,,>)))
32-
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
33-
.AsImplementedInterfaces()
34-
.WithSingletonLifetime());
25+
=> services.Scan(selector
26+
=> selector.FromApplicationDependencies(assembly
27+
=> assembly.FullName?.StartsWith(GetAssemblySuffix()) ?? default)
28+
.AddClasses(filter
29+
=> filter.AssignableTo(typeof(IMessageService<,,>)))
30+
.UsingRegistrationStrategy(RegistrationStrategy.Skip)
31+
.AsImplementedInterfaces()
32+
.WithSingletonLifetime());
3533

3634
public static IServiceCollection AddSubjects(this IServiceCollection services)
3735
=> services.AddSingleton(typeof(ISubject<>), typeof(ReplaySubject<>));
3836

3937
public static IServiceCollection AddAutoMapper(this IServiceCollection services)
40-
=> services.AddAutoMapper(
41-
AppDomain.CurrentDomain.GetAssemblies()
42-
.Where(x => x.FullName?
43-
.Contains(GetAssemblySuffix()) ?? false));
38+
=> services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies().Where(x
39+
=> x.FullName?.Contains(GetAssemblySuffix()) ?? default));
4440

4541
private static string GetAssemblySuffix()
4642
=> Assembly.GetEntryAssembly()?.FullName?.Substring(0, 16);

src/Dotnet5.GraphQL3.Store.Repositories/Dotnet5.GraphQL3.Store.Repositories.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<ItemGroup>
4-
<PackageReference Include="Bogus" Version="32.1.1" />
4+
<PackageReference Include="Bogus" Version="33.0.1" />
55
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="$(Microsoft_EntityFrameworkCore_Version)" />
66
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="$(Microsoft_EntityFrameworkCore_Version)" />
77
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="$(Microsoft_EntityFrameworkCore_Version)" />
Lines changed: 69 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,70 @@
1-
using System;
2-
using Dotnet5.GraphQL3.Store.Repositories.Contexts;
3-
using Microsoft.EntityFrameworkCore;
4-
using Microsoft.EntityFrameworkCore.Infrastructure;
5-
using Microsoft.Extensions.DependencyInjection;
6-
7-
namespace Dotnet5.GraphQL3.Store.Repositories.Extensions.DependencyInjection
8-
{
9-
public static class ServiceCollectionExtensions
10-
{
11-
private static readonly RepositoryOptions Options = new();
12-
13-
public static IServiceCollection AddApplicationDbContext(this IServiceCollection services, Action<RepositoryOptions> optionsAction)
14-
{
15-
optionsAction(Options);
16-
17-
return services
18-
.AddScoped<DbContext, StoreDbContext>()
19-
.AddDbContext<StoreDbContext>(DbContextOptionsBuilderAction);
20-
}
21-
22-
private static void DbContextOptionsBuilderAction(DbContextOptionsBuilder optionsBuilder)
23-
=> optionsBuilder
24-
.EnableDetailedErrors()
25-
.EnableSensitiveDataLogging()
26-
.UseSqlServer(
27-
connectionString: Options.ConnectionString,
28-
sqlServerOptionsAction: SqlServerOptionsAction);
29-
30-
private static void SqlServerOptionsAction(SqlServerDbContextOptionsBuilder optionsBuilder)
31-
=> optionsBuilder
32-
.EnableRetryOnFailure(
33-
maxRetryCount: Options.ResilientConnection.MaxRetryCount,
34-
maxRetryDelay: Options.ResilientConnection.MaxRetryDelay,
35-
errorNumbersToAdd: Options.ResilientConnection.ErrorNumbersToAdd)
36-
.MigrationsAssembly(typeof(StoreDbContext).Assembly.GetName().Name);
37-
}
38-
39-
public class DatabaseResilientConnection
40-
{
41-
private const int DefaultMaxRetryCount = 5;
42-
private const int DefaultMaxRetryDelay = 5;
43-
44-
private int _maxRetryCount;
45-
private int _maxSecondsRetryDelay;
46-
47-
public int MaxRetryCount
48-
{
49-
get => _maxRetryCount;
50-
set => _maxRetryCount = value is default(int) ? DefaultMaxRetryCount : value;
51-
}
52-
53-
public int MaxSecondsRetryDelay
54-
{
55-
get => _maxSecondsRetryDelay;
56-
set => _maxSecondsRetryDelay = value is default(int) ? DefaultMaxRetryDelay : value;
57-
}
58-
59-
public int[] ErrorNumbersToAdd { get; set; }
60-
61-
internal TimeSpan MaxRetryDelay
62-
=> TimeSpan.FromSeconds(MaxSecondsRetryDelay);
63-
}
64-
65-
public class RepositoryOptions
66-
{
67-
public string ConnectionString { get; set; }
68-
public DatabaseResilientConnection ResilientConnection { get; set; } = new();
69-
}
1+
using System;
2+
using Dotnet5.GraphQL3.Store.Repositories.Contexts;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.EntityFrameworkCore.Infrastructure;
5+
using Microsoft.Extensions.DependencyInjection;
6+
7+
namespace Dotnet5.GraphQL3.Store.Repositories.Extensions.DependencyInjection
8+
{
9+
public static class ServiceCollectionExtensions
10+
{
11+
private static readonly RepositoryOptions Options = new();
12+
13+
public static IServiceCollection AddApplicationDbContext(this IServiceCollection services, Action<RepositoryOptions> optionsAction)
14+
{
15+
optionsAction(Options);
16+
17+
return services
18+
.AddScoped<DbContext, StoreDbContext>()
19+
.AddDbContext<StoreDbContext>(DbContextOptionsBuilderAction);
20+
}
21+
22+
private static void DbContextOptionsBuilderAction(DbContextOptionsBuilder optionsBuilder)
23+
=> optionsBuilder
24+
.EnableDetailedErrors()
25+
.EnableSensitiveDataLogging()
26+
.UseSqlServer(
27+
connectionString: Options.DefaultConnection,
28+
sqlServerOptionsAction: SqlServerOptionsAction);
29+
30+
private static void SqlServerOptionsAction(SqlServerDbContextOptionsBuilder optionsBuilder)
31+
=> optionsBuilder
32+
.EnableRetryOnFailure(
33+
maxRetryCount: Options.ConnectionResiliency.MaxRetryCount,
34+
maxRetryDelay: Options.ConnectionResiliency.MaxRetryDelay,
35+
errorNumbersToAdd: Options.ConnectionResiliency.ErrorNumbersToAdd)
36+
.MigrationsAssembly(typeof(StoreDbContext).Assembly.GetName().Name);
37+
}
38+
39+
public class ConnectionResiliency
40+
{
41+
private const int DefaultMaxRetryCount = 5;
42+
private const int DefaultMaxRetryDelay = 5;
43+
44+
private int _maxRetryCount;
45+
private int _maxSecondsRetryDelay;
46+
47+
public int MaxRetryCount
48+
{
49+
get => _maxRetryCount;
50+
set => _maxRetryCount = value is default(int) ? DefaultMaxRetryCount : value;
51+
}
52+
53+
public int MaxSecondsRetryDelay
54+
{
55+
get => _maxSecondsRetryDelay;
56+
set => _maxSecondsRetryDelay = value is default(int) ? DefaultMaxRetryDelay : value;
57+
}
58+
59+
public int[] ErrorNumbersToAdd { get; set; }
60+
61+
internal TimeSpan MaxRetryDelay
62+
=> TimeSpan.FromSeconds(MaxSecondsRetryDelay);
63+
}
64+
65+
public class RepositoryOptions
66+
{
67+
public string DefaultConnection { get; set; }
68+
public ConnectionResiliency ConnectionResiliency { get; set; } = new();
69+
}
7070
}
Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
using System.Threading.Tasks;
12
using Microsoft.AspNetCore.Hosting;
3+
using Microsoft.EntityFrameworkCore;
4+
using Microsoft.Extensions.DependencyInjection;
25
using Microsoft.Extensions.Hosting;
36

47
namespace Dotnet5.GraphQL3.Store.WebAPI
@@ -7,10 +10,20 @@ public static class Program
710
{
811
private static IHostBuilder CreateHostBuilder(string[] args)
912
=> Host.CreateDefaultBuilder(args)
10-
.ConfigureWebHostDefaults(webBuilder
11-
=> webBuilder.UseStartup<Startup>());
13+
.ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup<Startup>())
14+
.UseDefaultServiceProvider((context, options) =>
15+
{
16+
options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
17+
options.ValidateOnBuild = true;
18+
});
1219

13-
public static void Main(string[] args)
14-
=> CreateHostBuilder(args).Build().Run();
20+
public static async Task Main(string[] args)
21+
{
22+
var host = CreateHostBuilder(args).Build();
23+
using var scope = host.Services.CreateScope();
24+
var dbContext = scope.ServiceProvider.GetRequiredService<DbContext>();
25+
await dbContext.Database.MigrateAsync();
26+
await host.RunAsync();
27+
}
1528
}
1629
}

src/Dotnet5.GraphQL3.Store.WebAPI/Startup.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public Startup(IConfiguration configuration, IWebHostEnvironment env)
2828
_configuration = configuration;
2929
}
3030

31-
public void Configure(IApplicationBuilder app, DbContext dbContext)
31+
public void Configure(IApplicationBuilder app)
3232
{
3333
if (_env.IsDevelopment())
3434
app.UseDeveloperExceptionPage();
@@ -42,8 +42,6 @@ public void Configure(IApplicationBuilder app, DbContext dbContext)
4242
});
4343

4444
app.UseApplicationGraphQL<StoreSchema>();
45-
46-
dbContext.Database.Migrate();
4745
}
4846

4947
public void ConfigureServices(IServiceCollection services)
@@ -62,8 +60,8 @@ public void ConfigureServices(IServiceCollection services)
6260

6361
services.AddApplicationDbContext(options =>
6462
{
65-
options.ConnectionString = _configuration.GetConnectionString("DefaultConnection");
66-
_configuration.Bind("DatabaseResilientConnection", options.ResilientConnection);
63+
options.DefaultConnection = _configuration.GetConnectionString(nameof(options.DefaultConnection));
64+
_configuration.Bind(nameof(options.ConnectionResiliency), options.ConnectionResiliency);
6765
});
6866

6967
services.AddApplicationGraphQL(options

src/Dotnet5.GraphQL3.Store.WebAPI/appsettings.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,9 @@
22
"ConnectionStrings": {
33
"DefaultConnection": "Server=mssql;Database=Store;User=sa;Password=!MyComplexPassword"
44
},
5-
"DatabaseResilientConnection": {
6-
"MaxRetryCount": 5,
7-
"MaxRetryDelay": 5,
5+
"ConnectionResiliency": {
6+
"MaxRetryCount": 10,
7+
"MaxSecondsRetryDelay": 10,
88
"ErrorNumbersToAdd": []
99
},
1010
"Logging": {

0 commit comments

Comments
 (0)