Skip to content

Commit 8953c4e

Browse files
jamesmblairJames Blair
andauthored
Update README, XML documentation comments, and release/publish workflow. (#5)
* Add additional unit tests * Begin adding XML documentation comments. #3 * Add XML doc comments for event sourcing types * Finish XML documentation for all public members * Finish XML documentation for all public members * Fix Rider version control config * Add Examples ASP.NET Core project. Add support for minimal APIs * First draft of README * Add .github/release.yml for automatic release note generation * Draft of nuget publish workflow * Update publish.yml to use non-deprecated artifact tasks * Add working directory setting to publish.yml * Update nuget package info for csproj files * Add unit tests for Result extensions for minimal APIs * Remove UserProfileId from event-sourcing base types --------- Co-authored-by: James Blair <jblair@feature23.com>
1 parent 41cf182 commit 8953c4e

File tree

68 files changed

+1839
-27
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+1839
-27
lines changed

.github/release.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
changelog:
2+
exclude:
3+
labels:
4+
- notes:ignore
5+
authors:
6+
- dependabot
7+
categories:
8+
- title: 💥 Breaking Changes
9+
labels:
10+
- notes:breaking-change
11+
- title: 🎉 New Features
12+
labels:
13+
- notes:new-feature
14+
- title: 🐞 Bug Fixes
15+
labels:
16+
- notes:bug-fix
17+
- title: 💪 Other Changes
18+
labels:
19+
- "*"

.github/workflows/ci_build.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2+
13
name: build
24

35
on:

.github/workflows/publish.yml

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# yaml-language-server: $schema=https://json.schemastore.org/github-workflow.json
2+
3+
name: publish
4+
5+
on:
6+
workflow_dispatch: # Allow running the workflow manually from the GitHub UI
7+
push:
8+
branches:
9+
- main # Run the workflow when pushing to the main branch
10+
- 'releases/**' # Run the workflow when pushing to a release branch
11+
pull_request:
12+
branches:
13+
- '*' # Run the workflow for all pull requests
14+
release:
15+
types:
16+
- published # Run the workflow when a new GitHub release is published
17+
# Publish to nuget.org will only occur when a new release is published
18+
19+
env:
20+
DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
21+
DOTNET_NOLOGO: true
22+
NuGetDirectory: ${{ github.workspace}}/nuget
23+
24+
jobs:
25+
create_nuget:
26+
runs-on: ubuntu-latest
27+
defaults:
28+
run:
29+
working-directory: src
30+
steps:
31+
- uses: actions/checkout@v3
32+
with:
33+
fetch-depth: 0 # Get all history to allow automatic versioning using MinVer
34+
35+
- name: Setup .NET
36+
uses: actions/setup-dotnet@v4
37+
38+
- run: dotnet pack --configuration Release --output ${{ env.NuGetDirectory }}
39+
40+
# Publish the NuGet packages as an artifact, so they can be used in the following jobs
41+
- uses: actions/upload-artifact@v4
42+
with:
43+
name: nuget
44+
if-no-files-found: error
45+
retention-days: 7
46+
path: ${{ env.NuGetDirectory }}/*.nupkg
47+
48+
run_test:
49+
runs-on: ubuntu-latest
50+
defaults:
51+
run:
52+
working-directory: src
53+
steps:
54+
- uses: actions/checkout@v3
55+
- name: Setup .NET
56+
uses: actions/setup-dotnet@v4
57+
- name: Run tests
58+
run: dotnet test --configuration Release
59+
60+
deploy:
61+
# Publish only when creating a GitHub Release
62+
# https://docs.github.com/en/repositories/releasing-projects-on-github/managing-releases-in-a-repository
63+
# You can update this logic if you want to manage releases differently
64+
if: github.event_name == 'release'
65+
runs-on: ubuntu-latest
66+
defaults:
67+
run:
68+
working-directory: src
69+
needs: [ create_nuget, run_test ]
70+
steps:
71+
# Download the NuGet package created in the previous job
72+
- uses: actions/download-artifact@v4
73+
with:
74+
name: nuget
75+
path: ${{ env.NuGetDirectory }}
76+
77+
- name: Setup .NET Core
78+
uses: actions/setup-dotnet@v4
79+
80+
# Publish all NuGet packages to NuGet.org
81+
# Use --skip-duplicate to prevent errors if a package with the same version already exists.
82+
# If you retry a failed workflow, already published packages will be skipped without error.
83+
- name: Publish NuGet package
84+
run: |
85+
foreach($file in (Get-ChildItem "${{ env.NuGetDirectory }}" -Recurse -Include *.nupkg)) {
86+
dotnet nuget push $file --api-key "${{ secrets.NUGET_APIKEY }}" --source https://api.nuget.org/v3/index.json --skip-duplicate
87+
}

README.md

Lines changed: 83 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,85 @@
1-
# kernel
1+
# feature[23] Shared Kernel
22

33
[![build](https://github.com/feature23/kernel/actions/workflows/ci_build.yml/badge.svg)](https://github.com/feature23/kernel/actions/workflows/ci_build.yml)
4+
5+
A library of reusable types for implementing Clean Architecture in .NET and ASP.NET Core applications, based heavily on the work of [Steve Smith](https://github.com/ardalis) in the following open-sourcee projects:
6+
- [ASP.NET Core Template](https://github.com/ardalis/CleanArchitecture)
7+
- [Shared Kernel](https://github.com/ardalis/Ardalis.SharedKernel)
8+
9+
For the core functionality, only the `F23.Kernel` library is needed. This library provides types for events, results, query and command handlers, validation, and messaging. For smoother integration with ASP.NET Core, the `F23.Kernel.AspNetCore` library can be used for easily mapping between core result types and ASP.NET Core `IActionResult` and model state.
10+
11+
> **WARNING:** This library is currently in a pre-release state, and breaking changes may occur before reaching version 1.0.
12+
13+
## NuGet Installation
14+
### Core Package
15+
```powershell
16+
dotnet add package F23.Kernel
17+
```
18+
19+
### ASP.NET Core Helper Package
20+
```powershell
21+
dotnet add package F23.Kernel.AspNetCore
22+
```
23+
24+
## Examples
25+
26+
### Query Handler
27+
```csharp
28+
class GetWeatherForecastQueryResult
29+
{
30+
public required IReadOnlyList<WeatherForecast> Forecast { get; init; }
31+
}
32+
33+
class GetWeatherForecastQuery : IQuery<GetWeatherForecastQueryResult>
34+
{
35+
public int DaysIntoTheFuture { get; init; } = 5;
36+
}
37+
38+
record WeatherForecast(DateOnly Date, int TemperatureC, string? Summary)
39+
{
40+
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
41+
}
42+
43+
class GetWeatherForecastQueryHandler(IValidator<GetWeatherForecastQuery> validator, IWeatherForecastRepository repository)
44+
: IQueryHandler<GetWeatherForecastQuery, GetWeatherForecastQueryResult>
45+
{
46+
public async Task<Result<GetWeatherForecastQueryResult>> Handle(GetWeatherForecastQuery query, CancellationToken cancellationToken = default)
47+
{
48+
if (await validator.Validate(query, cancellationToken) is ValidationFailedResult failed)
49+
{
50+
return Result<GetWeatherForecastQueryResult>.ValidationFailed(failed.Errors);
51+
}
52+
53+
var forecast = await repository.GetForecast(query.DaysIntoTheFuture, cancellationToken);
54+
55+
var result = new GetWeatherForecastQueryResult
56+
{
57+
Forecast = forecast
58+
};
59+
60+
return Result<GetWeatherForecastQueryResult>.Success(result);
61+
}
62+
}
63+
```
64+
65+
#### Program.cs
66+
```csharp
67+
builder.Services.RegisterQueryHandler<GetWeatherForecastQuery, GetWeatherForecastQueryResult, GetWeatherForecastQueryHandler>();
68+
69+
// Other code omitted for brevity
70+
71+
app.MapGet("/weatherforecast", async (IQueryHandler<GetWeatherForecastQuery, GetWeatherForecastQueryResult> queryHandler) =>
72+
{
73+
var result = await queryHandler.Handle(new GetWeatherForecastQuery());
74+
75+
return result.ToMinimalApiResult();
76+
})
77+
.WithName("GetWeatherForecast")
78+
.WithOpenApi();
79+
```
80+
81+
### Command Handler
82+
> TODO
83+
84+
### Event Sourcing
85+
> TODO

src/.idea/.idea.F23.Kernel/.idea/vcs.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/F23.Kernel.AspNetCore/F23.Kernel.AspNetCore.csproj

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,37 @@
44
<TargetFramework>net8.0</TargetFramework>
55
<ImplicitUsings>enable</ImplicitUsings>
66
<Nullable>enable</Nullable>
7+
<Version>0.1.0</Version>
8+
<Authors>feature[23]</Authors>
9+
<Copyright>feature[23]</Copyright>
10+
<PackageProjectUrl>https://github.com/feature23/kernel</PackageProjectUrl>
11+
<RepositoryUrl>https://github.com/feature23/kernel</RepositoryUrl>
12+
<PackageLicenseUrl>https://github.com/feature23/kernel/blob/main/LICENSE</PackageLicenseUrl>
13+
</PropertyGroup>
14+
15+
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
16+
<DocumentationFile>bin\Debug\net8.0\F23.Kernel.AspNetCore.xml</DocumentationFile>
17+
</PropertyGroup>
18+
19+
<PropertyGroup Condition=" '$(Configuration)' == 'Release' ">
20+
<DocumentationFile>bin\Release\net8.0\F23.Kernel.AspNetCore.xml</DocumentationFile>
721
</PropertyGroup>
822

923
<ItemGroup>
1024
<InternalsVisibleTo Include="F23.Kernel.Tests" />
1125
</ItemGroup>
1226

27+
<ItemGroup>
28+
<FrameworkReference Include="Microsoft.AspNetCore.App" />
29+
</ItemGroup>
30+
1331
<ItemGroup>
1432
<ProjectReference Include="..\F23.Kernel\F23.Kernel.csproj" />
1533
</ItemGroup>
1634

1735
<ItemGroup>
1836
<PackageReference Include="F23.Hateoas" Version="1.0.0" />
19-
<PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />
37+
<!-- <PackageReference Include="Microsoft.AspNetCore.Mvc.Core" Version="2.3.0" />-->
2038
</ItemGroup>
2139

2240
</Project>

src/F23.Kernel.AspNetCore/ModelStateExtensions.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,32 @@
22

33
namespace F23.Kernel.AspNetCore;
44

5+
/// <summary>
6+
/// Provides extension methods for working with the <see cref="Microsoft.AspNetCore.Mvc.ModelBinding.ModelStateDictionary"/> class
7+
/// to map <see cref="ValidationError"/> to the appropriate structure for HTTP response.
8+
/// </summary>
59
public static class ModelStateExtensions
610
{
7-
public static void AddModelErrors(this ModelStateDictionary modelState, string key, IEnumerable<ValidationError> errors)
11+
/// <summary>
12+
/// Adds multiple validation errors to the <see cref="ModelStateDictionary"/> for a specified key.
13+
/// </summary>
14+
/// <param name="modelState">The <see cref="ModelStateDictionary"/> instance where errors will be added.</param>
15+
/// <param name="key">The key to associate with each of the validation errors.</param>
16+
/// <param name="errors">The collection of <see cref="ValidationError"/> objects to add to the model state.</param>
17+
public static void AddModelErrors(this ModelStateDictionary modelState, string key,
18+
IEnumerable<ValidationError> errors)
819
{
920
foreach (var error in errors)
1021
{
1122
modelState.AddModelError(key, error.Message);
1223
}
1324
}
1425

26+
/// <summary>
27+
/// Adds multiple validation errors to the <see cref="ModelStateDictionary"/> using the keys specified by each error.
28+
/// </summary>
29+
/// <param name="modelState">The <see cref="ModelStateDictionary"/> instance where errors will be added.</param>
30+
/// <param name="errors">The collection of <see cref="ValidationError"/> objects to add to the model state.</param>
1531
public static void AddModelErrors(this ModelStateDictionary modelState, IEnumerable<ValidationError> errors)
1632
{
1733
foreach (var error in errors)
@@ -20,6 +36,11 @@ public static void AddModelErrors(this ModelStateDictionary modelState, IEnumera
2036
}
2137
}
2238

39+
/// <summary>
40+
/// Converts a collection of <see cref="ValidationError"/> objects to a populated <see cref="ModelStateDictionary"/>.
41+
/// </summary>
42+
/// <param name="errors">The collection of <see cref="ValidationError"/> objects to add to the <see cref="ModelStateDictionary"/>.</param>
43+
/// <returns>A <see cref="ModelStateDictionary"/> instance containing the specified validation errors.</returns>
2344
public static ModelStateDictionary ToModelState(this IEnumerable<ValidationError> errors)
2445
{
2546
var modelState = new ModelStateDictionary();

0 commit comments

Comments
 (0)