Skip to content

Commit

Permalink
Merge pull request #33 from AngeloDotNet/develop
Browse files Browse the repository at this point in the history
Sync Main from Develop
  • Loading branch information
AngeloDotNet authored Nov 18, 2024
2 parents 6dca614 + c9c5494 commit ac3e95d
Show file tree
Hide file tree
Showing 5 changed files with 234 additions and 2 deletions.
27 changes: 26 additions & 1 deletion src/GSWCloudApp.Common/Extensions/ApplicationExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
using GSWCloudApp.Common.Options;
using Asp.Versioning;
using GSWCloudApp.Common.Options;
using GSWCloudApp.Common.Vault.Options;
using GSWCloudApp.Common.Vault.Service;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.HttpOverrides;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.Hosting;

namespace GSWCloudApp.Common.Extensions;

public static class ApplicationExtensions
{
public static async Task<string> GetVaultStringConnectionAsync(WebApplicationBuilder builder, string vaultPath, string vaultKey)
{
var vaultOptions = builder.Services.ConfigureAndGet<VaultOptions>(builder.Configuration, nameof(VaultOptions))
?? throw new InvalidOperationException("Vault options not found.");

return await VaultService.ReadVaultSecretAsync(vaultOptions, vaultPath, vaultKey);
}

public static RouteGroupBuilder UseVersioningApi(WebApplication app)
{
var apiVersionSet = app.NewApiVersionSet()
.HasApiVersion(new ApiVersion(1))
.Build();

var versionedApi = app
.MapGroup("/api/v{version:apiVersion}")
.WithApiVersionSet(apiVersionSet);

return versionedApi;
}

public static void UseDevSwagger(this WebApplication app, ApplicationOptions options)
{
if (app.Environment.IsDevelopment() || options.SwaggerEnable)
Expand Down
137 changes: 137 additions & 0 deletions src/GSWCloudApp.Common/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
using Asp.Versioning;
using AutoMapper;
using FluentValidation;
using GSWCloudApp.Common.Options;
using GSWCloudApp.Common.RedisCache;
using GSWCloudApp.Common.RedisCache.Options;
using GSWCloudApp.Common.Service;
using GSWCloudApp.Common.Swagger;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Routing;
using Microsoft.AspNetCore.Server.Kestrel.Core;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace GSWCloudApp.Common.Extensions;

public static class ServiceExtensions
{
public static IServiceCollection ConfigureDbContextAsync<T, TDbContext>(this IServiceCollection services, string databaseConnection,
ApplicationOptions applicationOptions) where T : class
where TDbContext : DbContext
{
var assembly = typeof(T).Assembly.GetName().Name!.ToString();
var AssemblyMigrazioni = string.Concat(assembly, ".Migrations");

services.AddDbContext<TDbContext>(optionsBuilder =>
{
optionsBuilder.UseNpgsql(databaseConnection, options =>
{
options.MigrationsAssembly(AssemblyMigrazioni)
.MigrationsHistoryTable(applicationOptions.TabellaMigrazioni)
.UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)
.EnableRetryOnFailure(3, TimeSpan.FromSeconds(5), null);
});
});

return services;
}

public static IServiceCollection ConfigureCors(this IServiceCollection services, string policyName)
{
return services.AddCors(options =>
{
options.AddPolicy(policyName, builder
=> builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
});
}

public static IServiceCollection ConfigureApiVersioning(this IServiceCollection services)
{
services.AddApiVersioning(options =>
{
options.ApiVersionReader = new UrlSegmentApiVersionReader();
options.DefaultApiVersion = new ApiVersion(1);
options.AssumeDefaultVersionWhenUnspecified = true;
options.ReportApiVersions = true;
})
.AddApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = true;
});

return services;
}

public static IServiceCollection ConfigureSwagger(this IServiceCollection services)
{
return services
.AddEndpointsApiExplorer()
.AddSwaggerGen(options =>
{
options.EnableAnnotations();
options.OperationFilter<SwaggerDefaultValues>();
})
.ConfigureOptions<ConfigureSwaggerGenOptions>();
}

public static IServiceCollection ConfigureProblemDetails(this IServiceCollection services)
{
return services.AddProblemDetails(options =>
{
options.CustomizeProblemDetails = context =>
{
context.ProblemDetails.Instance = $"{context.HttpContext.Request.Method} {context.HttpContext.Request.Path}";
var activity = context.HttpContext.Features.Get<IHttpActivityFeature>()?.Activity;
context.ProblemDetails.Extensions.TryAdd("traceId", activity?.Id);
//context.ProblemDetails.Extensions.TryAdd("requestId", context.HttpContext.TraceIdentifier);
};
});
}

public static IServiceCollection ConfigureRedisCache(this IServiceCollection services, IConfiguration configuration, string redisConnection)
{
var options = services.ConfigureAndGet<RedisOptions>(configuration, nameof(RedisOptions))
?? throw new InvalidOperationException("Redis options not found in configuration.");

options.Hostname = redisConnection;

return services.AddStackExchangeRedisCache(action =>
{
action.Configuration = options.Hostname;
action.InstanceName = options.InstanceName;
});
}

public static IServiceCollection ConfigureServices<TDbContext, TMappingProfile, TValidator>(this IServiceCollection services)
where TDbContext : DbContext
where TMappingProfile : Profile
where TValidator : IValidator
{
services.AddAntiforgery();
services.AddAutoMapper(typeof(TMappingProfile).Assembly);
services.AddValidatorsFromAssemblyContaining<TValidator>();

// Service Registrations with Singleton Lifecycle
services.AddSingleton<ICacheService, CacheService>();

// Service Registrations with Transient Lifecycle
services.AddTransient<IGenericService, GenericService>();

// Service Registrations with Singleton Lifecycle
services.AddScoped<DbContext, TDbContext>();

return services;
}

public static IServiceCollection ConfigureOptions(this IServiceCollection services, IConfiguration configuration)
{
services.Configure<RouteOptions>(options => options.LowercaseUrls = true);
services.Configure<KestrelServerOptions>(configuration.GetSection("Kestrel"));

return services;
}
}
8 changes: 7 additions & 1 deletion src/GSWCloudApp.Common/GSWCloudApp.Common.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@
<ItemGroup>
<PackageReference Include="Asp.Versioning.Mvc.ApiExplorer" Version="8.1.0" />
<PackageReference Include="AutoMapper" Version="13.0.1" />
<PackageReference Include="FluentValidation" Version="11.11.0" />
<!--<PackageReference Include="FluentValidation" Version="11.11.0" />-->
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.11.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.11" />
<PackageReference Include="Microsoft.EntityFrameworkCore.InMemory" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.Caching.StackExchangeRedis" Version="8.0.11" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
<PackageReference Include="Nerdbank.GitVersioning" Version="3.6.146">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Npgsql.EntityFrameworkCore.PostgreSQL" Version="8.0.11" />
<PackageReference Include="StackExchange.Redis" Version="2.8.16" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="7.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore.Annotations" Version="7.0.0" />
<PackageReference Include="VaultSharp" Version="1.17.5.1" />
</ItemGroup>

Expand Down
52 changes: 52 additions & 0 deletions src/GSWCloudApp.Common/Helpers/ApplicationHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.Extensions.DependencyInjection;

namespace GSWCloudApp.Common.Helpers;

public static class ApplicationHelpers
{
public static async Task ConfigureDatabaseAsync<TDbContext>(IServiceProvider serviceProvider) where TDbContext : DbContext
{
using var scope = serviceProvider.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<TDbContext>();

if (!dbContext.Database.IsInMemory())
{
await EnsureDatabaseAsync();
await RunMigrationsAsync();
}
else
{
dbContext.Database.EnsureCreated();
}

async Task EnsureDatabaseAsync()
{
var dbCreator = dbContext.GetService<IRelationalDatabaseCreator>();
var strategy = dbContext.Database.CreateExecutionStrategy();

await strategy.ExecuteAsync(async () =>
{
if (!await dbCreator.ExistsAsync())
{
await dbCreator.CreateAsync();
}
});
}

async Task RunMigrationsAsync()
{
var strategy = dbContext.Database.CreateExecutionStrategy();

await strategy.ExecuteAsync(async () =>
{
await using var transaction = await dbContext.Database.BeginTransactionAsync();
await dbContext.Database.MigrateAsync();
await transaction.CommitAsync();
});
}
}
}
12 changes: 12 additions & 0 deletions src/GSWCloudApp.Common/Helpers/DatabaseHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using Microsoft.EntityFrameworkCore.Migrations;

namespace GSWCloudApp.Common.Helpers;

public static class DatabaseHelpers
{
public static void ExecuteSQLScriptFromAssembly(this MigrationBuilder migrationBuilder, string assetName)
{
var sqlFile = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SQLScripts", assetName);
migrationBuilder.Sql(File.ReadAllText(sqlFile));
}
}

0 comments on commit ac3e95d

Please sign in to comment.