mirror of
https://github.com/alex289/CleanArchitecture.git
synced 2025-07-05 05:23:57 +00:00
Add gRPC and fix some warnings
This commit is contained in:
parent
2c8bf95254
commit
f645b2cc8f
@ -24,6 +24,7 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CleanArchitecture.Application\CleanArchitecture.Application.csproj" />
|
<ProjectReference Include="..\CleanArchitecture.Application\CleanArchitecture.Application.csproj" />
|
||||||
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
|
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj" />
|
||||||
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
|
<ProjectReference Include="..\CleanArchitecture.Infrastructure\CleanArchitecture.Infrastructure.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ public class ApiController : ControllerBase
|
|||||||
return GetErrorStatusCode();
|
return GetErrorStatusCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected HttpStatusCode GetErrorStatusCode()
|
private HttpStatusCode GetErrorStatusCode()
|
||||||
{
|
{
|
||||||
if (_notifications.GetNotifications().Any(n => n.Code == ErrorCodes.ObjectNotFound))
|
if (_notifications.GetNotifications().Any(n => n.Code == ErrorCodes.ObjectNotFound))
|
||||||
{
|
{
|
||||||
|
@ -29,9 +29,11 @@ public class UserController : ApiController
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{id}")]
|
[HttpGet("{id}")]
|
||||||
public async Task<IActionResult> GetUserByIdAsync([FromRoute] Guid id)
|
public async Task<IActionResult> GetUserByIdAsync(
|
||||||
|
[FromRoute] Guid id,
|
||||||
|
[FromQuery] bool isDeleted = false)
|
||||||
{
|
{
|
||||||
var user = await _userService.GetUserByUserIdAsync(id);
|
var user = await _userService.GetUserByUserIdAsync(id, isDeleted);
|
||||||
return Response(user);
|
return Response(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using CleanArchitecture.Application.Extensions;
|
using CleanArchitecture.Application.Extensions;
|
||||||
using CleanArchitecture.Domain.Extensions;
|
using CleanArchitecture.Domain.Extensions;
|
||||||
|
using CleanArchitecture.gRPC;
|
||||||
using CleanArchitecture.Infrastructure.Database;
|
using CleanArchitecture.Infrastructure.Database;
|
||||||
using CleanArchitecture.Infrastructure.Extensions;
|
using CleanArchitecture.Infrastructure.Extensions;
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
@ -10,6 +11,7 @@ using Microsoft.Extensions.DependencyInjection;
|
|||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
builder.Services.AddControllers();
|
builder.Services.AddControllers();
|
||||||
|
builder.Services.AddGrpc();
|
||||||
builder.Services.AddEndpointsApiExplorer();
|
builder.Services.AddEndpointsApiExplorer();
|
||||||
builder.Services.AddSwaggerGen();
|
builder.Services.AddSwaggerGen();
|
||||||
|
|
||||||
@ -43,6 +45,7 @@ app.UseHttpsRedirection();
|
|||||||
app.UseAuthorization();
|
app.UseAuthorization();
|
||||||
|
|
||||||
app.MapControllers();
|
app.MapControllers();
|
||||||
|
app.MapGrpcService<UsersApiImplementation>();
|
||||||
|
|
||||||
using (IServiceScope scope = app.Services.CreateScope())
|
using (IServiceScope scope = app.Services.CreateScope())
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetAll;
|
using CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
using CleanArchitecture.Domain.Entities;
|
using CleanArchitecture.Domain.Entities;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
@ -8,7 +10,7 @@ namespace CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
|||||||
|
|
||||||
public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
|
public sealed class GetAllUsersTestFixture : QueryHandlerBaseFixture
|
||||||
{
|
{
|
||||||
public Mock<IUserRepository> UserRepository { get; }
|
private Mock<IUserRepository> UserRepository { get; }
|
||||||
public GetAllUsersQueryHandler Handler { get; }
|
public GetAllUsersQueryHandler Handler { get; }
|
||||||
public Guid ExistingUserId { get; } = Guid.NewGuid();
|
public Guid ExistingUserId { get; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
||||||
using CleanArchitecture.Domain.Entities;
|
using CleanArchitecture.Domain.Entities;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
@ -8,7 +10,7 @@ namespace CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
|||||||
|
|
||||||
public sealed class GetUserByIdTestFixture : QueryHandlerBaseFixture
|
public sealed class GetUserByIdTestFixture : QueryHandlerBaseFixture
|
||||||
{
|
{
|
||||||
public Mock<IUserRepository> UserRepository { get; }
|
private Mock<IUserRepository> UserRepository { get; }
|
||||||
public GetUserByIdQueryHandler Handler { get; }
|
public GetUserByIdQueryHandler Handler { get; }
|
||||||
public Guid ExistingUserId { get; } = Guid.NewGuid();
|
public Guid ExistingUserId { get; } = Guid.NewGuid();
|
||||||
|
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
using CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
||||||
using CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
using CleanArchitecture.Application.Tests.Fixtures.Queries.Users;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
@ -16,7 +18,7 @@ public sealed class GetUserByIdQueryHandlerTests
|
|||||||
_fixture.SetupUserAsync();
|
_fixture.SetupUserAsync();
|
||||||
|
|
||||||
var result = await _fixture.Handler.Handle(
|
var result = await _fixture.Handler.Handle(
|
||||||
new(_fixture.ExistingUserId),
|
new(_fixture.ExistingUserId, false),
|
||||||
default);
|
default);
|
||||||
|
|
||||||
_fixture.VerifyNoDomainNotification();
|
_fixture.VerifyNoDomainNotification();
|
||||||
@ -30,7 +32,7 @@ public sealed class GetUserByIdQueryHandlerTests
|
|||||||
{
|
{
|
||||||
_fixture.SetupUserAsync();
|
_fixture.SetupUserAsync();
|
||||||
|
|
||||||
var request = new GetUserByIdQuery(Guid.NewGuid());
|
var request = new GetUserByIdQuery(Guid.NewGuid(), false);
|
||||||
var result = await _fixture.Handler.Handle(
|
var result = await _fixture.Handler.Handle(
|
||||||
request,
|
request,
|
||||||
default);
|
default);
|
||||||
|
@ -3,7 +3,6 @@ using CleanArchitecture.Application.Interfaces;
|
|||||||
using CleanArchitecture.Application.Queries.Users.GetAll;
|
using CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
using CleanArchitecture.Application.Queries.Users.GetUserById;
|
||||||
using CleanArchitecture.Application.Services;
|
using CleanArchitecture.Application.Services;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
@ -7,7 +7,7 @@ namespace CleanArchitecture.Application.Interfaces;
|
|||||||
|
|
||||||
public interface IUserService
|
public interface IUserService
|
||||||
{
|
{
|
||||||
public Task<UserViewModel?> GetUserByUserIdAsync(Guid userId);
|
public Task<UserViewModel?> GetUserByUserIdAsync(Guid userId, bool isDeleted);
|
||||||
public Task<IEnumerable<UserViewModel>> GetAllUsersAsync();
|
public Task<IEnumerable<UserViewModel>> GetAllUsersAsync();
|
||||||
public Task<Guid> CreateUserAsync(CreateUserViewModel user);
|
public Task<Guid> CreateUserAsync(CreateUserViewModel user);
|
||||||
public Task UpdateUserAsync(UpdateUserViewModel user);
|
public Task UpdateUserAsync(UpdateUserViewModel user);
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.Queries.Users.GetAll;
|
namespace CleanArchitecture.Application.Queries.Users.GetAll;
|
||||||
|
|
||||||
public sealed record GetAllUsersQuery() : IRequest<IEnumerable<UserViewModel>>;
|
public sealed record GetAllUsersQuery : IRequest<IEnumerable<UserViewModel>>;
|
||||||
|
@ -2,7 +2,6 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using MediatR;
|
using MediatR;
|
||||||
|
|
||||||
namespace CleanArchitecture.Application.Queries.Users.GetUserById;
|
namespace CleanArchitecture.Application.Queries.Users.GetUserById;
|
||||||
|
|
||||||
public sealed record GetUserByIdQuery(Guid UserId) : IRequest<UserViewModel?>;
|
public sealed record GetUserByIdQuery(Guid UserId, bool IsDeleted) : IRequest<UserViewModel?>;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.ViewModels;
|
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Interfaces;
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
@ -27,7 +26,9 @@ public sealed class GetUserByIdQueryHandler :
|
|||||||
{
|
{
|
||||||
var user = _userRepository
|
var user = _userRepository
|
||||||
.GetAllNoTracking()
|
.GetAllNoTracking()
|
||||||
.FirstOrDefault(x => x.Id == request.UserId && !x.Deleted);
|
.FirstOrDefault(x =>
|
||||||
|
x.Id == request.UserId &&
|
||||||
|
x.Deleted == request.IsDeleted);
|
||||||
|
|
||||||
if (user == null)
|
if (user == null)
|
||||||
{
|
{
|
||||||
|
@ -21,9 +21,9 @@ public sealed class UserService : IUserService
|
|||||||
_bus = bus;
|
_bus = bus;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<UserViewModel?> GetUserByUserIdAsync(Guid userId)
|
public async Task<UserViewModel?> GetUserByUserIdAsync(Guid userId, bool isDeleted)
|
||||||
{
|
{
|
||||||
return await _bus.QueryAsync(new GetUserByIdQuery(userId));
|
return await _bus.QueryAsync(new GetUserByIdQuery(userId, isDeleted));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<IEnumerable<UserViewModel>> GetAllUsersAsync()
|
public async Task<IEnumerable<UserViewModel>> GetAllUsersAsync()
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
using CleanArchitecture.Domain.Commands.Users.CreateUser;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
@ -31,7 +33,7 @@ public sealed class UpdateUserCommandHandlerTests
|
|||||||
[Fact]
|
[Fact]
|
||||||
public async Task Should_Not_Update_Non_Existing_User()
|
public async Task Should_Not_Update_Non_Existing_User()
|
||||||
{
|
{
|
||||||
var user = _fixture.SetupUser();
|
_fixture.SetupUser();
|
||||||
|
|
||||||
var command = new UpdateUserCommand(
|
var command = new UpdateUserCommand(
|
||||||
Guid.NewGuid(),
|
Guid.NewGuid(),
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
||||||
using CleanArchitecture.Domain.Interfaces.Repositories;
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
using Moq;
|
using Moq;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
using CleanArchitecture.Domain.Commands.Users.UpdateUser;
|
||||||
using CleanArchitecture.Domain.Errors;
|
using CleanArchitecture.Domain.Errors;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using CleanArchitecture.Domain.Interfaces;
|
using CleanArchitecture.Domain.Interfaces;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
@ -7,9 +8,9 @@ namespace CleanArchitecture.Domain.Tests;
|
|||||||
|
|
||||||
public class CommandHandlerFixtureBase
|
public class CommandHandlerFixtureBase
|
||||||
{
|
{
|
||||||
public Mock<IMediatorHandler> Bus { get; protected set; }
|
protected Mock<IMediatorHandler> Bus { get; }
|
||||||
public Mock<IUnitOfWork> UnitOfWork { get; protected set; }
|
protected Mock<IUnitOfWork> UnitOfWork { get; }
|
||||||
public Mock<DomainNotificationHandler> NotificationHandler { get; protected set; }
|
protected Mock<DomainNotificationHandler> NotificationHandler { get; }
|
||||||
|
|
||||||
protected CommandHandlerFixtureBase()
|
protected CommandHandlerFixtureBase()
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using CleanArchitecture.Domain.Commands;
|
using CleanArchitecture.Domain.Commands;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using FluentValidation;
|
using FluentValidation;
|
||||||
@ -8,7 +10,7 @@ public class ValidationTestBase<TCommand, TValidation>
|
|||||||
where TCommand : CommandBase
|
where TCommand : CommandBase
|
||||||
where TValidation: AbstractValidator<TCommand>
|
where TValidation: AbstractValidator<TCommand>
|
||||||
{
|
{
|
||||||
protected readonly TValidation _validation;
|
private readonly TValidation _validation;
|
||||||
|
|
||||||
protected ValidationTestBase(TValidation validation)
|
protected ValidationTestBase(TValidation validation)
|
||||||
{
|
{
|
||||||
|
@ -4,7 +4,7 @@ namespace CleanArchitecture.Domain.Commands.Users.CreateUser;
|
|||||||
|
|
||||||
public sealed class CreateUserCommand : CommandBase
|
public sealed class CreateUserCommand : CommandBase
|
||||||
{
|
{
|
||||||
private static readonly CreateUserCommandValidation _validation = new();
|
private readonly CreateUserCommandValidation _validation = new();
|
||||||
|
|
||||||
public Guid UserId { get; }
|
public Guid UserId { get; }
|
||||||
public string Email { get; }
|
public string Email { get; }
|
||||||
|
@ -4,7 +4,7 @@ namespace CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
|||||||
|
|
||||||
public sealed class DeleteUserCommand : CommandBase
|
public sealed class DeleteUserCommand : CommandBase
|
||||||
{
|
{
|
||||||
private static readonly DeleteUserCommandValidation _validation = new();
|
private readonly DeleteUserCommandValidation _validation = new();
|
||||||
|
|
||||||
public Guid UserId { get; }
|
public Guid UserId { get; }
|
||||||
|
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
@ -35,7 +35,7 @@ public sealed class DomainNotificationHandlerTests
|
|||||||
|
|
||||||
var domainNotification = new DomainNotification(key, value, code);
|
var domainNotification = new DomainNotification(key, value, code);
|
||||||
var domainNotificationHandler = new DomainNotificationHandler();
|
var domainNotificationHandler = new DomainNotificationHandler();
|
||||||
domainNotificationHandler.Handle(domainNotification, default);
|
domainNotificationHandler.Handle(domainNotification);
|
||||||
domainNotificationHandler.GetNotifications().Should().HaveCount(1);
|
domainNotificationHandler.GetNotifications().Should().HaveCount(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using CleanArchitecture.Domain.Notifications;
|
using System;
|
||||||
|
using CleanArchitecture.Domain.Notifications;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
using CleanArchitecture.Domain.Commands.Users.DeleteUser;
|
||||||
using CleanArchitecture.Domain.Events.User;
|
using CleanArchitecture.Domain.Events.User;
|
||||||
using CleanArchitecture.Domain.Notifications;
|
using CleanArchitecture.Domain.Notifications;
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Infrastructure.Database;
|
using CleanArchitecture.Infrastructure.Database;
|
||||||
using CleanArchitecture.Infrastructure.Tests.Fixtures;
|
using CleanArchitecture.Infrastructure.Tests.Fixtures;
|
||||||
using FluentAssertions;
|
using FluentAssertions;
|
||||||
@ -37,7 +40,7 @@ public sealed class UnitOfWorkTests
|
|||||||
|
|
||||||
dbContextMock
|
dbContextMock
|
||||||
.Setup(x => x.SaveChangesAsync(CancellationToken.None))
|
.Setup(x => x.SaveChangesAsync(CancellationToken.None))
|
||||||
.Throws(new DbUpdateException("Boom", new System.Exception("it broke")));
|
.Throws(new DbUpdateException("Boom", new Exception("it broke")));
|
||||||
|
|
||||||
var unitOfWork = UnitOfWorkTestFixture.GetUnitOfWork(dbContextMock.Object, loggerMock.Object);
|
var unitOfWork = UnitOfWorkTestFixture.GetUnitOfWork(dbContextMock.Object, loggerMock.Object);
|
||||||
|
|
||||||
@ -59,8 +62,8 @@ public sealed class UnitOfWorkTests
|
|||||||
|
|
||||||
var unitOfWork = UnitOfWorkTestFixture.GetUnitOfWork(dbContextMock.Object, loggerMock.Object);
|
var unitOfWork = UnitOfWorkTestFixture.GetUnitOfWork(dbContextMock.Object, loggerMock.Object);
|
||||||
|
|
||||||
Func<Task> knalltAction = async () => await unitOfWork.CommitAsync();
|
Func<Task> throwsAction = async () => await unitOfWork.CommitAsync();
|
||||||
|
|
||||||
await knalltAction.Should().ThrowAsync<Exception>();
|
await throwsAction.Should().ThrowAsync<Exception>();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -10,23 +10,23 @@ namespace CleanArchitecture.Infrastructure.Repositories;
|
|||||||
|
|
||||||
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : Entity
|
public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : Entity
|
||||||
{
|
{
|
||||||
protected readonly DbContext _dbContext;
|
private readonly DbContext _dbContext;
|
||||||
protected readonly DbSet<TEntity> _dbSet;
|
protected readonly DbSet<TEntity> DbSet;
|
||||||
|
|
||||||
public BaseRepository(DbContext context)
|
protected BaseRepository(DbContext context)
|
||||||
{
|
{
|
||||||
_dbContext = context;
|
_dbContext = context;
|
||||||
_dbSet = _dbContext.Set<TEntity>();
|
DbSet = _dbContext.Set<TEntity>();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Add(TEntity entity)
|
public void Add(TEntity entity)
|
||||||
{
|
{
|
||||||
_dbSet.Add(entity);
|
DbSet.Add(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddRange(IEnumerable<TEntity> entities)
|
public void AddRange(IEnumerable<TEntity> entities)
|
||||||
{
|
{
|
||||||
_dbSet.AddRange(entities);
|
DbSet.AddRange(entities);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
@ -37,17 +37,17 @@ public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : Enti
|
|||||||
|
|
||||||
public virtual IQueryable<TEntity> GetAll()
|
public virtual IQueryable<TEntity> GetAll()
|
||||||
{
|
{
|
||||||
return _dbSet;
|
return DbSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual IQueryable<TEntity> GetAllNoTracking()
|
public virtual IQueryable<TEntity> GetAllNoTracking()
|
||||||
{
|
{
|
||||||
return _dbSet.AsNoTracking();
|
return DbSet.AsNoTracking();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<TEntity?> GetByIdAsync(Guid id)
|
public virtual async Task<TEntity?> GetByIdAsync(Guid id)
|
||||||
{
|
{
|
||||||
return await _dbSet.FindAsync(id);
|
return await DbSet.FindAsync(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SaveChanges()
|
public int SaveChanges()
|
||||||
@ -65,24 +65,24 @@ public class BaseRepository<TEntity> : IRepository<TEntity> where TEntity : Enti
|
|||||||
|
|
||||||
public virtual void Update(TEntity entity)
|
public virtual void Update(TEntity entity)
|
||||||
{
|
{
|
||||||
_dbSet.Update(entity);
|
DbSet.Update(entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Task<bool> ExistsAsync(Guid id)
|
public Task<bool> ExistsAsync(Guid id)
|
||||||
{
|
{
|
||||||
return _dbSet.AnyAsync(entity => entity.Id == id);
|
return DbSet.AnyAsync(entity => entity.Id == id);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Remove(TEntity entity, bool hardDelete = false)
|
public void Remove(TEntity entity, bool hardDelete = false)
|
||||||
{
|
{
|
||||||
if (hardDelete)
|
if (hardDelete)
|
||||||
{
|
{
|
||||||
_dbSet.Remove(entity);
|
DbSet.Remove(entity);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
entity.Delete();
|
entity.Delete();
|
||||||
_dbSet.Update(entity);
|
DbSet.Update(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,6 +14,6 @@ public sealed class UserRepository : BaseRepository<User>, IUserRepository
|
|||||||
|
|
||||||
public async Task<User?> GetByEmailAsync(string email)
|
public async Task<User?> GetByEmailAsync(string email)
|
||||||
{
|
{
|
||||||
return await _dbSet.SingleOrDefaultAsync(user => user.Email == email);
|
return await DbSet.SingleOrDefaultAsync(user => user.Email == email);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,7 +6,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
|
|
||||||
namespace CleanArchitecture.Infrastructure;
|
namespace CleanArchitecture.Infrastructure;
|
||||||
|
|
||||||
public class UnitOfWork<TContext> : IUnitOfWork where TContext : DbContext
|
public sealed class UnitOfWork<TContext> : IUnitOfWork where TContext : DbContext
|
||||||
{
|
{
|
||||||
private readonly TContext _context;
|
private readonly TContext _context;
|
||||||
private readonly ILogger<UnitOfWork<TContext>> _logger;
|
private readonly ILogger<UnitOfWork<TContext>> _logger;
|
||||||
@ -34,10 +34,11 @@ public class UnitOfWork<TContext> : IUnitOfWork where TContext : DbContext
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
|
// ReSharper disable once GCSuppressFinalizeForTypeWithoutDestructor
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
<IsPackable>false</IsPackable>
|
<IsPackable>false</IsPackable>
|
||||||
|
@ -1,4 +1,8 @@
|
|||||||
using System.Net;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Application.ViewModels.Users;
|
using CleanArchitecture.Application.ViewModels.Users;
|
||||||
using CleanArchitecture.IntegrationTests.Extensions;
|
using CleanArchitecture.IntegrationTests.Extensions;
|
||||||
using CleanArchitecture.IntegrationTests.Fixtures;
|
using CleanArchitecture.IntegrationTests.Fixtures;
|
||||||
@ -8,7 +12,7 @@ using Xunit.Priority;
|
|||||||
|
|
||||||
namespace CleanArchitecture.IntegrationTests.Controller;
|
namespace CleanArchitecture.IntegrationTests.Controller;
|
||||||
|
|
||||||
[Collection("Integrationtests")]
|
[Collection("IntegrationTests")]
|
||||||
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
[TestCaseOrderer(PriorityOrderer.Name, PriorityOrderer.Assembly)]
|
||||||
public sealed class UserControllerTests : IClassFixture<UserTestFixture>
|
public sealed class UserControllerTests : IClassFixture<UserTestFixture>
|
||||||
{
|
{
|
||||||
@ -122,7 +126,7 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
|
|||||||
|
|
||||||
message?.Data.Should().NotBeNull();
|
message?.Data.Should().NotBeNull();
|
||||||
|
|
||||||
var content = message!.Data!;
|
var content = message!.Data!.ToList();
|
||||||
|
|
||||||
content.Should().ContainSingle();
|
content.Should().ContainSingle();
|
||||||
content.First().Id.Should().Be(_fixture.CreatedUserId);
|
content.First().Id.Should().Be(_fixture.CreatedUserId);
|
||||||
@ -142,7 +146,7 @@ public sealed class UserControllerTests : IClassFixture<UserTestFixture>
|
|||||||
|
|
||||||
message?.Data.Should().NotBeEmpty();
|
message?.Data.Should().NotBeEmpty();
|
||||||
|
|
||||||
var content = message!.Data!;
|
var content = message!.Data;
|
||||||
content.Should().Be(_fixture.CreatedUserId);
|
content.Should().Be(_fixture.CreatedUserId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using System.Data.Common;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Common;
|
||||||
|
using System.Linq;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
@ -17,7 +20,7 @@ public static class FunctionalTestsServiceCollectionExtensions
|
|||||||
services.AddScoped(p =>
|
services.AddScoped(p =>
|
||||||
DbContextOptionsFactory<TContext>(
|
DbContextOptionsFactory<TContext>(
|
||||||
p,
|
p,
|
||||||
(sp, options) => options
|
(_, options) => options
|
||||||
.ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning))
|
.ConfigureWarnings(b => b.Log(CoreEventId.ManyServiceProvidersCreatedWarning))
|
||||||
.UseLazyLoadingProxies()
|
.UseLazyLoadingProxies()
|
||||||
.UseSqlite(connection)));
|
.UseSqlite(connection)));
|
||||||
@ -35,7 +38,7 @@ public static class FunctionalTestsServiceCollectionExtensions
|
|||||||
|
|
||||||
builder.UseApplicationServiceProvider(applicationServiceProvider);
|
builder.UseApplicationServiceProvider(applicationServiceProvider);
|
||||||
|
|
||||||
optionsAction?.Invoke(applicationServiceProvider, builder);
|
optionsAction.Invoke(applicationServiceProvider, builder);
|
||||||
|
|
||||||
return builder.Options;
|
return builder.Options;
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
using System.Text;
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using CleanArchitecture.Api.Models;
|
using CleanArchitecture.Api.Models;
|
||||||
|
|
||||||
namespace CleanArchitecture.IntegrationTests.Extensions;
|
namespace CleanArchitecture.IntegrationTests.Extensions;
|
||||||
|
|
||||||
public static class HttpExensions
|
public static class HttpExtensions
|
||||||
{
|
{
|
||||||
public static JsonSerializerOptions JsonSerializerOptions = new()
|
private static readonly JsonSerializerOptions JsonSerializerOptions = new()
|
||||||
{
|
{
|
||||||
PropertyNameCaseInsensitive = true,
|
PropertyNameCaseInsensitive = true,
|
||||||
};
|
};
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
using CleanArchitecture.Infrastructure.Database;
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net.Http;
|
||||||
|
using CleanArchitecture.Infrastructure.Database;
|
||||||
using CleanArchitecture.IntegrationTests.Infrastructure;
|
using CleanArchitecture.IntegrationTests.Infrastructure;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
namespace CleanArchitecture.IntegrationTests.Fixtures;
|
using System;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.IntegrationTests.Fixtures;
|
||||||
|
|
||||||
public sealed class UserTestFixture : TestFixtureBase
|
public sealed class UserTestFixture : TestFixtureBase
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
using CleanArchitecture.Infrastructure.Database;
|
using System;
|
||||||
|
using CleanArchitecture.Infrastructure.Database;
|
||||||
using CleanArchitecture.Infrastructure.Extensions;
|
using CleanArchitecture.Infrastructure.Extensions;
|
||||||
using CleanArchitecture.IntegrationTests.Extensions;
|
using CleanArchitecture.IntegrationTests.Extensions;
|
||||||
using Microsoft.AspNetCore.Hosting;
|
using Microsoft.AspNetCore.Hosting;
|
||||||
|
24
CleanArchitecture.Proto/CleanArchitecture.Proto.csproj
Normal file
24
CleanArchitecture.Proto/CleanArchitecture.Proto.csproj
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove="Users\Models.proto"/>
|
||||||
|
<None Remove="Users\UsersApi.proto"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Protobuf Include="Users\Models.proto" GrpcServices="Both"/>
|
||||||
|
<Protobuf Include="Users\UsersApi.proto" GrpcServices="Both"/>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Google.Protobuf" Version="3.22.1" />
|
||||||
|
<PackageReference Include="Google.Protobuf.Tools" Version="3.22.1" />
|
||||||
|
<PackageReference Include="Grpc.AspNetCore" Version="2.51.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
11
CleanArchitecture.Proto/Users/Models.proto
Normal file
11
CleanArchitecture.Proto/Users/Models.proto
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option csharp_namespace = "CleanArchitecture.Proto.Users";
|
||||||
|
|
||||||
|
message GrpcUser {
|
||||||
|
string id = 1;
|
||||||
|
string firstName = 3;
|
||||||
|
string lastName = 4;
|
||||||
|
string email = 5;
|
||||||
|
bool isDeleted = 6;
|
||||||
|
}
|
17
CleanArchitecture.Proto/Users/UsersApi.proto
Normal file
17
CleanArchitecture.Proto/Users/UsersApi.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
option csharp_namespace = "CleanArchitecture.Proto.Users";
|
||||||
|
|
||||||
|
import "Users/Models.proto";
|
||||||
|
|
||||||
|
service UsersApi {
|
||||||
|
rpc GetByIds(GetByIdsRequest) returns (GetByIdsResult);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetByIdsResult {
|
||||||
|
repeated GrpcUser users = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetByIdsRequest {
|
||||||
|
repeated string ids = 1;
|
||||||
|
}
|
@ -0,0 +1,31 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="FluentAssertions" Version="6.10.0" />
|
||||||
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2" />
|
||||||
|
<PackageReference Include="MockQueryable.Moq" Version="7.0.0" />
|
||||||
|
<PackageReference Include="Moq" Version="4.18.4" />
|
||||||
|
<PackageReference Include="xunit" Version="2.4.2" />
|
||||||
|
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
<PackageReference Include="coverlet.collector" Version="3.1.2">
|
||||||
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
|
<PrivateAssets>all</PrivateAssets>
|
||||||
|
</PackageReference>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
36
CleanArchitecture.gRPC.Tests/Fixtures/UserTestsFixture.cs
Normal file
36
CleanArchitecture.gRPC.Tests/Fixtures/UserTestsFixture.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using CleanArchitecture.Domain.Entities;
|
||||||
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
|
using MockQueryable.Moq;
|
||||||
|
using Moq;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.gRPC.Tests.Fixtures;
|
||||||
|
|
||||||
|
public sealed class UserTestsFixture
|
||||||
|
{
|
||||||
|
private Mock<IUserRepository> UserRepository { get; } = new ();
|
||||||
|
|
||||||
|
public UsersApiImplementation UsersApiImplementation { get; }
|
||||||
|
|
||||||
|
public IEnumerable<User> ExistingUsers { get; }
|
||||||
|
|
||||||
|
public UserTestsFixture()
|
||||||
|
{
|
||||||
|
ExistingUsers = new List<User>()
|
||||||
|
{
|
||||||
|
new (Guid.NewGuid(), "test@test.de", "Test First Name", "Test Last Name"),
|
||||||
|
new (Guid.NewGuid(), "email@Email.de", "Email First Name", "Email Last Name"),
|
||||||
|
new (Guid.NewGuid(), "user@user.de", "User First Name", "User Last Name"),
|
||||||
|
};
|
||||||
|
|
||||||
|
var queryable = ExistingUsers.AsQueryable().BuildMock();
|
||||||
|
|
||||||
|
UserRepository
|
||||||
|
.Setup(repository => repository.GetAllNoTracking())
|
||||||
|
.Returns(queryable);
|
||||||
|
|
||||||
|
UsersApiImplementation = new UsersApiImplementation(UserRepository.Object);
|
||||||
|
}
|
||||||
|
}
|
74
CleanArchitecture.gRPC.Tests/Users/GetUsersByIdsTests.cs
Normal file
74
CleanArchitecture.gRPC.Tests/Users/GetUsersByIdsTests.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.gRPC.Tests.Fixtures;
|
||||||
|
using CleanArchitecture.Proto.Users;
|
||||||
|
using FluentAssertions;
|
||||||
|
using Xunit;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.gRPC.Tests.Users;
|
||||||
|
|
||||||
|
public sealed class GetUsersByIdsTests : IClassFixture<UserTestsFixture>
|
||||||
|
{
|
||||||
|
private readonly UserTestsFixture _fixture;
|
||||||
|
|
||||||
|
public GetUsersByIdsTests(UserTestsFixture fixture)
|
||||||
|
{
|
||||||
|
_fixture = fixture;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Should_Get_Empty_List_If_No_Ids_Are_Given()
|
||||||
|
{
|
||||||
|
var result = await _fixture.UsersApiImplementation.GetByIds(
|
||||||
|
SetupRequest(Enumerable.Empty<Guid>()),
|
||||||
|
null!);
|
||||||
|
|
||||||
|
result.Users.Should().HaveCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public async Task Should_Get_Requested_Asked_Ids()
|
||||||
|
{
|
||||||
|
var nonExistingId = Guid.NewGuid();
|
||||||
|
|
||||||
|
var ids = _fixture.ExistingUsers
|
||||||
|
.Take(2)
|
||||||
|
.Select(user => user.Id)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
ids.Add(nonExistingId);
|
||||||
|
|
||||||
|
var result = await _fixture.UsersApiImplementation.GetByIds(
|
||||||
|
SetupRequest(ids),
|
||||||
|
null!);
|
||||||
|
|
||||||
|
result.Users.Should().HaveCount(2);
|
||||||
|
|
||||||
|
foreach (var user in result.Users)
|
||||||
|
{
|
||||||
|
var userId = Guid.Parse(user.Id);
|
||||||
|
|
||||||
|
userId.Should().NotBe(nonExistingId);
|
||||||
|
|
||||||
|
var mockUser = _fixture.ExistingUsers.First(u => u.Id == userId);
|
||||||
|
|
||||||
|
mockUser.Should().NotBeNull();
|
||||||
|
|
||||||
|
user.Email.Should().Be(mockUser.Email);
|
||||||
|
user.FirstName.Should().Be(mockUser.GivenName);
|
||||||
|
user.LastName.Should().Be(mockUser.Surname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static GetByIdsRequest SetupRequest(IEnumerable<Guid> ids)
|
||||||
|
{
|
||||||
|
var request = new GetByIdsRequest();
|
||||||
|
|
||||||
|
request.Ids.AddRange(ids.Select(id => id.ToString()));
|
||||||
|
request.Ids.Add("Not a guid");
|
||||||
|
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
}
|
17
CleanArchitecture.gRPC/CleanArchitecture.gRPC.csproj
Normal file
17
CleanArchitecture.gRPC/CleanArchitecture.gRPC.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\CleanArchitecture.Domain\CleanArchitecture.Domain.csproj" />
|
||||||
|
<ProjectReference Include="..\CleanArchitecture.Proto\CleanArchitecture.Proto.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.EntityFrameworkCore" Version="7.0.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
54
CleanArchitecture.gRPC/UsersApiImplementation.cs
Normal file
54
CleanArchitecture.gRPC/UsersApiImplementation.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using CleanArchitecture.Domain.Interfaces.Repositories;
|
||||||
|
using CleanArchitecture.Proto.Users;
|
||||||
|
using Grpc.Core;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace CleanArchitecture.gRPC;
|
||||||
|
|
||||||
|
public sealed class UsersApiImplementation : UsersApi.UsersApiBase
|
||||||
|
{
|
||||||
|
private readonly IUserRepository _userRepository;
|
||||||
|
|
||||||
|
public UsersApiImplementation(IUserRepository userRepository)
|
||||||
|
{
|
||||||
|
_userRepository = userRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override async Task<GetByIdsResult> GetByIds(
|
||||||
|
GetByIdsRequest request,
|
||||||
|
ServerCallContext context)
|
||||||
|
{
|
||||||
|
var idsAsGuids = new List<Guid>(request.Ids.Count);
|
||||||
|
|
||||||
|
foreach (var id in request.Ids)
|
||||||
|
{
|
||||||
|
if (Guid.TryParse(id, out var parsed))
|
||||||
|
{
|
||||||
|
idsAsGuids.Add(parsed);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var users = await _userRepository
|
||||||
|
.GetAllNoTracking()
|
||||||
|
.Where(user => idsAsGuids.Contains(user.Id))
|
||||||
|
.Select(user => new GrpcUser
|
||||||
|
{
|
||||||
|
Id = user.Id.ToString(),
|
||||||
|
Email = user.Email,
|
||||||
|
FirstName = user.GivenName,
|
||||||
|
LastName = user.Surname,
|
||||||
|
IsDeleted = user.Deleted
|
||||||
|
})
|
||||||
|
.ToListAsync();
|
||||||
|
|
||||||
|
var result = new GetByIdsResult();
|
||||||
|
|
||||||
|
result.Users.AddRange(users);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -16,6 +16,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.Infrastru
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.IntegrationTests", "CleanArchitecture.IntegrationTests\CleanArchitecture.IntegrationTests.csproj", "{39732BD4-909F-410C-8737-1F9FE3E269A7}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.IntegrationTests", "CleanArchitecture.IntegrationTests\CleanArchitecture.IntegrationTests.csproj", "{39732BD4-909F-410C-8737-1F9FE3E269A7}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.gRPC", "CleanArchitecture.gRPC\CleanArchitecture.gRPC.csproj", "{7A6353A9-B60C-4B13-A849-D21B315047EE}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.Proto", "CleanArchitecture.Proto\CleanArchitecture.Proto.csproj", "{5F978903-7A7A-45C2-ABE0-C2906ECD326B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.gRPC.Tests", "CleanArchitecture.gRPC.Tests\CleanArchitecture.gRPC.Tests.csproj", "{E3A836DD-85DB-44FD-BC19-DDFE111D9EB0}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -54,5 +60,17 @@ Global
|
|||||||
{39732BD4-909F-410C-8737-1F9FE3E269A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{39732BD4-909F-410C-8737-1F9FE3E269A7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{39732BD4-909F-410C-8737-1F9FE3E269A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{39732BD4-909F-410C-8737-1F9FE3E269A7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{39732BD4-909F-410C-8737-1F9FE3E269A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
{39732BD4-909F-410C-8737-1F9FE3E269A7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7A6353A9-B60C-4B13-A849-D21B315047EE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7A6353A9-B60C-4B13-A849-D21B315047EE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7A6353A9-B60C-4B13-A849-D21B315047EE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7A6353A9-B60C-4B13-A849-D21B315047EE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5F978903-7A7A-45C2-ABE0-C2906ECD326B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5F978903-7A7A-45C2-ABE0-C2906ECD326B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5F978903-7A7A-45C2-ABE0-C2906ECD326B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5F978903-7A7A-45C2-ABE0-C2906ECD326B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E3A836DD-85DB-44FD-BC19-DDFE111D9EB0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E3A836DD-85DB-44FD-BC19-DDFE111D9EB0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E3A836DD-85DB-44FD-BC19-DDFE111D9EB0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E3A836DD-85DB-44FD-BC19-DDFE111D9EB0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
Loading…
Reference in New Issue
Block a user