Skip to content

Commit 5ec3f4f

Browse files
authored
Merge pull request #8 from feO2x/composition-root-project
Composition root project
2 parents a9f40c4 + 0209a16 commit 5ec3f4f

17 files changed

+640
-25
lines changed

Directory.Packages.props

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,12 @@
77
<ItemGroup>
88
<PackageVersion Include="FluentAssertions" Version="[7.2.0]" />
99
<PackageVersion Include="Light.GuardClauses" Version="13.0.0" />
10+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection" Version="8.0.1" />
11+
<PackageVersion Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.0" />
12+
<PackageVersion Include="Microsoft.Extensions.Logging" Version="8.0.1" />
13+
<PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.0" />
1014
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
15+
<PackageVersion Include="Neovolve.Logging.Xunit.v3" Version="7.1.0" />
1116
<PackageVersion Include="xunit.runner.visualstudio" Version="3.1.1" />
1217
<PackageVersion Include="xunit.v3" Version="2.0.3" />
1318
</ItemGroup>

Light.TemporaryStreams.sln

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,18 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{
2525
EndProjectSection
2626
EndProject
2727
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{048D0C61-6CF0-43E6-B7DB-1FDD8F791D57}"
28+
ProjectSection(SolutionItems) = preProject
29+
src\Directory.Build.props = src\Directory.Build.props
30+
EndProjectSection
2831
EndProject
2932
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{DA93B299-75F5-4A49-B2A6-4A1247047E5E}"
33+
ProjectSection(SolutionItems) = preProject
34+
tests\Directory.Build.props = tests\Directory.Build.props
35+
EndProjectSection
36+
EndProject
37+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Light.TemporaryStreams", "src\Light.TemporaryStreams\Light.TemporaryStreams.csproj", "{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}"
38+
EndProject
39+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Light.TemporaryStreams.Tests", "tests\Light.TemporaryStreams.Tests\Light.TemporaryStreams.Tests.csproj", "{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}"
3040
EndProject
3141
Global
3242
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -62,6 +72,30 @@ Global
6272
{4D6B4F48-1E4B-4ACA-9F32-829442DB5E56}.Release|x64.Build.0 = Release|Any CPU
6373
{4D6B4F48-1E4B-4ACA-9F32-829442DB5E56}.Release|x86.ActiveCfg = Release|Any CPU
6474
{4D6B4F48-1E4B-4ACA-9F32-829442DB5E56}.Release|x86.Build.0 = Release|Any CPU
75+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
76+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Debug|Any CPU.Build.0 = Debug|Any CPU
77+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Debug|x64.ActiveCfg = Debug|Any CPU
78+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Debug|x64.Build.0 = Debug|Any CPU
79+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Debug|x86.ActiveCfg = Debug|Any CPU
80+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Debug|x86.Build.0 = Debug|Any CPU
81+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Release|Any CPU.ActiveCfg = Release|Any CPU
82+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Release|Any CPU.Build.0 = Release|Any CPU
83+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Release|x64.ActiveCfg = Release|Any CPU
84+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Release|x64.Build.0 = Release|Any CPU
85+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Release|x86.ActiveCfg = Release|Any CPU
86+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1}.Release|x86.Build.0 = Release|Any CPU
87+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
88+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
89+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Debug|x64.ActiveCfg = Debug|Any CPU
90+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Debug|x64.Build.0 = Debug|Any CPU
91+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Debug|x86.ActiveCfg = Debug|Any CPU
92+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Debug|x86.Build.0 = Debug|Any CPU
93+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
94+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Release|Any CPU.Build.0 = Release|Any CPU
95+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Release|x64.ActiveCfg = Release|Any CPU
96+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Release|x64.Build.0 = Release|Any CPU
97+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Release|x86.ActiveCfg = Release|Any CPU
98+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8}.Release|x86.Build.0 = Release|Any CPU
6599
EndGlobalSection
66100
GlobalSection(SolutionProperties) = preSolution
67101
HideSolutionNode = FALSE
@@ -70,5 +104,7 @@ Global
70104
{05D48EEC-A2AB-4143-9533-A633E7B25EA3} = {677E4EE1-7062-46AB-81FF-8D20E9316ED6}
71105
{C86E6D31-A10A-4B61-B490-5A7AC4451BA5} = {048D0C61-6CF0-43E6-B7DB-1FDD8F791D57}
72106
{4D6B4F48-1E4B-4ACA-9F32-829442DB5E56} = {DA93B299-75F5-4A49-B2A6-4A1247047E5E}
107+
{61725DD8-D81C-4EC0-A0A1-63D96A87DAC1} = {048D0C61-6CF0-43E6-B7DB-1FDD8F791D57}
108+
{93CCDAD2-A16A-4BA3-A805-4FC7C4B518C8} = {DA93B299-75F5-4A49-B2A6-4A1247047E5E}
73109
EndGlobalSection
74110
EndGlobal

src/Directory.Build.props

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
<Project>
2+
<PropertyGroup>
3+
<ParentPropsFile>$([MSBuild]::GetPathOfFileAbove('Directory.Build.props', '$(MSBuildThisFileDirectory)../'))</ParentPropsFile>
4+
</PropertyGroup>
5+
6+
<Import Project="$(ParentPropsFile)" />
7+
8+
<PropertyGroup>
9+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
10+
<IsAotCompatible>true</IsAotCompatible>
11+
<RootNamespace>Light.TemporaryStreams</RootNamespace>
12+
</PropertyGroup>
13+
</Project>

src/Light.TemporaryStreams.Core/Hashing/HashingPlugin.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ public async ValueTask DisposeAsync()
7878
public ValueTask<Stream> SetUpAsync(Stream innerStream, CancellationToken cancellationToken = default)
7979
{
8080
innerStream.MustNotBeNull();
81-
Stream currentStream = innerStream;
81+
cancellationToken.ThrowIfCancellationRequested();
82+
var currentStream = innerStream;
8283
for (var i = 0; i < HashCalculators.Length; i++)
8384
{
8485
currentStream = HashCalculators[i].CreateWrappingCryptoStream(currentStream, leaveWrappedStreamOpen: true);

src/Light.TemporaryStreams.Core/Light.TemporaryStreams.Core.csproj

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

3-
<PropertyGroup>
4-
<GenerateDocumentationFile>true</GenerateDocumentationFile>
5-
<IsAotCompatible>true</IsAotCompatible>
6-
<RootNamespace>Light.TemporaryStreams</RootNamespace>
7-
</PropertyGroup>
8-
93
<ItemGroup>
104
<PackageReference Include="Light.GuardClauses" />
115
</ItemGroup>

src/Light.TemporaryStreams.Core/TemporaryStreamErrorHandlerProvider.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ public sealed class TemporaryStreamErrorHandlerProvider
99
{
1010
private readonly Action<TemporaryStream, Exception>? _errorHandler;
1111

12-
1312
/// <summary>
1413
/// Initializes a new instance of <see cref="TemporaryStreamErrorHandlerProvider" />.
1514
/// </summary>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<ItemGroup>
4+
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" />
5+
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" />
6+
</ItemGroup>
7+
8+
<ItemGroup>
9+
<ProjectReference Include="..\Light.TemporaryStreams.Core\Light.TemporaryStreams.Core.csproj" />
10+
</ItemGroup>
11+
12+
</Project>
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
using System;
2+
using Microsoft.Extensions.Logging;
3+
4+
namespace Light.TemporaryStreams;
5+
6+
/// <summary>
7+
/// Provides extension methods for <see cref="ILogger" /> that are specifically designed for use with the
8+
/// <see cref="TemporaryStreamService" />.
9+
/// </summary>
10+
public static partial class MicrosoftLoggingExtensions
11+
{
12+
/// <summary>
13+
/// Logs an error message when an exception occurs while deleting a temporary stream.
14+
/// </summary>
15+
/// <param name="logger">The logger to write the error message to.</param>
16+
/// <param name="exception">The exception that occurred.</param>
17+
/// <param name="temporaryStreamFilePath">The file path of the temporary stream.</param>
18+
[LoggerMessage(
19+
EventId = 1001,
20+
Level = LogLevel.Error,
21+
Message = "An error occurred while deleting the temporary stream '{TemporaryStreamFilePath}'"
22+
)
23+
]
24+
public static partial void LogErrorDeletingTemporaryStream(
25+
this ILogger logger,
26+
Exception exception,
27+
string temporaryStreamFilePath
28+
);
29+
}
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
using System;
2+
using Light.GuardClauses;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.DependencyInjection.Extensions;
5+
using Microsoft.Extensions.Logging;
6+
7+
namespace Light.TemporaryStreams;
8+
9+
/// <summary>
10+
/// Provides extension methods for <see cref="IServiceCollection" /> to register <see cref="TemporaryStreamService" />
11+
/// and corresponding dependencies.
12+
/// </summary>
13+
public static class ServiceCollectionExtensions
14+
{
15+
/// <summary>
16+
/// Adds the <see cref="TemporaryStreamService" /> to the specified <see cref="IServiceCollection" />.
17+
/// </summary>
18+
/// <param name="services">The <see cref="IServiceCollection" /> to add the service to.</param>
19+
/// <param name="createOptions">An optional delegate to create the <see cref="TemporaryStreamServiceOptions" />.</param>
20+
/// <param name="integrateIntoMicrosoftExtensionsLogging">
21+
/// When true, the <see cref="TemporaryStreamErrorHandlerProvider" /> returns a delegate which logs exceptions
22+
/// that occur during the deletion of temporary streams to Microsoft.Extensions.Logging. If false, the provider
23+
/// will simply return null and logging will occur against the .NET Trace.
24+
/// </param>
25+
/// <returns>The <see cref="IServiceCollection" /> so that additional calls can be chained.</returns>
26+
/// <exception cref="ArgumentNullException">Thrown when <paramref name="services" /> is null.</exception>
27+
public static IServiceCollection AddTemporaryStreamService(
28+
this IServiceCollection services,
29+
Func<IServiceProvider, TemporaryStreamServiceOptions>? createOptions = null,
30+
bool integrateIntoMicrosoftExtensionsLogging = true
31+
)
32+
{
33+
services.MustNotBeNull();
34+
if (createOptions is null)
35+
{
36+
services.TryAddSingleton<TemporaryStreamServiceOptions>();
37+
}
38+
else
39+
{
40+
services.TryAddSingleton(createOptions);
41+
}
42+
43+
if (integrateIntoMicrosoftExtensionsLogging)
44+
{
45+
services.TryAddSingleton<TemporaryStreamErrorHandlerProvider>(
46+
sp =>
47+
{
48+
var loggerFactory = sp.GetRequiredService<ILoggerFactory>();
49+
var logger = loggerFactory.CreateLogger(nameof(TemporaryStreamService));
50+
return new TemporaryStreamErrorHandlerProvider(
51+
(stream, exception) =>
52+
logger.LogErrorDeletingTemporaryStream(
53+
exception,
54+
stream.GetUnderlyingFilePath()
55+
)
56+
);
57+
}
58+
);
59+
}
60+
else
61+
{
62+
services.TryAddSingleton<TemporaryStreamErrorHandlerProvider>(
63+
_ => new TemporaryStreamErrorHandlerProvider(null)
64+
);
65+
}
66+
67+
services.TryAddSingleton<TemporaryStreamService>();
68+
services.TryAddSingleton<ITemporaryStreamService>(sp => sp.GetRequiredService<TemporaryStreamService>());
69+
return services;
70+
}
71+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
{
2+
"version": 2,
3+
"dependencies": {
4+
"net8.0": {
5+
"Microsoft.Extensions.DependencyInjection.Abstractions": {
6+
"type": "Direct",
7+
"requested": "[8.0.0, )",
8+
"resolved": "8.0.0",
9+
"contentHash": "cjWrLkJXK0rs4zofsK4bSdg+jhDLTaxrkXu4gS6Y7MAlCvRyNNgwY/lJi5RDlQOnSZweHqoyvgvbdvQsRIW+hg=="
10+
},
11+
"Microsoft.Extensions.Logging.Abstractions": {
12+
"type": "Direct",
13+
"requested": "[8.0.0, )",
14+
"resolved": "8.0.0",
15+
"contentHash": "arDBqTgFCyS0EvRV7O3MZturChstm50OJ0y9bDJvAcmEPJm0FFpFyjU/JLYyStNGGey081DvnQYlncNX5SJJGA==",
16+
"dependencies": {
17+
"Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0"
18+
}
19+
},
20+
"Microsoft.NET.ILLink.Tasks": {
21+
"type": "Direct",
22+
"requested": "[8.0.17, )",
23+
"resolved": "8.0.17",
24+
"contentHash": "x5/y4l8AtshpBOrCZdlE4txw8K3e3s9meBFeZeR3l8hbbku2V7kK6ojhXvrbjg1rk3G+JqL1BI26gtgc1ZrdUw=="
25+
},
26+
"light.temporarystreams.core": {
27+
"type": "Project",
28+
"dependencies": {
29+
"Light.GuardClauses": "[13.0.0, )"
30+
}
31+
},
32+
"Light.GuardClauses": {
33+
"type": "CentralTransitive",
34+
"requested": "[13.0.0, )",
35+
"resolved": "13.0.0",
36+
"contentHash": "mhlWUk0o+XibJgYuPlO9vQQpMmh4EAeDRFAac7pP6W3zmpjEeyUVGOiw+mdCxX469QQ2rkMYjWyHoDlZv599/w=="
37+
}
38+
}
39+
}
40+
}

0 commit comments

Comments
 (0)