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