Skip to content

Commit afe0e01

Browse files
authored
Merge pull request #27 from smdn/extend-di-apis
Improve DI-related APIs to support custom types
2 parents f7fad45 + 253dfda commit afe0e01

File tree

11 files changed

+1261
-181
lines changed

11 files changed

+1261
-181
lines changed

src/Smdn.Net.MuninNode.Hosting/Smdn.Net.MuninNode.Hosting.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ This library uses [Smdn.Net.MuninNode](https://www.nuget.org/packages/Smdn.Net.M
3434

3535
<ItemGroup>
3636
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="8.0.0" />
37-
<ProjectOrPackageReference ReferencePackageVersion="[2.2.0,4.0.0)" Include="..\Smdn.Net.MuninNode\Smdn.Net.MuninNode.csproj" />
37+
<ProjectOrPackageReference ReferencePackageVersion="[2.5.0,4.0.0)" Include="..\Smdn.Net.MuninNode\Smdn.Net.MuninNode.csproj" />
3838
</ItemGroup>
3939

4040
<Target Name="GenerateReadmeFileContent">

src/Smdn.Net.MuninNode.Hosting/Smdn.Net.MuninNode.Hosting/IServiceCollectionExtensions.cs

Lines changed: 238 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
// SPDX-License-Identifier: MIT
33

44
using System;
5+
#if SYSTEM_DIAGNOSTICS_CODEANALYSIS_DYNAMICALLYACCESSEDMEMBERSATTRIBUTE
6+
using System.Diagnostics.CodeAnalysis;
7+
#endif
58

69
using Microsoft.Extensions.DependencyInjection;
710

@@ -20,50 +23,273 @@ public static class IServiceCollectionExtensions {
2023
/// configure the <c>Munin-Node</c> to be built.
2124
/// </param>
2225
/// <param name="buildNode">
23-
/// An <see cref="Action{IMuninServiceBuilder}"/> to build <c>Munin-Node</c> using with
24-
/// the <see cref="IMuninServiceBuilder"/>.
26+
/// An <see cref="Action{IMuninNodeBuilder}"/> to build <c>Munin-Node</c> using with
27+
/// the <see cref="IMuninNodeBuilder"/>.
2528
/// </param>
2629
/// <returns>The current <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
2730
/// <exception cref="ArgumentNullException">
2831
/// <paramref name="services"/> is <see langword="null"/>, or
2932
/// <paramref name="configureNode"/> is <see langword="null"/>, or
3033
/// <paramref name="buildNode"/> is <see langword="null"/>.
3134
/// </exception>
35+
#pragma warning disable CS0618 // accept MuninNodeBuilder instead of IMuninNodeBuilder
3236
public static IServiceCollection AddHostedMuninNodeService(
3337
this IServiceCollection services,
3438
Action<MuninNodeOptions> configureNode,
3539
Action<IMuninNodeBuilder> buildNode
3640
)
41+
#pragma warning restore CS0618
42+
=> AddHostedMuninNodeService<
43+
MuninNodeBackgroundService,
44+
IMuninNode,
45+
IMuninNode,
46+
MuninNodeOptions,
47+
DefaultMuninNodeBuilder
48+
>(
49+
services: services ?? throw new ArgumentNullException(nameof(services)),
50+
configureNode: configureNode ?? throw new ArgumentNullException(nameof(configureNode)),
51+
createNodeBuilder: static (serviceBuilder, serviceKey) => new(serviceBuilder, serviceKey),
52+
buildNode: builder => (buildNode ?? throw new ArgumentNullException(nameof(buildNode)))(builder)
53+
);
54+
55+
private class DefaultMuninNodeBuilder(IMuninServiceBuilder serviceBuilder, string serviceKey)
56+
: MuninNodeBuilder(serviceBuilder, serviceKey) {
57+
}
58+
59+
/// <summary>
60+
/// Add <typeparamref name="TMuninNodeBackgroundService"/>, which runs <typeparamref name="TMuninNode"/> as an
61+
/// <see cref="Microsoft.Extensions.Hosting.IHostedService"/>, to <see cref="IServiceCollection"/>.
62+
/// </summary>
63+
/// <typeparam name="TMuninNodeBackgroundService">
64+
/// The type of <see cref="Microsoft.Extensions.Hosting.IHostedService"/> service to add to the <seealso cref="IServiceCollection"/>.
65+
/// </typeparam>
66+
/// <typeparam name="TMuninNode">
67+
/// The type of <see cref="IMuninNode"/> service to add to the <seealso cref="IServiceCollection"/>.
68+
/// </typeparam>
69+
/// <typeparam name="TMuninNodeOptions">
70+
/// The extended type of <see cref="MuninNodeOptions"/> to configure the <typeparamref name="TMuninNode"/>.
71+
/// </typeparam>
72+
/// <typeparam name="TMuninNodeBuilder">
73+
/// The extended type of <see cref="MuninNodeBuilder"/> to build the <typeparamref name="TMuninNode"/>.
74+
/// </typeparam>
75+
/// <param name="services">
76+
/// An <see cref="IServiceCollection"/> that the built <typeparamref name="TMuninNodeBackgroundService"/> and
77+
/// <typeparamref name="TMuninNode"/> will be added to.
78+
/// </param>
79+
/// <param name="configureNode">
80+
/// An <see cref="Action{TMuninNodeOptions}"/> to setup <typeparamref name="TMuninNodeOptions"/> to
81+
/// configure the <typeparamref name="TMuninNode"/> to be built.
82+
/// </param>
83+
/// <param name="createNodeBuilder">
84+
/// An <see cref="Func{TMuninNodeBuilder}"/> to create <typeparamref name="TMuninNodeBuilder"/> to build
85+
/// the <typeparamref name="TMuninNode"/>.
86+
/// </param>
87+
/// <param name="buildNode">
88+
/// An <see cref="Action{TMuninNodeBuilder}"/> to build <typeparamref name="TMuninNode"/> using with
89+
/// the <typeparamref name="TMuninNodeBuilder"/>.
90+
/// </param>
91+
/// <returns>The current <see cref="IMuninNodeBuilder"/> so that additional calls can be chained.</returns>
92+
/// <exception cref="ArgumentNullException">
93+
/// <paramref name="services"/> is <see langword="null"/>, or
94+
/// <paramref name="configureNode"/> is <see langword="null"/>, or
95+
/// <paramref name="createNodeBuilder"/> is <see langword="null"/>, or
96+
/// <paramref name="buildNode"/> is <see langword="null"/>.
97+
/// </exception>
98+
#pragma warning disable IDE0055
99+
public static
100+
IServiceCollection AddHostedMuninNodeService<
101+
#if SYSTEM_DIAGNOSTICS_CODEANALYSIS_DYNAMICALLYACCESSEDMEMBERSATTRIBUTE
102+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
103+
#endif
104+
TMuninNodeBackgroundService,
105+
TMuninNode,
106+
TMuninNodeOptions,
107+
TMuninNodeBuilder
108+
>(
109+
this IServiceCollection services,
110+
Action<TMuninNodeOptions> configureNode,
111+
Func<IMuninServiceBuilder, string, TMuninNodeBuilder> createNodeBuilder,
112+
Action<TMuninNodeBuilder> buildNode
113+
)
114+
where TMuninNodeBackgroundService : MuninNodeBackgroundService
115+
where TMuninNode : class, IMuninNode
116+
where TMuninNodeOptions : MuninNodeOptions, new()
117+
where TMuninNodeBuilder : MuninNodeBuilder
118+
#pragma warning restore IDE0055
119+
=> AddHostedMuninNodeService<
120+
TMuninNodeBackgroundService,
121+
TMuninNode,
122+
TMuninNode,
123+
TMuninNodeOptions,
124+
TMuninNodeBuilder
125+
>(
126+
services: services ?? throw new ArgumentNullException(nameof(services)),
127+
configureNode: configureNode ?? throw new ArgumentNullException(nameof(configureNode)),
128+
createNodeBuilder: createNodeBuilder ?? throw new ArgumentNullException(nameof(configureNode)),
129+
buildNode: buildNode ?? throw new ArgumentNullException(nameof(buildNode))
130+
);
131+
132+
/// <summary>
133+
/// Add <typeparamref name="TMuninNodeBackgroundService"/>, which runs <typeparamref name="TMuninNodeImplementation"/> as an
134+
/// <see cref="Microsoft.Extensions.Hosting.IHostedService"/>, to <see cref="IServiceCollection"/>.
135+
/// </summary>
136+
/// <typeparam name="TMuninNodeBackgroundService">
137+
/// The type of <see cref="Microsoft.Extensions.Hosting.IHostedService"/> service to add to the <seealso cref="IServiceCollection"/>.
138+
/// </typeparam>
139+
/// <typeparam name="TMuninNodeService">
140+
/// The type of <see cref="IMuninNode"/> service to add to the <seealso cref="IServiceCollection"/>.
141+
/// </typeparam>
142+
/// <typeparam name="TMuninNodeImplementation">
143+
/// The type of <typeparamref name="TMuninNodeService"/> implementation.
144+
/// </typeparam>
145+
/// <typeparam name="TMuninNodeOptions">
146+
/// The extended type of <see cref="MuninNodeOptions"/> to configure the <typeparamref name="TMuninNodeImplementation"/>.
147+
/// </typeparam>
148+
/// <typeparam name="TMuninNodeBuilder">
149+
/// The extended type of <see cref="MuninNodeBuilder"/> to build the <typeparamref name="TMuninNodeImplementation"/>.
150+
/// </typeparam>
151+
/// <param name="services">
152+
/// An <see cref="IServiceCollection"/> that the built <typeparamref name="TMuninNodeBackgroundService"/> and
153+
/// <typeparamref name="TMuninNodeImplementation"/> will be added to.
154+
/// </param>
155+
/// <param name="configureNode">
156+
/// An <see cref="Action{TMuninNodeOptions}"/> to setup <typeparamref name="TMuninNodeOptions"/> to
157+
/// configure the <typeparamref name="TMuninNodeImplementation"/> to be built.
158+
/// </param>
159+
/// <param name="createNodeBuilder">
160+
/// An <see cref="Func{TMuninNodeBuilder}"/> to create <typeparamref name="TMuninNodeBuilder"/> to build
161+
/// the <typeparamref name="TMuninNodeImplementation"/>.
162+
/// </param>
163+
/// <param name="buildNode">
164+
/// An <see cref="Action{TMuninNodeBuilder}"/> to build <typeparamref name="TMuninNodeImplementation"/> using with
165+
/// the <typeparamref name="TMuninNodeBuilder"/>.
166+
/// </param>
167+
/// <returns>The current <see cref="IMuninNodeBuilder"/> so that additional calls can be chained.</returns>
168+
/// <exception cref="ArgumentNullException">
169+
/// <paramref name="services"/> is <see langword="null"/>, or
170+
/// <paramref name="configureNode"/> is <see langword="null"/>, or
171+
/// <paramref name="createNodeBuilder"/> is <see langword="null"/>, or
172+
/// <paramref name="buildNode"/> is <see langword="null"/>.
173+
/// </exception>
174+
#pragma warning disable IDE0055
175+
public static
176+
IServiceCollection AddHostedMuninNodeService<
177+
#if SYSTEM_DIAGNOSTICS_CODEANALYSIS_DYNAMICALLYACCESSEDMEMBERSATTRIBUTE
178+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
179+
#endif
180+
TMuninNodeBackgroundService,
181+
TMuninNodeService,
182+
TMuninNodeImplementation,
183+
TMuninNodeOptions,
184+
TMuninNodeBuilder
185+
>(
186+
this IServiceCollection services,
187+
Action<TMuninNodeOptions> configureNode,
188+
Func<IMuninServiceBuilder, string, TMuninNodeBuilder> createNodeBuilder,
189+
Action<TMuninNodeBuilder> buildNode
190+
)
191+
where TMuninNodeBackgroundService : MuninNodeBackgroundService
192+
where TMuninNodeService : class, IMuninNode
193+
where TMuninNodeImplementation : class, TMuninNodeService
194+
where TMuninNodeOptions : MuninNodeOptions, new()
195+
where TMuninNodeBuilder : MuninNodeBuilder
196+
#pragma warning restore IDE0055
37197
{
38198
if (services is null)
39199
throw new ArgumentNullException(nameof(services));
40200
if (configureNode is null)
41201
throw new ArgumentNullException(nameof(configureNode));
202+
if (createNodeBuilder is null)
203+
throw new ArgumentNullException(nameof(createNodeBuilder));
42204
if (buildNode is null)
43205
throw new ArgumentNullException(nameof(buildNode));
44206

45-
return services.AddMunin(
46-
muninBuilder => {
47-
var muninNodeBuilder = muninBuilder.AddNode(configureNode);
207+
return AddHostedMuninNodeService<TMuninNodeBackgroundService, TMuninNodeBuilder>(
208+
services: services,
209+
buildMunin: muninBuilder => {
210+
var muninNodeBuilder = muninBuilder.AddNode<
211+
TMuninNodeService,
212+
TMuninNodeImplementation,
213+
TMuninNodeOptions,
214+
TMuninNodeBuilder
215+
>(
216+
configureNode,
217+
createNodeBuilder
218+
);
48219

49220
buildNode(muninNodeBuilder);
50221

51-
muninNodeBuilder.Services.AddHostedService<MuninNodeBackgroundService>();
222+
return muninNodeBuilder;
223+
}
224+
);
225+
}
52226

53-
// TODO: support keyed service
54-
#if false
55-
var muninNodeBuilder = muninBuilder.AddKeyedNode(configureNode);
227+
/// <summary>
228+
/// Add <typeparamref name="TMuninNodeBackgroundService"/>, which runs <c>Munin-Node</c> as an
229+
/// <see cref="Microsoft.Extensions.Hosting.IHostedService"/>, to <see cref="IServiceCollection"/>.
230+
/// </summary>
231+
/// <typeparam name="TMuninNodeBackgroundService">
232+
/// The type of <see cref="Microsoft.Extensions.Hosting.IHostedService"/> service to add to the <seealso cref="IServiceCollection"/>.
233+
/// </typeparam>
234+
/// <typeparam name="TMuninNodeBuilder">
235+
/// The extended type of <see cref="MuninNodeBuilder"/> to build the <c>Munin-Node</c>.
236+
/// </typeparam>
237+
/// <param name="services">
238+
/// An <see cref="IServiceCollection"/> that the built <typeparamref name="TMuninNodeBackgroundService"/> and
239+
/// <c>Munin-Node</c> will be added to.
240+
/// </param>
241+
/// <param name="buildMunin">
242+
/// A <see cref="Func{IMuninServiceBuilder, TMuninNodeBuilder}"/> that registers at least one <see cref="IMuninNode"/> to
243+
/// <paramref name="services"/> and returns <typeparamref name="TMuninNodeBuilder"/>, which builds the <see cref="IMuninNode"/>
244+
/// to be registered.
245+
/// </param>
246+
/// <returns>The current <see cref="IServiceCollection"/> so that additional calls can be chained.</returns>
247+
/// <exception cref="ArgumentNullException">
248+
/// <paramref name="services"/> is <see langword="null"/>, or
249+
/// <paramref name="buildMunin"/> is <see langword="null"/>.
250+
/// </exception>
251+
/// <remarks>
252+
/// In future implementations, <typeparamref name="TMuninNodeBackgroundService"/> to be registered by
253+
/// this method will use the same key as the <see cref="MuninNodeBuilder.ServiceKey"/> of the
254+
/// <typeparamref name="TMuninNodeBuilder"/> returned by the <paramref name="buildMunin"/>.
255+
/// </remarks>
256+
#pragma warning disable IDE0055
257+
public static
258+
IServiceCollection AddHostedMuninNodeService<
259+
#if SYSTEM_DIAGNOSTICS_CODEANALYSIS_DYNAMICALLYACCESSEDMEMBERSATTRIBUTE
260+
[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)]
261+
#endif
262+
TMuninNodeBackgroundService,
263+
TMuninNodeBuilder
264+
>(
265+
this IServiceCollection services,
266+
Func<IMuninServiceBuilder, TMuninNodeBuilder> buildMunin
267+
)
268+
where TMuninNodeBackgroundService : MuninNodeBackgroundService
269+
where TMuninNodeBuilder : MuninNodeBuilder
270+
#pragma warning restore IDE0055
271+
{
272+
if (services is null)
273+
throw new ArgumentNullException(nameof(services));
274+
if (buildMunin is null)
275+
throw new ArgumentNullException(nameof(buildMunin));
56276

57-
buildNode(muninNodeBuilder);
277+
return services.AddMunin(
278+
muninBuilder => {
279+
var muninNodeBuilder = buildMunin(muninBuilder);
280+
281+
muninNodeBuilder.Services.AddHostedService<TMuninNodeBackgroundService>();
58282

283+
// TODO: support keyed service
284+
#if false
59285
// these code does not work currently
60286
// https://github.com/dotnet/runtime/issues/99085
61-
muninNodeBuilder.Services.AddHostedService<MuninNodeBackgroundService>(
287+
muninNodeBuilder.Services.AddHostedService<TMuninNodeBackgroundService>(
62288
serviceKey: muninNodeBuilder.ServiceKey
63289
);
64290

65291
muninNodeBuilder.Services.TryAddEnumerable(
66-
ServiceDescriptor.KeyedSingleton<IHostedService, MuninNodeBackgroundService>(
292+
ServiceDescriptor.KeyedSingleton<IHostedService, TMuninNodeBackgroundService>(
67293
serviceKey: muninNodeBuilder.ServiceKey
68294
)
69295
);

src/Smdn.Net.MuninNode/Smdn.Net.MuninNode.DependencyInjection/IMuninNodeBuilder.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ namespace Smdn.Net.MuninNode.DependencyInjection;
1414
/// <see cref="IMuninNodeBuilderExtensions.AddPlugin"/>
1515
/// <see cref="IMuninNodeBuilderExtensions.UseListenerFactory"/>
1616
/// <see cref="IMuninNodeBuilderExtensions.UseSessionCallback"/>
17+
[Obsolete($"Use or inherit {nameof(MuninNodeBuilder)} instead.")]
1718
public interface IMuninNodeBuilder {
1819
/// <summary>
1920
/// Gets the <see cref="IServiceCollection"/> where the <c>Munin-Node</c> services are configured.

0 commit comments

Comments
 (0)