diff --git a/CleanArchitecture.Api/Program.cs b/CleanArchitecture.Api/Program.cs index 3678e19..c4f97be 100644 --- a/CleanArchitecture.Api/Program.cs +++ b/CleanArchitecture.Api/Program.cs @@ -1,7 +1,7 @@ using CleanArchitecture.Api.Extensions; using CleanArchitecture.Application.Extensions; +using CleanArchitecture.Application.gRPC; using CleanArchitecture.Domain.Extensions; -using CleanArchitecture.gRPC; using CleanArchitecture.Infrastructure.Database; using CleanArchitecture.Infrastructure.Extensions; using Microsoft.AspNetCore.Builder; diff --git a/CleanArchitecture.Application/CleanArchitecture.Application.csproj b/CleanArchitecture.Application/CleanArchitecture.Application.csproj index 2b5f8ef..1fcc7a9 100644 --- a/CleanArchitecture.Application/CleanArchitecture.Application.csproj +++ b/CleanArchitecture.Application/CleanArchitecture.Application.csproj @@ -6,11 +6,12 @@ - + - + + diff --git a/CleanArchitecture.gRPC/UsersApiImplementation.cs b/CleanArchitecture.Application/gRPC/UsersApiImplementation.cs similarity index 96% rename from CleanArchitecture.gRPC/UsersApiImplementation.cs rename to CleanArchitecture.Application/gRPC/UsersApiImplementation.cs index 279bdfc..97e1b11 100644 --- a/CleanArchitecture.gRPC/UsersApiImplementation.cs +++ b/CleanArchitecture.Application/gRPC/UsersApiImplementation.cs @@ -7,7 +7,7 @@ using CleanArchitecture.Proto.Users; using Grpc.Core; using Microsoft.EntityFrameworkCore; -namespace CleanArchitecture.gRPC; +namespace CleanArchitecture.Application.gRPC; public sealed class UsersApiImplementation : UsersApi.UsersApiBase { diff --git a/CleanArchitecture.Proto/Users/Models.proto b/CleanArchitecture.Proto/Users/Models.proto index b627309..03e59a7 100644 --- a/CleanArchitecture.Proto/Users/Models.proto +++ b/CleanArchitecture.Proto/Users/Models.proto @@ -8,4 +8,12 @@ message GrpcUser { string lastName = 4; string email = 5; bool isDeleted = 6; +} + +message GetByIdsResult { + repeated GrpcUser users = 1; +} + +message GetByIdsRequest { + repeated string ids = 1; } \ No newline at end of file diff --git a/CleanArchitecture.Proto/Users/UsersApi.proto b/CleanArchitecture.Proto/Users/UsersApi.proto index 557b028..e718218 100644 --- a/CleanArchitecture.Proto/Users/UsersApi.proto +++ b/CleanArchitecture.Proto/Users/UsersApi.proto @@ -7,11 +7,3 @@ import "Users/Models.proto"; service UsersApi { rpc GetByIds(GetByIdsRequest) returns (GetByIdsResult); } - -message GetByIdsResult { - repeated GrpcUser users = 1; -} - -message GetByIdsRequest { - repeated string ids = 1; -} diff --git a/CleanArchitecture.Shared/CleanArchitecture.Shared.csproj b/CleanArchitecture.Shared/CleanArchitecture.Shared.csproj new file mode 100644 index 0000000..de3c61c --- /dev/null +++ b/CleanArchitecture.Shared/CleanArchitecture.Shared.csproj @@ -0,0 +1,8 @@ + + + + net7.0 + enable + + + diff --git a/CleanArchitecture.Shared/Users/UserViewModel.cs b/CleanArchitecture.Shared/Users/UserViewModel.cs new file mode 100644 index 0000000..c183ded --- /dev/null +++ b/CleanArchitecture.Shared/Users/UserViewModel.cs @@ -0,0 +1,10 @@ +using System; + +namespace CleanArchitecture.Shared.Users; + +public sealed record UserViewModel( + Guid Id, + string Email, + string FirstName, + string LastName, + bool IsDeleted); diff --git a/CleanArchitecture.gRPC.Tests/CleanArchitecture.gRPC.Tests.csproj b/CleanArchitecture.gRPC.Tests/CleanArchitecture.gRPC.Tests.csproj index b6443c4..bf35a75 100644 --- a/CleanArchitecture.gRPC.Tests/CleanArchitecture.gRPC.Tests.csproj +++ b/CleanArchitecture.gRPC.Tests/CleanArchitecture.gRPC.Tests.csproj @@ -8,11 +8,11 @@ - - - - - + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive all @@ -24,8 +24,9 @@ - - + + + diff --git a/CleanArchitecture.gRPC.Tests/Fixtures/UserTestsFixture.cs b/CleanArchitecture.gRPC.Tests/Fixtures/UserTestsFixture.cs index 5b04bef..a6f8245 100644 --- a/CleanArchitecture.gRPC.Tests/Fixtures/UserTestsFixture.cs +++ b/CleanArchitecture.gRPC.Tests/Fixtures/UserTestsFixture.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using CleanArchitecture.Application.gRPC; using CleanArchitecture.Domain.Entities; using CleanArchitecture.Domain.Enums; using CleanArchitecture.Domain.Interfaces.Repositories; diff --git a/CleanArchitecture.gRPC/CleanArchitecture.cs b/CleanArchitecture.gRPC/CleanArchitecture.cs new file mode 100644 index 0000000..649b2fc --- /dev/null +++ b/CleanArchitecture.gRPC/CleanArchitecture.cs @@ -0,0 +1,15 @@ +using CleanArchitecture.gRPC.Interfaces; + +namespace CleanArchitecture.gRPC; + +public sealed class CleanArchitecture : ICleanArchitecture +{ + private readonly IUsersContext _users; + + public IUsersContext Users => _users; + + public CleanArchitecture(IUsersContext users) + { + _users = users; + } +} diff --git a/CleanArchitecture.gRPC/CleanArchitecture.gRPC.csproj b/CleanArchitecture.gRPC/CleanArchitecture.gRPC.csproj index 1268e7f..1bec38c 100644 --- a/CleanArchitecture.gRPC/CleanArchitecture.gRPC.csproj +++ b/CleanArchitecture.gRPC/CleanArchitecture.gRPC.csproj @@ -1,4 +1,4 @@ - + net7.0 @@ -6,12 +6,9 @@ - - - - - - + + + diff --git a/CleanArchitecture.gRPC/Contexts/UsersContext.cs b/CleanArchitecture.gRPC/Contexts/UsersContext.cs new file mode 100644 index 0000000..4822231 --- /dev/null +++ b/CleanArchitecture.gRPC/Contexts/UsersContext.cs @@ -0,0 +1,35 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using CleanArchitecture.gRPC.Interfaces; +using CleanArchitecture.Proto.Users; +using CleanArchitecture.Shared.Users; + +namespace CleanArchitecture.gRPC.Contexts; + +public sealed class UsersContext : IUsersContext +{ + private readonly UsersApi.UsersApiClient _client; + + public UsersContext(UsersApi.UsersApiClient client) + { + _client = client; + } + + public async Task> GetUsersByIds(IEnumerable ids) + { + var request = new GetByIdsRequest(); + + request.Ids.AddRange(ids.Select(id => id.ToString())); + + var result = await _client.GetByIdsAsync(request); + + return result.Users.Select(user => new UserViewModel( + Guid.Parse(user.Id), + user.Email, + user.FirstName, + user.LastName, + user.IsDeleted)); + } +} diff --git a/CleanArchitecture.gRPC/Extensions/ServiceCollectionExtensions.cs b/CleanArchitecture.gRPC/Extensions/ServiceCollectionExtensions.cs new file mode 100644 index 0000000..72d5c3c --- /dev/null +++ b/CleanArchitecture.gRPC/Extensions/ServiceCollectionExtensions.cs @@ -0,0 +1,54 @@ +using CleanArchitecture.gRPC.Contexts; +using CleanArchitecture.gRPC.Interfaces; +using CleanArchitecture.gRPC.Models; +using CleanArchitecture.Proto.Users; +using Grpc.Net.Client; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace CleanArchitecture.gRPC.Extensions; + +public static class ServiceCollectionExtensions +{ + public static IServiceCollection AddGrpcClient( + this IServiceCollection services, + IConfiguration configuration, + string configSectionKey = "gRPC") + { + var settings = new GRPCSettings(); + configuration.Bind(configSectionKey, settings); + + return AddGrpcClient(services, settings); + } + + public static IServiceCollection AddGrpcClient(this IServiceCollection services, GRPCSettings settings) + { + if (!string.IsNullOrWhiteSpace(settings.CleanArchitectureUrl)) + { + services.AddCleanArchitectureGrpcClient(settings.CleanArchitectureUrl); + } + + services.AddSingleton(); + + return services; + } + + public static IServiceCollection AddCleanArchitectureGrpcClient( + this IServiceCollection services, + string tetraQueryApiUrl) + { + if (string.IsNullOrWhiteSpace(tetraQueryApiUrl)) + { + return services; + } + + var channel = GrpcChannel.ForAddress(tetraQueryApiUrl); + + var usersClient = new UsersApi.UsersApiClient(channel); + services.AddSingleton(usersClient); + + services.AddSingleton(); + + return services; + } +} diff --git a/CleanArchitecture.gRPC/ICleanArchitecture.cs b/CleanArchitecture.gRPC/ICleanArchitecture.cs new file mode 100644 index 0000000..94acbb7 --- /dev/null +++ b/CleanArchitecture.gRPC/ICleanArchitecture.cs @@ -0,0 +1,9 @@ +using System; +using CleanArchitecture.gRPC.Interfaces; + +namespace CleanArchitecture.gRPC; + +public interface ICleanArchitecture +{ + IUsersContext Users { get; } +} diff --git a/CleanArchitecture.gRPC/Interfaces/IUsersContext.cs b/CleanArchitecture.gRPC/Interfaces/IUsersContext.cs new file mode 100644 index 0000000..f1f2f04 --- /dev/null +++ b/CleanArchitecture.gRPC/Interfaces/IUsersContext.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using CleanArchitecture.Shared.Users; + +namespace CleanArchitecture.gRPC.Interfaces; + +public interface IUsersContext +{ + Task> GetUsersByIds(IEnumerable ids); +} diff --git a/CleanArchitecture.gRPC/Models/GRPCSettings.cs b/CleanArchitecture.gRPC/Models/GRPCSettings.cs new file mode 100644 index 0000000..fd7a02c --- /dev/null +++ b/CleanArchitecture.gRPC/Models/GRPCSettings.cs @@ -0,0 +1,6 @@ +namespace CleanArchitecture.gRPC.Models; + +public sealed class GRPCSettings +{ + public string CleanArchitectureUrl { get; set; } = string.Empty; +} diff --git a/CleanArchitecture.sln b/CleanArchitecture.sln index 1209ff0..3e8b93c 100644 --- a/CleanArchitecture.sln +++ b/CleanArchitecture.sln @@ -27,6 +27,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CleanArchitecture.gRPC.Test EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D3DF9DF5-BD7D-48BC-8BE6-DBD0FABB8B45}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CleanArchitecture.Shared", "CleanArchitecture.Shared\CleanArchitecture.Shared.csproj", "{E82B473D-0281-4713-9550-7D3FF7D9CFDE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -77,6 +79,10 @@ Global {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 + {E82B473D-0281-4713-9550-7D3FF7D9CFDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E82B473D-0281-4713-9550-7D3FF7D9CFDE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E82B473D-0281-4713-9550-7D3FF7D9CFDE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E82B473D-0281-4713-9550-7D3FF7D9CFDE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -88,4 +94,7 @@ Global {39732BD4-909F-410C-8737-1F9FE3E269A7} = {D3DF9DF5-BD7D-48BC-8BE6-DBD0FABB8B45} {E3A836DD-85DB-44FD-BC19-DDFE111D9EB0} = {D3DF9DF5-BD7D-48BC-8BE6-DBD0FABB8B45} EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {DDAAEEA0-FB1B-4EAD-902B-C12034FFC17A} + EndGlobalSection EndGlobal