Add an Application layer #2

Merged
Wesser merged 7 commits from feat/application into release/v1.0.0 2024-01-08 16:13:10 +03:00
17 changed files with 215 additions and 1 deletions

View File

@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<Company>Winsomnia</Company>
<Version>1.0.0-a0</Version>
<AssemblyVersion>1.0.0.0</AssemblyVersion>
<FileVersion>1.0.0.0</FileVersion>
<AssemblyName>Mirea.Api.DataAccess.Application</AssemblyName>
<RootNamespace>$(AssemblyName)</RootNamespace>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="FluentValidation" Version="11.9.0" />
<PackageReference Include="FluentValidation.DependencyInjectionExtensions" Version="11.9.0" />
<PackageReference Include="MediatR" Version="12.2.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Domain\Domain.csproj" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,30 @@
using FluentValidation;
using MediatR;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Mirea.Api.DataAccess.Application.Common.Behaviors;
public class ValidationBehavior<TRequest, TResponse>(IEnumerable<IValidator<TRequest>> validators)
: IPipelineBehavior<TRequest, TResponse> where TRequest : IRequest<TResponse>
{
public Task<TResponse> Handle(TRequest request,
RequestHandlerDelegate<TResponse> next, CancellationToken cancellationToken)
{
var context = new ValidationContext<TRequest>(request);
var failures = validators
.Select(v => v.Validate(context))
.SelectMany(result => result.Errors)
.Where(failure => failure != null)
.ToList();
if (failures.Count != 0)
{
throw new ValidationException(failures);
}
return next();
}
}

View File

@ -0,0 +1,28 @@
using AutoMapper;
using System;
using System.Linq;
using System.Reflection;
namespace Mirea.Api.DataAccess.Application.Common.Mappings;
public class AssemblyMappingProfile : Profile
{
public AssemblyMappingProfile(Assembly assembly) =>
ApplyMappingsFromAssembly(assembly);
private void ApplyMappingsFromAssembly(Assembly assembly)
{
var types = assembly.GetExportedTypes()
.Where(type => type.GetInterfaces()
.Any(i => i.IsGenericType &&
i.GetGenericTypeDefinition() == typeof(IMapWith<>)))
.ToList();
foreach (var type in types)
{
var instance = Activator.CreateInstance(type);
var methodInfo = type.GetMethod("Mapping");
methodInfo?.Invoke(instance, new[] { this });
}
}
}

View File

@ -0,0 +1,9 @@
using AutoMapper;
namespace Mirea.Api.DataAccess.Application.Common.Mappings;
public interface IMapWith<T>
{
void Mapping(Profile profile) =>
profile.CreateMap(typeof(T), GetType());
}

View File

@ -0,0 +1,19 @@
using FluentValidation;
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using Mirea.Api.DataAccess.Application.Common.Behaviors;
using System.Reflection;
namespace Mirea.Api.DataAccess.Application;
public static class DependencyInjection
{
public static IServiceCollection AddApplication(this IServiceCollection services)
{
services.AddMediatR(cfg => cfg.RegisterServicesFromAssembly(Assembly.GetExecutingAssembly()));
services.AddValidatorsFromAssemblies(new[] { Assembly.GetExecutingAssembly() });
services.AddTransient(typeof(IPipelineBehavior<,>),
typeof(ValidationBehavior<,>));
return services;
}
}

View File

@ -0,0 +1,9 @@
using System.Threading;
using System.Threading.Tasks;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts;
public interface IDbContextBase
{
Task<int> SaveChangesAsync(CancellationToken cancellationToken);
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface ICampusDbContext : IDbContextBase
{
DbSet<Campus> Campuses { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface IDayDbContext : IDbContextBase
{
DbSet<Day> Days { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface IFacultyDbContext : IDbContextBase
{
DbSet<Faculty> Faculties { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface IGroupDbContext : IDbContextBase
{
DbSet<Group> Groups { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface ILectureHallDbContext : IDbContextBase
{
DbSet<LectureHall> LectureHalls { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface ILessonDbContext : IDbContextBase
{
DbSet<Lesson> Lessons { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface ILessonToTypeOfOccupationDbContext : IDbContextBase
{
DbSet<LessonToTypeOfOccupation> LessonToTypeOfOccupations { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface IProfessorDbContext : IDbContextBase
{
DbSet<Professor> Professors { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface IProfessorToLessonDbContext : IDbContextBase
{
DbSet<ProfessorToLesson> ProfessorToLessons { get; set; }
}

View File

@ -0,0 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Mirea.Api.DataAccess.Domain.Schedule;
namespace Mirea.Api.DataAccess.Application.Interfaces.DbContexts.Schedule;
public interface ITypeOfOccupationDbContext : IDbContextBase
{
DbSet<TypeOfOccupation> TypeOfOccupations { get; set; }
}

View File

@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.8.34330.188 VisualStudioVersion = 17.8.34330.188
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Domain", "Domain\Domain.csproj", "{C27FB5CD-6A70-4FB2-847A-847B34806902}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Domain", "Domain\Domain.csproj", "{C27FB5CD-6A70-4FB2-847A-847B34806902}"
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Endpoint", "Endpoint\Endpoint.csproj", "{F3A1D12E-F5B2-4339-9966-DBF869E78357}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Endpoint", "Endpoint\Endpoint.csproj", "{F3A1D12E-F5B2-4339-9966-DBF869E78357}"
EndProject EndProject
@ -17,6 +17,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Elements of the solution",
README.md = README.md README.md = README.md
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Application", "Application\Application.csproj", "{E7F0A4D4-B032-4BB9-9526-1AF688F341A4}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU