diff --git a/Src/4.EndPoints/WebApi.EndPoints/BaseWebApi/Controllers/BaseController.cs b/Src/4.EndPoints/WebApi.EndPoints/BaseWebApi/Controllers/BaseController.cs index 2f64565..f6c5b47 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/BaseWebApi/Controllers/BaseController.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/BaseWebApi/Controllers/BaseController.cs @@ -5,7 +5,7 @@ using MediatR; using Microsoft.AspNetCore.Mvc; using System.Net; -using WebApi.EndPoints.DIContainers; +using WebApi.EndPoints.HostExtensions.Providers.HttpAccessor; namespace WebApi.EndPoints.BaseWebApi.Controllers; @@ -128,4 +128,8 @@ protected async Task Get(TQuery query) where TQuer return BadRequest(result.Messages); } + protected async Task ReturnResponse(TModel model) + { + return await Task.FromResult(Ok(model)); + } } diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/CatalogItemController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/CatalogItemController.cs deleted file mode 100644 index c0ec8cf..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/Controllers/CatalogItemController.cs +++ /dev/null @@ -1,14 +0,0 @@ -using MediatR; -using Microsoft.AspNetCore.Mvc; -using WebApi.EndPoints.BaseWebApi.Controllers; - -namespace WebApi.EndPoints.Controllers; - -[ApiController] -[Route("[controller]")] -public class CatalogItemController : BaseController -{ - public CatalogItemController(IMediator mediator) : base(mediator) - { - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/HomeController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/HomeController.cs deleted file mode 100644 index 2e530b9..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/Controllers/HomeController.cs +++ /dev/null @@ -1,11 +0,0 @@ -using MediatR; -using WebApi.EndPoints.BaseWebApi.Controllers; - -namespace WebApi.EndPoints.Controllers; - -public class HomeController : BaseController -{ - public HomeController(IMediator mediator) : base(mediator) - { - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Account/AccountController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AccountController.cs similarity index 78% rename from Src/4.EndPoints/WebApi.EndPoints/Controllers/Account/AccountController.cs rename to Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AccountController.cs index 0b80db9..6a043d4 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Account/AccountController.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AccountController.cs @@ -1,11 +1,12 @@ using MediatR; using WebApi.EndPoints.BaseWebApi.Controllers; -namespace WebApi.EndPoints.Controllers.Account; +namespace WebApi.EndPoints.Controllers.Identity; public class AccountController : BaseController { public AccountController(IMediator mediator) : base(mediator) { } -} \ No newline at end of file +} + diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AuthenticateController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AuthenticateController.cs new file mode 100644 index 0000000..713bd27 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AuthenticateController.cs @@ -0,0 +1,15 @@ +using MediatR; +using Microsoft.AspNetCore.Mvc; +using WebApi.EndPoints.BaseWebApi.Controllers; +using WebApi.EndPoints.Models.Identity.Authenticate; + +namespace WebApi.EndPoints.Controllers.Identity; + +public class AuthenticateController : BaseController +{ + public AuthenticateController(IMediator mediator) : base(mediator) + { + } + +} + diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AuthorizationController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AuthorizationController.cs new file mode 100644 index 0000000..8e89a98 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Identity/AuthorizationController.cs @@ -0,0 +1,12 @@ +using MediatR; +using WebApi.EndPoints.BaseWebApi.Controllers; + +namespace WebApi.EndPoints.Controllers.Identity; + +public class AuthorizationController : BaseController +{ + public AuthorizationController(IMediator mediator) : base(mediator) + { + } +} + diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/PersonController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/PersonController.cs deleted file mode 100644 index 2d381e4..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/Controllers/PersonController.cs +++ /dev/null @@ -1,62 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Commands.ChangeName; -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Commands.ChangePassword; -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Commands.CreatePerson; -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Commands.DeletePerson; -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Commands.UpdatePerson; -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Queries.GetAllPerson; -using CleanArchitectureCQRS.Application.Library.Aggregates.People.Queries.GetById; -using MediatR; -using Microsoft.AspNetCore.Mvc; -using WebApi.EndPoints.BaseWebApi.Controllers; - -namespace WebApi.EndPoints.Controllers; - -public class PersonController : BaseController -{ - public PersonController(IMediator mediator) : base(mediator) - { - } - - [HttpPost] - public async Task Create(CreatePerson command) => await Create(command); - - [HttpDelete] - public async Task Delete(int id) - { - return Ok(await mediator.Send(new DeletePerson(id))); - } - [HttpPut] - public async Task Update(int id, UpdatePerson command) - { - if (id != command.Id) - { - return BadRequest(); - } - return Ok(await mediator.Send(command)); - } - [HttpPut("ChangeName")] - public async Task ChangeName(ChangeName command) - { - return Ok(await mediator.Send(command)); - } - - - [HttpGet("GetAll")] - public async Task GetAll() - { - return await Get>(new GetAllPerson()); - } - - - [HttpGet("GetById")] - public async Task GetById(GetPersonById getPerson) => await Get(getPerson); - - - [HttpPut("ChangePassword")] - public async Task ChangePassword(ChangePassword command) - { - return Ok(await mediator.Send(command)); - } - - -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Security/RoleController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Security/RoleController.cs deleted file mode 100644 index 8a7994c..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Security/RoleController.cs +++ /dev/null @@ -1,11 +0,0 @@ -using MediatR; -using WebApi.EndPoints.BaseWebApi.Controllers; - -namespace WebApi.EndPoints.Controllers.Security; - -public class RoleController : BaseController -{ - public RoleController(IMediator mediator) : base(mediator) - { - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Security/UserController.cs b/Src/4.EndPoints/WebApi.EndPoints/Controllers/Security/UserController.cs deleted file mode 100644 index 2ed4bfb..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/Controllers/Security/UserController.cs +++ /dev/null @@ -1,45 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.Aggregates.Users.Commands.CreateUser; -using CleanArchitectureCQRS.Application.Library.Aggregates.Users.Queires.GetAllUser; -using CleanArchitectureCQRS.Application.Library.Aggregates.Users.Queires.GetUserById; -using MediatR; -using Microsoft.AspNetCore.Mvc; -using System.Diagnostics; -using WebApi.EndPoints.BaseWebApi.Controllers; - -namespace WebApi.EndPoints.Controllers.Security; - -public class UserController : BaseController -{ - private readonly ILogger _logger; - private readonly Stopwatch _stopwatch; - public UserController(IMediator mediator, ILogger logger) : base(mediator) - { - _logger = logger; - _stopwatch = new Stopwatch(); - } - - [HttpPost] - public async Task Create(CreateUser command) - { - _stopwatch.Start(); - _logger.LogInformation($"=>Start Stopwatch{_stopwatch.ElapsedMilliseconds}"); - - for (int i = 1; i <= 1000; i++) - { - Console.ForegroundColor = ConsoleColor.Yellow; - _logger.LogInformation($"=> Start Handler{i} : Stopwatch{_stopwatch.ElapsedMilliseconds}"); - await Create(command); - _logger.LogInformation($"=> Start Handler{i} : Stopwatch{_stopwatch.ElapsedMilliseconds}"); - } - _stopwatch.Stop(); - _logger.LogInformation($"=>Stop Stopwatch{_stopwatch.ElapsedMilliseconds}"); - return Ok(); - } - - - [HttpGet("GetAll")] - public async Task GetAll() - { - return await Get>(new GetAllUsers()); - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddApplicationServicesExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddApplicationServicesExtensions.cs deleted file mode 100644 index 05beade..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddApplicationServicesExtensions.cs +++ /dev/null @@ -1,59 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.BaseApplication.ApplicationServices.Commands; -using CleanArchitectureCQRS.Application.Library.BaseApplication.ApplicationServices.Events; -using CleanArchitectureCQRS.Application.Library.BaseApplication.ApplicationServices.Queries; -using FluentValidation; -using System.Reflection; - -namespace WebApi.EndPoints.DIContainers; - -public static class AddApplicationServicesExtensions -{ - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddApplicationServices(this IServiceCollection services, - IEnumerable assembliesForSearch) - => services.AddCommandHandlers(assembliesForSearch) - .AddQueryHandlers(assembliesForSearch) - .AddEventHandlers(assembliesForSearch) - .AddFluentValidators(assembliesForSearch); - - /// - /// - /// - /// - /// - /// - private static IServiceCollection AddCommandHandlers(this IServiceCollection services, IEnumerable assembliesForSearch) - => services.AddWithTransientLifetime(assembliesForSearch, typeof(ICommandHandler<>), typeof(ICommandHandler<,>)); - - /// - /// - /// - /// - /// - /// - private static IServiceCollection AddQueryHandlers(this IServiceCollection services, IEnumerable assembliesForSearch) - => services.AddWithTransientLifetime(assembliesForSearch, typeof(IQueryHandler<,>)); - - /// - /// - /// - /// - /// - /// - private static IServiceCollection AddEventHandlers(this IServiceCollection services, IEnumerable assembliesForSearch) - => services.AddWithTransientLifetime(assembliesForSearch, typeof(IDomainEventHandler<>)); - - /// - /// - /// - /// - /// - /// - private static IServiceCollection AddFluentValidators(this IServiceCollection services, IEnumerable assembliesForSearch) - => services.AddValidatorsFromAssemblies(assembliesForSearch); -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddDataAccessExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddDataAccessExtensions.cs deleted file mode 100644 index 3ce25b7..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddDataAccessExtensions.cs +++ /dev/null @@ -1,48 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.BaseApplication.Contracts.Data.Commands; -using CleanArchitectureCQRS.Application.Library.BaseApplication.Contracts.Data.Queries; -using System.Reflection; - -namespace WebApi.EndPoints.DIContainers; - -/// -/// توابع کمکی جهت ثبت نیازمندی‌های لایه داده -/// -public static class AddDataAccessExtensions -{ - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddDataAccess( - this IServiceCollection services, - IEnumerable assembliesForSearch) => - services - .AddRepositories(assembliesForSearch) - .AddUnitOfWorks(assembliesForSearch); - - - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddRepositories(this IServiceCollection services, - IEnumerable assembliesForSearch) => - services.AddWithTransientLifetime(assembliesForSearch, typeof(ICommandRepository<,>), typeof(IQueryRepository)); - - - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddUnitOfWorks(this IServiceCollection services, - IEnumerable assembliesForSearch) => - services.AddWithTransientLifetime(assembliesForSearch, typeof(IUnitOfWork)); -} - - diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddServicesExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddServicesExtensions.cs deleted file mode 100644 index 334172d..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddServicesExtensions.cs +++ /dev/null @@ -1,13 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.BaseApplication.Utilities; - -namespace WebApi.EndPoints.DIContainers; - -public static class AddServicesExtensions -{ - public static IServiceCollection AddUntilityServices( - this IServiceCollection services) - { - services.AddTransient(); - return services; - } -} \ No newline at end of file diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/DependencyInjection.cs b/Src/4.EndPoints/WebApi.EndPoints/DIContainers/DependencyInjection.cs deleted file mode 100644 index ae680c8..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/DependencyInjection.cs +++ /dev/null @@ -1,133 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.BaseApplication.Contracts.Data.Transactions; -using Microsoft.Extensions.DependencyModel; -using System.Reflection; - -namespace WebApi.EndPoints.DIContainers; - -public static class DependencyInjection -{ - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddDependencies(this IServiceCollection services, - params string[] assemblyNamesForSearch) - { - - var assemblies = GetAssemblies(assemblyNamesForSearch); - services - .AddApplicationServices(assemblies) - .AddDataAccess(assemblies) - .AddUntilityServices() - .AddCustomeDepenecies(assemblies); - return services; - } - - - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddCustomeDepenecies(this IServiceCollection services, IEnumerable assemblies) - { - return services.AddWithTransientLifetime(assemblies, typeof(ITransientLifetime)) - .AddWithScopedLifetime(assemblies, typeof(IScopeLifetime)) - .AddWithSingletonLifetime(assemblies, typeof(ISingletoneLifetime)); - } - - /// - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddWithScopedLifetime(this IServiceCollection services, - IEnumerable assembliesForSearch, - params Type[] assignableTo) - { - services.Scan(s => s.FromAssemblies(assembliesForSearch) - .AddClasses(c => c.AssignableToAny(assignableTo)) - .AsImplementedInterfaces() - .WithScopedLifetime()); - return services; - } - - - /// - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddWithSingletonLifetime(this IServiceCollection services, - IEnumerable assembliesForSearch, - params Type[] assignableTo) - { - services.Scan(s => s.FromAssemblies(assembliesForSearch) - .AddClasses(c => c.AssignableToAny(assignableTo)) - .AsImplementedInterfaces() - .WithSingletonLifetime()); - return services; - } - - - - /// - /// - /// - /// - /// - /// - /// - public static IServiceCollection AddWithTransientLifetime(this IServiceCollection services, - IEnumerable assembliesForSearch, - params Type[] assignableTo) - { - services.Scan(s => s.FromAssemblies(assembliesForSearch) - .AddClasses(c => c.AssignableToAny(assignableTo)) - .AsImplementedInterfaces() - .WithTransientLifetime()); - return services; - } - /// - /// - /// - /// - /// - private static List GetAssemblies(string[] assmblyName) - { - - var assemblies = new List(); - var dependencies = DependencyContext.Default.RuntimeLibraries; - foreach (var library in dependencies) - { - if (IsCandidateCompilationLibrary(library, assmblyName)) - { - var assembly = Assembly.Load(new AssemblyName(library.Name)); - assemblies.Add(assembly); - } - } - return assemblies; - } - /// - /// - /// - /// - /// - /// - - private static bool IsCandidateCompilationLibrary(RuntimeLibrary compilationLibrary, string[] assmblyName) - { - return assmblyName.Any(d => compilationLibrary.Name.Contains(d)) - || compilationLibrary.Dependencies.Any(d => assmblyName.Any(c => d.Name.Contains(c))); - } - -} - - diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/HostingExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/DIContainers/HostingExtensions.cs deleted file mode 100644 index 1279c6a..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/HostingExtensions.cs +++ /dev/null @@ -1,26 +0,0 @@ -using CleanArchitectureCQRS.CommandsDb.Library.BaseCommandInfrastrcture.Intercepters; -using CleanArchitectureCQRS.CommandsDb.Library.Database; -using CleanArchitectureCQRS.QueriesDb.Library.Database; -using Microsoft.EntityFrameworkCore; - -namespace WebApi.EndPoints.DIContainers -{ - public static class HostingExtensions - { - public static IServiceCollection ConfigureServices(this IServiceCollection services, IConfiguration configuration) - { - //CommandDbContext - services.AddDbContext( - c => - c.UseSqlServer(configuration.GetConnectionString("DefaultConnectionCommandDatabase"))); - //.AddInterceptors(new SetPersianYeKeInterceptor(), - // new AddAuditDataInterceptor())); - - //QueryDbContext - services.AddDbContext( - c => c.UseSqlServer(configuration.GetConnectionString("DefaultConnectionQueryDatabase"))); - - return services; - } - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/HttpContextExtentions.cs b/Src/4.EndPoints/WebApi.EndPoints/DIContainers/HttpContextExtentions.cs deleted file mode 100644 index c9caa09..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/HttpContextExtentions.cs +++ /dev/null @@ -1,10 +0,0 @@ -using CleanArchitectureCQRS.Application.Library.BaseApplication.Utilities; - -namespace WebApi.EndPoints.DIContainers -{ - public static class HttpContextExtensions - { - public static UtilitiesServices ApplicationContext(this HttpContext httpContext) => - (UtilitiesServices)httpContext.RequestServices.GetService(typeof(UtilitiesServices)); - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddApiConfigurationExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddApiConfigurationExtensions.cs similarity index 76% rename from Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddApiConfigurationExtensions.cs rename to Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddApiConfigurationExtensions.cs index a629b00..a3e0fcd 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/DIContainers/AddApiConfigurationExtensions.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddApiConfigurationExtensions.cs @@ -1,32 +1,19 @@ using FluentValidation.AspNetCore; using WebApi.EndPoints.Middlewares.ApiExceptionHandler; -namespace WebApi.EndPoints.DIContainers; - -/// -/// -/// +namespace WebApi.EndPoints.HostExtensions.Configurations; public static class AddApiConfigurationExtensions { - /// - /// - /// - /// - /// - /// public static IServiceCollection AddWebApiCore(this IServiceCollection services, params string[] assemblyNamesForLoad) { - services.AddControllers().AddFluentValidation(); + services + .AddControllers() + .AddFluentValidation(); + services.AddDependencies(assemblyNamesForLoad); return services; } - - /// - /// - /// - /// - public static void UseApiExceptionHandler(this IApplicationBuilder app) { app.UseApiExceptionHandler(options => @@ -50,6 +37,4 @@ public static void UseApiExceptionHandler(this IApplicationBuilder app) }); } - - } diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddWebApplicationAssemblies.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddWebApplicationAssemblies.cs new file mode 100644 index 0000000..9223938 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddWebApplicationAssemblies.cs @@ -0,0 +1,18 @@ +using Microsoft.Extensions.DependencyModel; +using System.Reflection; +using WebApi.EndPoints.HostExtensions.Providers.FluentValidation; +using WebApi.EndPoints.HostExtensions.Providers.MediatR; + +namespace WebApi.EndPoints.HostExtensions.Configurations; + +public static class AddWebApplicationAssemblies +{ + public static IServiceCollection AddApplicationServices(this IServiceCollection services, + IEnumerable assembliesForSearch) + => services + .AddMediatRService(assembliesForSearch) + .AddFluentService(assembliesForSearch) + ; + + +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddWebApplicationInjections.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddWebApplicationInjections.cs new file mode 100644 index 0000000..dc2941f --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Configurations/AddWebApplicationInjections.cs @@ -0,0 +1,72 @@ +using Microsoft.Extensions.DependencyModel; +using System.Reflection; + +namespace WebApi.EndPoints.HostExtensions.Configurations; + +public static class AddWebApplicationInjections +{ + public static IServiceCollection AddDependencies(this IServiceCollection services, + params string[] assemblyNamesForSearch) + { + var assemblies = GetAssemblies(assemblyNamesForSearch); + services.AddApplicationServices(assemblies); + return services; + } + + /// + /// + /// + /// + /// + private static List GetAssemblies(string[] assmblyName) + { + + var assemblies = new List(); + var dependencies = DependencyContext.Default.RuntimeLibraries; + foreach (var library in dependencies) + { + if (IsCandidateCompilationLibrary(library, assmblyName)) + { + var assembly = Assembly.Load(new AssemblyName(library.Name)); + assemblies.Add(assembly); + } + } + return assemblies; + } + + /// + /// + /// + /// + /// + private static List GetAssembly(string assmblyName) + { + + var assemblies = new List(); + var dependencies = DependencyContext.Default.RuntimeLibraries; + foreach (var library in dependencies) + { + if (IsCandidateCompilationLibrary(library, assmblyName)) + { + var assembly = Assembly.Load(new AssemblyName(library.Name)); + assemblies.Add(assembly); + } + } + return assemblies; + } + + /// + /// + /// + /// + /// + /// + + private static bool IsCandidateCompilationLibrary(RuntimeLibrary compilationLibrary, string[] assmblyName) + { + return assmblyName.Any(d => compilationLibrary.Name.Contains(d)) + || compilationLibrary.Dependencies.Any(d => assmblyName.Any(c => d.Name.Contains(c))); + } + private static bool IsCandidateCompilationLibrary(RuntimeLibrary compilationLibrary, string assmblyName) + => (compilationLibrary.Name.Contains(assmblyName) || compilationLibrary.Dependencies.Any(d => assmblyName.Equals(d))); +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Identity/AddIdentityServices.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Identity/AddIdentityServices.cs deleted file mode 100644 index 4ef86d2..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Identity/AddIdentityServices.cs +++ /dev/null @@ -1,16 +0,0 @@ -namespace WebApi.EndPoints.HostExtensions.Identity; - -public static class IdentityExtensions -{ - public static IServiceCollection AddIdentityService(this IServiceCollection services) - { - return services; - } - - - public static void UseIdentity(this WebApplication app) - { - app.UseAuthentication(); - app.UseAuthorization(); - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ProgramStartup/ApplicationConfiguration.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ProgramStartup/ApplicationConfiguration.cs new file mode 100644 index 0000000..3baaab8 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ProgramStartup/ApplicationConfiguration.cs @@ -0,0 +1,80 @@ +using CleanArchitectureCQRS.CommandsDb.Library.DIContainer; +using CleanArchitectureCQRS.QueriesDb.Library.DIContainer; +using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Cors.Infrastructure; +using Serilog; +using WebApi.EndPoints.HostExtensions.Configurations; +using WebApi.EndPoints.HostExtensions.Providers.Identity; +using WebApi.EndPoints.HostExtensions.Providers.Swagger; + +namespace WebApi.EndPoints.HostExtensions.ProgramStartup; + +public static class ApplicationConfiguration +{ + + public static WebApplication AddServicesApplication(this WebApplicationBuilder builder) + { + IConfiguration configuration = builder.Configuration; + var scopes = configuration.GetSection("Scopes").Value.Split(","); + builder.Services.AddWebApiCore(scopes); + + builder.Host.UseSerilog((hostingContext, loggerConfiguration) => loggerConfiguration.ReadFrom.Configuration(hostingContext.Configuration)); + + builder.Services.AddIdentityServices(configuration); + + builder.Services.AddSwaggerServiceConfiguration(configuration, "Swagger"); + + builder.Services.AddContextDatabaseCommandDependencies(configuration); + + builder.Services.AddContextDatabaseQueryDependencies(configuration); + + builder.Services.AddMvc(); + + builder.Services.AddControllers(); + + return builder.Build(); + } + public static WebApplication UsePipelineApplication(this WebApplication app) + { + // Configure the HTTP request pipeline. + if (!app.Environment.IsDevelopment()) + { + app.UseExceptionHandler("/Home/Error"); + // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. + app.UseHsts(); + } + + app.UseSerilogRequestLogging(); + + app.UseStaticFiles(); + + app.UseRouting(); + + app.UseMiddleware(); + + app.UseApiExceptionHandler(); + + app.UseSerilogRequestLogging(); + + app.UseIdentity(); + + app.UseSwaggerUI("Swagger"); + + //app.UseStatusCodePages(); + + app.UseCors(delegate (CorsPolicyBuilder builder) + { + builder.AllowAnyOrigin(); + builder.AllowAnyHeader(); + builder.AllowAnyMethod(); + }); + + app.MapControllers(); + + app.UseHttpsRedirection(); + + + return app; + } + +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ProgramStartup/StartupApplication.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ProgramStartup/StartupApplication.cs new file mode 100644 index 0000000..b253a58 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ProgramStartup/StartupApplication.cs @@ -0,0 +1,27 @@ +using Serilog; +using Serilog.Events; + +namespace WebApi.EndPoints.HostExtensions.ProgramStartup; + +public class StartupApplication +{ + public static void StartApplication(Action action) + { + try + { + Log.Logger = new LoggerConfiguration().WriteTo.Console().CreateBootstrapLogger(); + Log.Information("startUpMessage"); + action(); + } + catch (Exception ex) + { + + Log.Fatal(ex, ex.Message); + } + finally + { + Log.Information("shutdownMessage"); + Log.CloseAndFlush(); + } + } +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/FluentValidation/FluentValidationExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/FluentValidation/FluentValidationExtensions.cs new file mode 100644 index 0000000..ed7bdf7 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/FluentValidation/FluentValidationExtensions.cs @@ -0,0 +1,10 @@ +using FluentValidation; +using System.Reflection; + +namespace WebApi.EndPoints.HostExtensions.Providers.FluentValidation; + +public static class FluentValidationExtensions +{ + public static IServiceCollection AddFluentService(this IServiceCollection services, IEnumerable assembliesForSearch) + => services.AddValidatorsFromAssemblies(assembliesForSearch); +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/HttpAccessor/HttpContextExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/HttpAccessor/HttpContextExtensions.cs new file mode 100644 index 0000000..d4d4a8d --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/HttpAccessor/HttpContextExtensions.cs @@ -0,0 +1,8 @@ +using CleanArchitectureCQRS.Application.Library.BaseApplication.Utilities; + +namespace WebApi.EndPoints.HostExtensions.Providers.HttpAccessor; + +public static class HttpContextExtensions +{ + public static UtilitiesServices ApplicationContext(this HttpContext httpContext) => (UtilitiesServices)httpContext.RequestServices.GetService(typeof(UtilitiesServices)); +} \ No newline at end of file diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Identity/IdentityExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Identity/IdentityExtensions.cs new file mode 100644 index 0000000..373942c --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Identity/IdentityExtensions.cs @@ -0,0 +1,13 @@ +namespace WebApi.EndPoints.HostExtensions.Providers.Identity; + +public static class IdentityExtensions +{ + public static IServiceCollection AddIdentityServices(this IServiceCollection services, IConfiguration configuration) + => services; + + public static void UseIdentity(this WebApplication app) + { + app.UseAuthentication(); + app.UseAuthorization(); + } +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/MediatR/MediatRExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/MediatR/MediatRExtensions.cs new file mode 100644 index 0000000..25f1456 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/MediatR/MediatRExtensions.cs @@ -0,0 +1,29 @@ +using CleanArchitectureCQRS.Application.Library.BaseApplication.Behaviors; +using CleanArchitectureCQRS.Application.Library.BaseApplication.Utilities; +using MediatR; +using System.Reflection; + +namespace WebApi.EndPoints.HostExtensions.Providers.MediatR; + +public static class MediatRExtensions +{ + public static IServiceCollection AddMediatRService(this IServiceCollection services, IEnumerable assembliesForSearch) + { + services.AddMediatR(cfg => + { + //cf.RegisterServicesFromAssembly(typeof(DependencyInjection).Assembly); + foreach (var assembly in assembliesForSearch) + { + cfg.RegisterServicesFromAssembly(assembly); + } + cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(UnhandledExceptionBehaviour<,>)); + cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(AuthorizationBehaviour<,>)); + cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(ValidationBehaviour<,>)); + cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(PerformanceBehaviour<,>)); + cfg.AddBehavior(typeof(IPipelineBehavior<,>), typeof(LoggingBehavior<,>)); + + }); + services.AddScoped(); + return services; + } +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/Filters/AddParamsToHeader.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/Filters/AddParamsToHeader.cs new file mode 100644 index 0000000..9bc05b9 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/Filters/AddParamsToHeader.cs @@ -0,0 +1,30 @@ +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerGen; + +namespace WebApi.EndPoints.HostExtensions.Providers.Swagger.Filters; + +public class AddParamsToHeader : IOperationFilter +{ + public void Apply(OpenApiOperation operation, OperationFilterContext context) + { + if (operation.Security == null) + operation.Security = new List(); + + operation.Security.Add(new OpenApiSecurityRequirement() + { + { + new OpenApiSecurityScheme() + { + Name="OAuth2", + Scheme= "OAuth2", + In = ParameterLocation.Header, + Reference = new OpenApiReference() + { + Type = ReferenceType.SecurityScheme, + Id = "OAuth2" + } + }, new List() + } + }); + } +} \ No newline at end of file diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/Options/SwaggerOAuthOption.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/Options/SwaggerOAuthOption.cs new file mode 100644 index 0000000..0caad03 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/Options/SwaggerOAuthOption.cs @@ -0,0 +1,24 @@ +namespace WebApi.EndPoints.HostExtensions.Providers.Swagger.Options; + +public class SwaggerOption +{ + public bool Enabled { get; set; } = true; + public SwaggerDocOption SwaggerDoc { get; set; } = new(); + public SwaggerOAuthOption OAuth { get; set; } = new(); +} + +public class SwaggerDocOption +{ + public string Version { get; set; } = "v1"; + public string Title { get; set; } = "CleanArchitecture_CQRS Web Api"; + public string Name { get; set; } = "v1"; + public string URL { get; set; } = "/swagger/v1/swagger.json"; +} + +public class SwaggerOAuthOption +{ + public bool Enabled { get; set; } = false; + public string AuthorizationUrl { get; set; } = string.Empty; + public string TokenUrl { get; set; } = string.Empty; + public Dictionary Scopes { get; set; } = new(); +} \ No newline at end of file diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/SwaggerExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/SwaggerExtensions.cs new file mode 100644 index 0000000..2a23c49 --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Providers/Swagger/SwaggerExtensions.cs @@ -0,0 +1,92 @@ +using Microsoft.AspNetCore.Mvc.Controllers; +using Microsoft.OpenApi.Models; +using Swashbuckle.AspNetCore.SwaggerUI; +using System.Reflection; +using WebApi.EndPoints.HostExtensions.Providers.Swagger.Filters; +using WebApi.EndPoints.HostExtensions.Providers.Swagger.Options; + +namespace WebApi.EndPoints.HostExtensions.Providers.Swagger; + +public static class SwaggerExtensions +{ + public static IServiceCollection AddSwaggerServiceConfiguration(this IServiceCollection services, IConfiguration configuration, string sectionName) + { + var swaggerOption = configuration.GetSection(sectionName).Get(); + + if (swaggerOption != null && swaggerOption.SwaggerDoc != null && swaggerOption.Enabled == true) + { + services.AddSwaggerGen(o => + { + o.SwaggerDoc(swaggerOption.SwaggerDoc.Name, new OpenApiInfo + { + Title = swaggerOption.SwaggerDoc.Title, + Version = swaggerOption.SwaggerDoc.Version + }); + + o.TagActionsBy(api => + { + if (api.GroupName != null) + return new[] { api.GroupName }; + + var controllerActionDescriptor = api.ActionDescriptor as ControllerActionDescriptor; + + if (controllerActionDescriptor != null) + return new[] { controllerActionDescriptor.ControllerName }; + + throw new InvalidOperationException("Unable to determine tag for endpoint."); + }); + + o.DocInclusionPredicate((name, api) => true); + var oAuthOption = configuration.GetSection("OAuth").Get(); + if (oAuthOption != null && oAuthOption.Enabled) + { + o.AddSecurityDefinition("OAuth2", new OpenApiSecurityScheme + { + Name = "Authorization", + Description = "OAuth2", + BearerFormat = "Bearer ", + In = ParameterLocation.Header, + Type = SecuritySchemeType.OAuth2, + Flows = new OpenApiOAuthFlows + { + AuthorizationCode = new OpenApiOAuthFlow + { + AuthorizationUrl = new Uri(oAuthOption.AuthorizationUrl), + TokenUrl = new Uri(oAuthOption.TokenUrl), + Scopes = oAuthOption.Scopes + } + }, + }); ; + + o.OperationFilter(); + } + + var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; + var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); + //o.IncludeXmlComments(xmlPath); + }); + } + + return services; + } + + + public static void UseSwaggerUI(this WebApplication app, string sectionName) + { + var swaggerOption = app.Configuration + .GetSection(sectionName) + .Get(); + + if (swaggerOption != null && swaggerOption.SwaggerDoc != null && swaggerOption.Enabled == true) + { + app.UseSwagger(); + app.UseSwaggerUI(option => + { + option.DocExpansion(DocExpansion.None); + option.SwaggerEndpoint(swaggerOption.SwaggerDoc.URL, swaggerOption.SwaggerDoc.Title); + //option.RoutePrefix = string.Empty; + option.OAuthUsePkce(); + }); + } + } +} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ServiceExtensions/ServiceInjectionExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ServiceExtensions/ServiceInjectionExtensions.cs deleted file mode 100644 index 80de9a6..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/ServiceExtensions/ServiceInjectionExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -using AbstractionsExtensions.Library.UsersManagement.Services.Extensions.DependencyInjection; -using CleanArchitectureCQRS.Application.Library.BaseApplication.DIContainer; -using CleanArchitectureCQRS.ContextDatabase.Library.DIContainer; -using Microsoft.Extensions.Hosting; -using Microsoft.Extensions.Options; -using Microsoft.OpenApi.Models; -using System; -using WebApi.EndPoints.DIContainers; -using WebApi.EndPoints.HostExtensions.Identity; -using WebApi.EndPoints.HostExtensions.Swagger; -using WebApi.EndPoints.Middlewares; - -namespace WebApi.EndPoints.HostExtensions.ServiceExtensions; - -public static class ServiceInjectionExtensions -{ - public static WebApplication ApplicationServices(this WebApplicationBuilder builder) - { - var configurationBuilder = builder.GetConfiguration(); - var configuration = builder.Configuration; - - builder.Services.AddDependencies("CleanArchitectureCQRS"); - builder.Services.AddWebApiCore("CleanArchitectureCQRS"); - builder.Services.AddWebUserInfoService(configuration, "CleanArchitectureCQRS", true); - builder.Services.AddApplicationDependencies(); - builder.Services.AddContextDatabaseDependencies(configuration); - builder.Services.ConfigureServices(configuration); - builder.Services.AddControllers(); - builder.Services.AddEndpointsApiExplorer(); - - builder.Services.AddIdentityService(); - - builder.Services.SwaggerService(configuration, "Swagger"); - return builder.Build(); - } - - public static WebApplication ApplicationPipeline(this WebApplication app) - { - if (app.Environment.IsDevelopment()) - { - app.UseSwaggerUI("Swagger"); - } - app.UseExceptionsHandling(); - app.UseHttpsRedirection(); - - app.UseIdentity(); - - app.MapControllers(); - - app.Run(); - return app; - } - - private static IConfigurationBuilder GetConfiguration(this WebApplicationBuilder builder) - { - var environment = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); - var configuration = builder.Configuration.SetBasePath(Directory.GetCurrentDirectory()) - .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true) - .AddJsonFile($"appsettings.{environment}.json", optional: true) - .AddEnvironmentVariables(); - return configuration; - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/StartUp/StartupApplication.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/StartUp/StartupApplication.cs deleted file mode 100644 index bcc18d4..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/StartUp/StartupApplication.cs +++ /dev/null @@ -1,17 +0,0 @@ -namespace WebApi.EndPoints.HostExtensions.StartUp; - -public class StartupApplication -{ - public static void StartApplication(Action action) - { - try - { - action(); - } - catch (Exception) - { - - throw; - } - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Swagger/SwaggerExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Swagger/SwaggerExtensions.cs deleted file mode 100644 index 812e920..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/HostExtensions/Swagger/SwaggerExtensions.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.OpenApi.Models; - -namespace WebApi.EndPoints.HostExtensions.Swagger; - -public static class SwaggerExtensions -{ - public static IServiceCollection SwaggerService(this IServiceCollection services, IConfiguration configuration, string sectionName) - { - services.AddSwaggerGen(option => - { - option.SwaggerDoc("v1", new OpenApiInfo - { - Title = "CleanArchitecture_CQRS", - Version = "v1", - Description = "CleanArchitecture_CQRS Application", - License = new OpenApiLicense - { - Name = "License", - Url = new Uri("https://google.com") - }, - Contact = new OpenApiContact - { - Name = "Tajerbashi", - Email = "Tajerbashi@mail.com", - Url = new Uri("https://github.com/KTajerbashi") - }, - TermsOfService = new Uri("https://github.com/KTajerbashi/CleanArchitecture_CQRS") - }); - option.AddSecurityDefinition("JWT", new OpenApiSecurityScheme - { - Name = "Authorization", - Description = "Enter the Bearer Authorization string as following: `Bearer Generated-JWT-Token`", - BearerFormat = "text", - In = ParameterLocation.Header, - Flows = new OpenApiOAuthFlows - { - AuthorizationCode = new OpenApiOAuthFlow - { - AuthorizationUrl = new Uri("https://github.com/KTajerbashi"), - TokenUrl = new Uri("https://github.com/KTajerbashi"), - }, - ClientCredentials = new OpenApiOAuthFlow { } - }, - OpenIdConnectUrl = new Uri("https://github.com/KTajerbashi"), - Scheme = "Bearer", - Type = SecuritySchemeType.ApiKey, - UnresolvedReference = true, - }); - - }); - return services; - } - public static void UseSwaggerUI(this WebApplication app, string sectionName) - { - app.UseSwagger(); - app.UseSwaggerUI(c => - { - c.SwaggerEndpoint("/swagger/v1/swagger.json", "CleanArchitecture_CQRS V1 "); - }); - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiError.cs b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiError.cs index 319fd11..7910daa 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiError.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiError.cs @@ -1,11 +1,24 @@ -namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler; - -public class ApiError +namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler { - public string Id { get; set; } - public short Status { get; set; } - public string Code { get; set; } - public string Links { get; set; } - public string Title { get; set; } - public string Detail { get; set; } + public class ApiError + { + public string Id { get; set; } + public short Status { get; set; } + public string Code { get; set; } + public string Links { get; set; } + public string Title { get; set; } + public string Detail { get; set; } + public string TraceId { get; set; } + } + public class ErrorDetails + { + public string Errors { get; set; } + public int StatusCode { get; set; } + public string Message { get; set; } + + public override string ToString() + { + return System.Text.Json.JsonSerializer.Serialize(this); + } + } } diff --git a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddleware.cs b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddleware.cs index d67f2aa..06d61c3 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddleware.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddleware.cs @@ -1,63 +1,92 @@ -using CleanArchitectureCQRS.Application.Library.BaseApplication.Utilities.Translator; +using Azure; +using FluentValidation; +using System.Diagnostics; using System.Net; -namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler; - -public class ApiExceptionMiddleware +namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler { - private readonly RequestDelegate _next; - private readonly ILogger _logger; - private readonly ApiExceptionOptions _options; - private readonly ITranslator _translator; - - public ApiExceptionMiddleware(ApiExceptionOptions options, RequestDelegate next, - ILogger logger, ITranslator translator - ) + public class ApiExceptionMiddleware { - _next = next; - _logger = logger; - _options = options; - _translator = translator; - } + private readonly RequestDelegate _next; + private readonly ILogger _logger; + private readonly ApiExceptionOptions _options; - public async Task Invoke(HttpContext context) - { - try + public ApiExceptionMiddleware( + ApiExceptionOptions options, + RequestDelegate next, + ILogger logger + ) { - await _next(context); + _next = next; + _logger = logger; + _options = options; } - catch (Exception ex) + + public async Task Invoke(HttpContext context) { - await HandleExceptionAsync(context, ex); + try + { + context.TraceIdentifier = Activity.Current?.Id ?? context?.TraceIdentifier; + await _next(context); + } + catch (Exception ex) + { + await HandleExceptionAsync(context, ex); + } } - } - private Task HandleExceptionAsync(HttpContext context, Exception exception) - { - var error = new ApiError + private Task HandleExceptionAsync(HttpContext context, Exception exception) { - Id = Guid.NewGuid().ToString(), - Status = (short)HttpStatusCode.InternalServerError, - Title = _translator["SOME_KIND_OF_ERROR_OCCURRED_IN_THE_API"] - }; + var error = new ApiError + { + Id = Guid.NewGuid().ToString(), + Status = (short)HttpStatusCode.InternalServerError, + Title = $"{exception.InnerException}", + TraceId = context.TraceIdentifier, + }; - _options.AddResponseDetails?.Invoke(context, exception, error); + _options.AddResponseDetails?.Invoke(context, exception, error); - var innerExMessage = GetInnermostExceptionMessage(exception); + var innerExMessage = GetInnermostExceptionMessage(exception); - var level = _options.DetermineLogLevel?.Invoke(exception) ?? LogLevel.Error; - _logger.Log(level, exception, "BADNESS!!! " + innerExMessage + " -- {ErrorId}.", error.Id); + var level = _options.DetermineLogLevel?.Invoke(exception) ?? LogLevel.Error; + _logger.Log(level, exception, "BADNESS!!! " + innerExMessage + " -- {ErrorId}.", error.Id); - var result = error.ToString(); - context.Response.ContentType = "application/json"; - context.Response.StatusCode = (int)HttpStatusCode.InternalServerError; - return context.Response.WriteAsync(result); - } - private string GetInnermostExceptionMessage(Exception exception) - { - if (exception.InnerException != null) - return GetInnermostExceptionMessage(exception.InnerException); + context.Response.ContentType = "application/json"; + context.Response.StatusCode = exception switch + { + ValidationException => (int)HttpStatusCode.BadRequest, + UnauthorizedAccessException => (int)HttpStatusCode.Unauthorized, + KeyNotFoundException => (int)HttpStatusCode.NotFound, + _ => (int)HttpStatusCode.InternalServerError + }; + + var message = exception switch + { + ValidationException => exception.Message, + UnauthorizedAccessException => exception.Message, + KeyNotFoundException => exception.Message, + _ => "Internal Server Error from the custom middleware." + }; + var errorJson = System.Text.Json.JsonSerializer.Serialize(new + { + Error = error, + Message = message, + StatusCode = context.Response.StatusCode, - return exception.Message; + }); + return context.Response.WriteAsync(new ErrorDetails() + { + Errors = errorJson, + }.ToString()); + + } + private string GetInnermostExceptionMessage(Exception exception) + { + if (exception.InnerException != null) + return GetInnermostExceptionMessage(exception.InnerException); + + return exception.Message; + } } } diff --git a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddlewareExtensions.cs b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddlewareExtensions.cs index 0d804e5..d424dd4 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddlewareExtensions.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionMiddlewareExtensions.cs @@ -1,19 +1,26 @@ -namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler; - -public static class ApiExceptionMiddlewareExtensions +namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler { - public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder) + public static class ApiExceptionMiddlewareExtensions { - var options = new ApiExceptionOptions(); - return builder.UseMiddleware(options); - } + public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder) + { + var options = new ApiExceptionOptions(); + return builder.UseMiddleware(options); + } - public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder, - Action configureOptions) - { - var options = new ApiExceptionOptions(); - configureOptions(options); + /// + /// در ادامه مرحله پنجم بعد از گام اول اجرا میشود + /// + /// + /// + /// + public static IApplicationBuilder UseApiExceptionHandler(this IApplicationBuilder builder, + Action configureOptions) + { + var options = new ApiExceptionOptions(); + configureOptions(options); - return builder.UseMiddleware(options); + return builder.UseMiddleware(options); + } } } diff --git a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionOptions.cs b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionOptions.cs index 988ba5a..9a72b8b 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionOptions.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ApiExceptionHandler/ApiExceptionOptions.cs @@ -1,7 +1,10 @@ -namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler; +using Microsoft.AspNetCore.Http; -public class ApiExceptionOptions +namespace WebApi.EndPoints.Middlewares.ApiExceptionHandler { - public Action AddResponseDetails { get; set; } - public Func DetermineLogLevel { get; set; } + public class ApiExceptionOptions + { + public Action AddResponseDetails { get; set; } + public Func DetermineLogLevel { get; set; } + } } diff --git a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ExceptionsHandling.cs b/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ExceptionsHandling.cs deleted file mode 100644 index bfcdc97..0000000 --- a/Src/4.EndPoints/WebApi.EndPoints/Middlewares/ExceptionsHandling.cs +++ /dev/null @@ -1,38 +0,0 @@ -namespace WebApi.EndPoints.Middlewares; - -// You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project -public class ExceptionsHandling -{ - private readonly RequestDelegate _next; - - public ExceptionsHandling(RequestDelegate next) - { - Console.WriteLine("INFO UP : ExceptionsHandling"); - _next = next; - } - - public Task Invoke(HttpContext httpContext) - { - Console.WriteLine("INFO UP : Invoke"); - try - { - return _next(httpContext); - } - catch (Exception ex) - { - Console.WriteLine($"INFO Down {ex.Message}"); - throw; - } - } -} - -// Extension method used to add the middleware to the HTTP request pipeline. -public static class ExceptionsHandlingExtensions -{ - public static IApplicationBuilder UseExceptionsHandling(this IApplicationBuilder builder) - { - Console.WriteLine("INFO UP : UseExceptionsHandling"); - return builder.UseMiddleware(); - Console.WriteLine("INFO Down : UseExceptionsHandling"); - } -} diff --git a/Src/4.EndPoints/WebApi.EndPoints/Models/Identity/Authenticate/AuthenticationRule.cs b/Src/4.EndPoints/WebApi.EndPoints/Models/Identity/Authenticate/AuthenticationRule.cs new file mode 100644 index 0000000..1ca59cb --- /dev/null +++ b/Src/4.EndPoints/WebApi.EndPoints/Models/Identity/Authenticate/AuthenticationRule.cs @@ -0,0 +1,9 @@ +namespace WebApi.EndPoints.Models.Identity.Authenticate; + +public class AuthenticationRule +{ + public int Id { get; set; } + public string RuleName { get; set; } + public string Description { get; set; } + public bool IsEnabled { get; set; } +} \ No newline at end of file diff --git a/Src/4.EndPoints/WebApi.EndPoints/Program.cs b/Src/4.EndPoints/WebApi.EndPoints/Program.cs index 01fecbe..57b6231 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/Program.cs +++ b/Src/4.EndPoints/WebApi.EndPoints/Program.cs @@ -1,13 +1,12 @@ -using WebApi.EndPoints.HostExtensions.ServiceExtensions; -using WebApi.EndPoints.HostExtensions.StartUp; +using WebApi.EndPoints.HostExtensions.ProgramStartup; StartupApplication.StartApplication(() => { WebApplication .CreateBuilder(args) - .ApplicationServices() - .ApplicationPipeline() - .RunAsync(); + .AddServicesApplication() + .UsePipelineApplication() + .Run(); }); diff --git a/Src/4.EndPoints/WebApi.EndPoints/WebApi.EndPoints.csproj b/Src/4.EndPoints/WebApi.EndPoints/WebApi.EndPoints.csproj index bd4d78e..274f0f3 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/WebApi.EndPoints.csproj +++ b/Src/4.EndPoints/WebApi.EndPoints/WebApi.EndPoints.csproj @@ -13,7 +13,20 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + @@ -25,4 +38,9 @@ + + + + + diff --git a/Src/4.EndPoints/WebApi.EndPoints/appsettings.Development.json b/Src/4.EndPoints/WebApi.EndPoints/appsettings.Development.json index d017ed8..b5e974c 100644 --- a/Src/4.EndPoints/WebApi.EndPoints/appsettings.Development.json +++ b/Src/4.EndPoints/WebApi.EndPoints/appsettings.Development.json @@ -2,9 +2,51 @@ "Logging": { "LogLevel": { "Default": "Information", - "Microsoft.AspNetCore": "Warning" + "Microsoft": "Warning", + "Microsoft.Hosting.Lifetime": "Information" } }, + "Scopes": "WebApi, CleanArchitectureCQRS", + "Serilog": { + "Using": [ "Serilog.Sinks.Console", "Serilog.Sinks.File" ], + "MinimumLevel": { + "Default": "Information", + "Override": { + "Microsoft": "Warning", + "System": "Warning", + "TK": "Verbose" + } + }, + "WriteTo": [ + { "Name": "Console" }, + { + "Name": "File", + "Args": { "path": "%TEMP%\\Logs\\Desktop.Log.txt" } + }, + { + "Name": "Elasticsearch", + "Args": { + "nodeUris": "http://localhost:9200", + "indexFormat": "CleanArchitecture_CQRS-serilog-sample-index-{0:yyyy.MM}", + "restrictedToMinimumLevel": "Verbose", + "autoRegisterTemplate": true, + "autoRegisterTemplateVersion": "ESv6", + "batchPostingLimit": 50, + "period": 2, + "inlineFields": true, + "bufferFileSizeLimitBytes": 5242880, + "bufferLogShippingInterval": 5000, + "bufferRetainedInvalidPayloadsLimitBytes": 5000, + "bufferFileCountLimit": 31, + "connectionTimeout": 5, + "emitEventFailure": "WriteToSelfLog", + "queueSizeLimit": "100000" + } + } + ] + }, + + "ConnectionStrings": { "DefaultConnection": "Server =172.20.1.20\\DEV; Database=CleanArchitecture_CQRS;User Id = sa;Password=soft157703ware; MultipleActiveResultSets=true; Encrypt = false", "DefaultConnectionCommandDatabase": "Server =172.20.1.20\\DEV; Database=CleanArchitecture_CQRS;User Id = sa;Password=soft157703ware; MultipleActiveResultSets=true; Encrypt = false", @@ -15,7 +57,34 @@ //"DefaultConnectionCommandDatabase": "Server =TAJERBASHI; Database=CleanArchitecture_CQRS;User Id = sa;Password=123123; MultipleActiveResultSets=true; Encrypt = false", //"DefaultConnectionQueryDatabase": "Server =TAJERBASHI; Database=CleanArchitecture_CQRS;User Id = sa;Password=123123; MultipleActiveResultSets=true; Encrypt = false" }, - "WebUserInfo": { - "DefaultUserId": -1 + "OAuth": { + "Authority": "https://localhost:5000", + "Audience": "Desktop", + "RequireHttpsMetadata": true, + "Scopes": { + "DesktopScope": "DesktopScope" + }, + "ValidateAudience": false, + "Enabled": false, + "ValidateIssuer": false, + "ValidateIssuerSigningKey": false + }, + + "Swagger": { + "Enabled": true, + "SwaggerDoc": { + "Version": "v1", + "Title": "CleanArchitecture_CQRS", + "Name": "v1", + "URL": "/swagger/v1/swagger.json" + }, + "OAuth": { + "Enabled": false, + "AuthorizationUrl": "", + "TokenUrl": "", + "Scopes": { + "DesktopScope": "CleanArchitecture_CQRS" + } + } } }