-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Farshad DASHTI
authored and
Farshad DASHTI
committed
Oct 3, 2024
1 parent
d5f507a
commit d87a4e6
Showing
7 changed files
with
376 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,96 @@ | ||
# DfE.CoreLibs | ||
|
||
DfE Core Libraries | ||
================== | ||
|
||
This repository consists of a .NET solution containing multiple class libraries, with each library published as a standalone NuGet package. The libraries follow the naming convention: `DfE.CoreLibs.{library_name}`. | ||
|
||
Adding a New Library to the Repository | ||
-------------------------------------- | ||
|
||
To add a new library to this repository and automatically publish it as a NuGet package, follow these steps: | ||
|
||
1. **Create a new library** in the `src` folder in the root of the solution. | ||
2. **Copy the two YAML workflow files** used for other libraries (e.g., from `Caching`) into your new library directory, and modify them as needed to match your new library. | ||
|
||
### File 1: `build-test-{library_name}.yml` | ||
|
||
For example, if your new library is called "FileService," name the file `build-test-FileService.yml`. | ||
|
||
#### Example Content (Replace with your library name): | ||
|
||
```yaml | ||
name: Build DfE.CoreLibs.FileService | ||
|
||
on: | ||
push: | ||
branches: | ||
- main | ||
paths: | ||
- 'src/DfE.CoreLibs.FileService/**' | ||
|
||
jobs: | ||
build-and-test: | ||
uses: ./.github/workflows/build-test-template.yml | ||
with: | ||
project_name: DfE.CoreLibs.FileService | ||
project_path: src/DfE.CoreLibs.FileService | ||
sonar_project_key: DFE-Digital_corelibs-fileservice | ||
secrets: | ||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} | ||
``` | ||
Make sure to: | ||
* Replace `DfE.CoreLibs.FileService` with your new library name. | ||
* Ensure the path to the new library is correct. | ||
|
||
### File 2: `pack-{library_name}.yml` | ||
|
||
For example, name the file `pack-FileService.yml` for your new library. | ||
|
||
#### Example Content (Replace with your library name): | ||
|
||
```yaml | ||
name: Pack DfE.CoreLibs.FileService | ||
on: | ||
workflow_run: | ||
workflows: ["Build DfE.CoreLibs.FileService"] | ||
types: | ||
- completed | ||
jobs: | ||
build-and-package: | ||
uses: ./.github/workflows/nuget-package-template.yml | ||
with: | ||
project_name: DfE.CoreLibs.FileService | ||
project_path: src/DfE.CoreLibs.FileService | ||
nuget_package_name: DfE.CoreLibs.FileService | ||
``` | ||
|
||
|
||
Workflows Explanation | ||
--------------------- | ||
|
||
* **Build and Test Workflow** (`build-test-{library_name}.yml`): This workflow is responsible for building and testing your library. | ||
* **Pack Workflow** (`pack-{library_name}.yml`): This workflow handles versioning and packaging of your library, but it only runs after the build and test workflow successfully completes. | ||
|
||
Versioning and Auto-Publishing | ||
------------------------------ | ||
|
||
* **Initial Versioning:** The first time your library is published, the version will start at `1.0.0`. | ||
* **Automatic Increment:** With subsequent changes, the patch version will increment automatically (e.g., `1.0.1`, `1.0.2`, and so on). | ||
* **Custom Version Bumps:** To bump the **minor** or **major** version of your library, follow these steps: | ||
1. Make the necessary changes in your library. | ||
2. Commit your changes with a message like the following: | ||
|
||
(#update {Project_Name} package version to {version_number}) | ||
|
||
Example: | ||
|
||
(#update DfE.CoreLibs.FileService package version to 1.1.0) | ||
|
||
|
||
The packaging workflow will then automatically set the version to `1.1.0` and increment the patch part (`1.1.x`) with each further change. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
# DfE.CoreLibs.BackgroundService | ||
|
||
This library provides a robust framework for implementing long-running background tasks in .NET applications. It simplifies the development of background services by offering reusable components that streamline task scheduling, execution, and error handling. Ideal for any project requiring background processing, it ensures reliability and scalability across different environments. | ||
|
||
## Installation | ||
|
||
To install the DfE.CoreLibs.BackgroundService Library, use the following command in your .NET project: | ||
|
||
```sh | ||
dotnet add package DfE.CoreLibs.BackgroundService | ||
``` | ||
|
||
## Usage | ||
|
||
|
||
**Usage in a Command Handler** | ||
|
||
1. **Service Registration:** You use a background service factory to enqueue tasks. Register the factory in your `Program.cs`: | ||
|
||
```csharp | ||
public void ConfigureServices(IServiceCollection services) | ||
{ | ||
services.AddBackgroundService(); | ||
} | ||
``` | ||
|
||
|
||
2. **Implementation in the Handler:** You enqueue tasks using `IBackgroundServiceFactory` directly inside a command handler, optionally you can pass in an event to be raised when the task is completed, as shown in your code: | ||
|
||
```csharp | ||
public class CreateReportCommandHandler : IRequestHandler<CreateReportCommand, bool> | ||
{ | ||
private readonly IBackgroundServiceFactory _backgroundServiceFactory; | ||
|
||
public CreateReportCommandHandler(IBackgroundServiceFactory backgroundServiceFactory) | ||
{ | ||
_backgroundServiceFactory = backgroundServiceFactory; | ||
} | ||
|
||
public Task<bool> Handle(CreateReportCommand request, CancellationToken cancellationToken) | ||
{ | ||
var taskName = "Create_Report_Task1"; | ||
|
||
_backgroundServiceFactory.EnqueueTask( | ||
async () => await (new CreateReportExampleTask()).RunAsync(taskName), | ||
result => new CreateReportExampleTaskCompletedEvent(taskName, result) | ||
); | ||
|
||
return Task.FromResult(true); | ||
} | ||
} | ||
``` | ||
|
||
3. **Events:** The background service triggers events when a task is completed. For example: | ||
|
||
```csharp | ||
public class CreateReportExampleTaskCompletedEvent : IBackgroundServiceEvent | ||
{ | ||
public string TaskName { get; } | ||
public string Message { get; } | ||
|
||
public CreateReportExampleTaskCompletedEvent(string taskName, string message) | ||
{ | ||
TaskName = taskName; | ||
Message = message; | ||
} | ||
} | ||
``` | ||
|
||
4. **Event Handlers:** These events are processed by event handlers. Here's an example of how you handle task completion events: | ||
|
||
```csharp | ||
public class SimpleTaskCompletedEventHandler : IBackgroundServiceEventHandler<CreateReportExampleTaskCompletedEvent> | ||
{ | ||
public Task Handle(CreateReportExampleTaskCompletedEvent notification, CancellationToken cancellationToken) | ||
{ | ||
Console.WriteLine($"Event received for Task: {notification.TaskName}, Message: {notification.Message}"); | ||
return Task.CompletedTask; | ||
} | ||
} | ||
``` | ||
|
||
This setup allows you to enqueue tasks in the background, fire events when tasks complete, and handle those events using a custom event handler architecture. | ||
|
||
* * * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
# DfE.CoreLibs.Caching | ||
|
||
This caching library offers a unified, efficient caching solution for .NET projects. It provides a simple, reusable abstraction over different caching mechanisms, enabling developers to easily implement in-memory and distributed caching strategies, improving the performance and scalability of their applications. | ||
|
||
## Installation | ||
|
||
To install the DfE.CoreLibs.Caching Library, use the following command in your .NET project: | ||
|
||
```sh | ||
dotnet add package DfE.CoreLibs.Caching | ||
``` | ||
|
||
## Usage | ||
|
||
|
||
**Usage in Handlers** | ||
|
||
1. **Service Registration:** You use `ICacheService` in your handlers to store and retrieve data from memory to avoid unnecessary processing and database queries. Here's how you register the caching service: | ||
|
||
|
||
```csharp | ||
public void ConfigureServices(IServiceCollection services) | ||
{ | ||
services.AddServiceCaching(config); | ||
} | ||
``` | ||
|
||
|
||
2. **Usage in Handlers:** Here's an example of how caching is used in one of your query handlers: | ||
|
||
```csharp | ||
public class GetPrincipalBySchoolQueryHandler( | ||
ISchoolRepository schoolRepository, | ||
IMapper mapper, | ||
ICacheService cacheService) | ||
: IRequestHandler<GetPrincipalBySchoolQuery, Principal?> | ||
{ | ||
public async Task<Principal?> Handle(GetPrincipalBySchoolQuery request, CancellationToken cancellationToken) | ||
{ | ||
var cacheKey = $"Principal_{CacheKeyHelper.GenerateHashedCacheKey(request.SchoolName)}"; | ||
|
||
var methodName = nameof(GetPrincipalBySchoolQueryHandler); | ||
|
||
return await cacheService.GetOrAddAsync(cacheKey, async () => | ||
{ | ||
var principal= await schoolRepository | ||
.GetPrincipalBySchoolAsync(request.SchoolName, cancellationToken); | ||
|
||
var result = mapper.Map<Principal?>(principal); | ||
|
||
return result; | ||
}, methodName); | ||
} | ||
} | ||
``` | ||
|
||
In this case, the query handler checks if the principals are cached by generating a unique cache key. If the data is not cached, it retrieves the data from the repository, caches it, and returns it. | ||
|
||
### Cache Duration Based on Method Name | ||
|
||
The caching service dynamically determines the cache duration based on the method name. This is particularly useful when you want to apply different caching durations to different query handlers. | ||
In this example, the cache duration for `GetPrincipalBySchoolQueryHandler` is retrieved from the configuration using the method name. If no specific duration is defined for the method, it will fall back to the default cache duration. | ||
|
||
#### Example of Cache Settings in appsettings.json | ||
|
||
Here is the configuration for cache durations in the `appsettings.json` file: | ||
|
||
```csharp | ||
"CacheSettings": { | ||
"DefaultDurationInSeconds": 60, | ||
"Durations": { | ||
"GetPrincipalBySchoolQueryHandler": 86400 | ||
} | ||
} | ||
``` | ||
|
||
This setup ensures that the `GetPrincipalBySchoolQueryHandler` cache duration is set to 24 hours (86400 seconds), while other handlers will use the default duration of 60 seconds if no specific duration is configured. | ||
|
||
* * * |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.