Umbrella Question
In an onion architecture, where do all the components needed to consume an external API fit in?
The following is the architecture I have so far, based off an example found here: https://github.com/CodeMazeBlog/onion-architecture-aspnetcore/
Requirements
I'm now trying to test out this architecture by writing code to fulfill these requirements:
- Call Microsoft Graph. get the current list of teams in a specific tenant.
- For each team i get back, save some of the fields to a local database. We also have other custom fields that we want to save for each team.
- Make the latest data we saved in the database available as a "report".
For example, here's what you get from Graph:
"value": [
{
"reportRefreshDate": "2021-09-01",
"teamName": "sampleTeam",
"teamId": "a063d832-ae9a-467d-8cb4-17c073260890",
"teamType": "Private",
"lastActivityDate": "2021-09-01",
"details": [
{
"reportPeriod":7,
"activeUsers": 26,
"activeChannels": 17,
"guests": 4,
"reactions": 36,
"meetingsOrganized": 0,
"postMessages": 0,
"replyMessages": 0,
"channelMessages": 0,
"urgentMessages": 0,
"mentions": 0,
"activeSharedChannels": "6",
"activeExternalUsers": "8"
}
]
}
]
And these are the fields I want to save:
"LastSynchronizedDate": "2021-09-01",
"teamName": "sampleTeam",
"teamId": "a063d832-ae9a-467d-8cb4-17c073260890",
"teamType": "Private",
"lastActivityDate": "2021-09-01",
"details": [
{
"activeUsers": 26,
"activeChannels": 17,
"guests": 4,
"activeSharedChannels": "6",
"activeExternalUsers": "8",
"mycustomfield1": "8",
"mycustomfield2": "somestringvalue"
}
Components
Using the structure shown in the screen shot can you help me vet my design as far as where I'm going to put everything? Assuming the folder structure is fixed, I'd like to make sure that I'm populating each folder with the correct type of logic.
I'm thinking of creating the following files
database model and methods that contains my definition of what a team is. This will contain methods with business logic to manipulate my version of a team. "Domain->Entities->MyTeam.cs"
a model of what MS Graph returns in the report. My understanding is that DTOs are basically db models. So in my case, this would represents what the data will look from Graph. Can this 'model' also include methods to manipulate the json data from Graph? or just the model of record itself? "Contracts->GraphTeamModelDTO.cs"
a model of my local team.
"Contracts -> MyTeamDto.cs"An interface to my local database's team's table "Domain->Repositories-> IMyTeamRepository.cs"
public interface IO365TeamRepository { Task<IEnumerable> GetAllAsync(CancellationToken cancellationToken = default);
a new internal sealed class that will allow something to call "synchronize teams data" to trigger the call to graph. This class is what will use the DTO.
"Services >TeamsManagementService.cs**
public Task<IEnumerable<TeamFromGraphDto>> SynchronizeTeamsForTenant(int tenantId, CancellationToken cancellationToken = default) { }
a corresponding public service interface that the presentation layer will rely on to trigger this entire process /report "Services.Abstractions ->ITeamsManagementService.cs**
Concrete class that implements the database methods to get at my local teams table "Infrastructure -> Persistence -> Repository -> MyTeamRepository.cs"
a controller that exposes an API so clients can call my service. Presentation -> Controller -> TeamManagement.cs
[ApiController] [Route("api/beta/reporting/teams/{tenantId:int}")] public class TeamsManagement: ControllerBase { private readonly IServiceManager _serviceManager;
public TeamsManagement(IServiceManager serviceManager) => _serviceManager = serviceManager; [HttpGet] public async Task<IActionResult> SynchronizeTeams(int tenantId, CancellationToken cancellationToken) { var teams = await _serviceManager.TeamManagementService.SynchronizeTeamsForTenant(tenantId, cancellationToken); return Ok(teams); }
What's Missing
I don't know exactly where to put the following objects:
concrete class that creates a ms graph client using their library. I think it should be something like: "Infrastructure -> ExternalAPIs -> Graph ->MyGraphServiceClient.cs"
the related interface that I think will be consumed by my TeamsManagement service: "Service.Abstractions -> IMyGraphServiceClient.cs"
Does this sound reasonable / correct? I'm in the middle of writing the actual logic to test this out... But i thought i'd ask for community input as well before I get too far along - in case I've strayed.