Skip to content

Commit dd8ea27

Browse files
authored
Added details about IEnumerable<T> into DI. (#21257)
* Added details about IEnumerable<T> into DI. * Added missing access-by-lines.txt file for all fundamentals work.
1 parent 53a63a6 commit dd8ea27

File tree

24 files changed

+167
-28
lines changed

24 files changed

+167
-28
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
snippets/configuration/dependency-injection/Program.cs: ~/docs/core/extensions/dependency-injection.md
2+
snippets/configuration/console-di-ienumerable/Program.cs: ~/docs/core/extensions/dependency-injection.md
3+
snippets/configuration/console-di-ienumerable/ExampleService.cs: ~/docs/core/extensions/dependency-injection.md
4+
snippets/configuration/console-json/Program.cs: ~/docs/core/extensions/configuration-providers.md
5+
snippets/configuration/console-xml/Program.cs: ~/docs/core/extensions/configuration-providers.md
6+
snippets/configuration/console-ini/Program.cs: ~/docs/core/extensions/configuration-providers.md
7+
snippets/configuration/console/Program.cs: ~/docs/core/extensions/configuration.md
8+
snippets/logging/console-formatter-simple/Program.cs: ~/docs/core/extensions/custom-log-formatter.md
9+
snippets/configuration/custom-provider/Program.cs: ~/docs/core/extensions/custom-configuration-provider.md
10+
snippets/configuration/console-custom-logging/ColorConsoleLogger.cs: ~/docs/core/extensions/custom-logging-provider.md
11+
snippets/configuration/console-di-disposable/Program.cs: ~/docs/core/extensions/dependency-injection-guidelines.md
12+
snippets/configuration/console-di/Program.cs: ~/docs/core/extensions/dependency-injection-usage.md
13+
snippets/configuration/console-host/Program.cs: ~/docs/core/extensions/generic-host.md
14+
snippets/configuration/app-lifetime/Program.cs: ~/docs/core/extensions/generic-host.md
15+
snippets/configuration/app-lifetime/ExampleHostedService.cs: ~/docs/core/extensions/generic-host.md
16+
snippets/configuration/worker-service-options/Worker.cs: ~/docs/core/extensions/high-performance-logging.md
17+
snippets/configuration/console/Program.cs: ~/docs/core/extensions/logging-providers.md
18+
snippets/configuration/worker-service/appsettings.IncludeScopes.json: ~/docs/core/extensions/logging.md
19+
snippets/configuration/worker-service/Worker.cs: ~/docs/core/extensions/logging.md
20+
snippets/configuration/console-json/appsettings.json: ~/docs/core/extensions/options.md
21+
snippets/configuration/console-json/TransientFaultHandlingOptions.cs: ~/docs/core/extensions/options.md
22+
snippets/configuration/console-json/Program.cs: ~/docs/core/extensions/options.md

docs/core/extensions/dependency-injection.md

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ title: Dependency injection in .NET
33
description: Learn how .NET implements dependency injection and how to use it.
44
author: IEvangelist
55
ms.author: dapine
6-
ms.date: 09/23/2020
6+
ms.date: 10/28/2020
77
ms.topic: overview
88
---
99

@@ -205,16 +205,41 @@ The framework provides service registration extension methods that are useful in
205205

206206
For more information on type disposal, see the [Disposal of services](dependency-injection-guidelines.md#disposal-of-services) section.
207207

208+
Registering a service with only an implementation type is equivalent to registering that service with the same implementation and service type. This is why multiple implementations of a service cannot be registered using the methods that don't take an explicit service type. These methods can register multiple *instances* of a service, but they will all have the same *implementation* type.
209+
210+
Any of the above service registration methods can be used to register multiple service instances of the same service type. In the following example, `AddSingleton` is called twice with `IMessageWriter` as the service type. The second call to `AddSingleton` overrides the previous one when resolved as `IMessageWriter` and adds to the previous one when multiple services are resolved via `IEnumerable<IMessageWriter>`. Services appear in the order they were registered when resolved via `IEnumerable<{SERVICE}>`.
211+
212+
:::code language="csharp" source="snippets/configuration/console-di-ienumerable/Program.cs" highlight="19-24":::
213+
214+
The preceding sample source code registers two implementations of the `IMessageWriter`.
215+
216+
:::code language="csharp" source="snippets/configuration/console-di-ienumerable/ExampleService.cs" highlight="9-18":::
217+
218+
The `ExampleService` defines two constructor parameters; a single `IMessageWriter`, and an `IEnumerable<IMessageWriter>`. The single `IMessageWriter` is the last implemenation to have been registered, whereas the `IEnumerable<IMessageWriter>` represents all registered implementations.
219+
208220
The framework also provides `TryAdd{LIFETIME}` extension methods, which register the service only if there isn't already an implementation registered.
209221

210-
In the following example, the call to `AddSingleton` registers `MessageWriter` as an implementation for `IMessageWriter`. The call to `TryAddSingleton` has no effect because `IMessageWriter` already has a registered implementation:
222+
In the following example, the call to `AddSingleton` registers `ConsoleMessageWriter` as an implementation for `IMessageWriter`. The call to `TryAddSingleton` has no effect because `IMessageWriter` already has a registered implementation:
211223

212224
```csharp
213-
services.AddSingleton<IMessageWriter, MessageWriter>();
214-
services.TryAddSingleton<IMessageWriter, DifferentMessageWriter>();
225+
services.AddSingleton<IMessageWriter, ConsoleMessageWriter>();
226+
services.TryAddSingleton<IMessageWriter, LoggingMessageWriter>();
215227
```
216228

217-
The `TryAddSingleton` has no effect, as it was already added and the "try" will fail.
229+
The `TryAddSingleton` has no effect, as it was already added and the "try" will fail. The `ExampleService` would assert the following:
230+
231+
```csharp
232+
public class ExampleService
233+
{
234+
public ExampleService(
235+
IMessageWriter messageWriter,
236+
IEnumerable<IMessageWriter> messageWriters)
237+
{
238+
Trace.Assert(messageWriter is ConsoleMessageWriter);
239+
Trace.Assert(messageWriters.Single() is ConsoleMessageWriter);
240+
}
241+
}
242+
```
218243

219244
For more information, see:
220245

docs/core/extensions/snippets/configuration/app-lifetime/app-lifetime.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20451.14" />
10+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.2.20475.5" />
1111
</ItemGroup>
1212

1313
</Project>

docs/core/extensions/snippets/configuration/console-custom-logging/console-custom-logging.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20451.14" />
11-
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0-rc.1.20451.14" />
10+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.2.20475.5" />
11+
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0-rc.2.20475.5" />
1212
</ItemGroup>
1313

1414
</Project>

docs/core/extensions/snippets/configuration/console-di-disposable/console-di-disposable.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.1.20451.14" />
10+
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0-rc.2.20475.5" />
1111
</ItemGroup>
1212

1313
</Project>
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
using System;
2+
3+
namespace ConsoleDI.IEnumerableExample
4+
{
5+
public class ConsoleMessageWriter : IMessageWriter
6+
{
7+
public void Write(string message) =>
8+
Console.WriteLine(
9+
$"ConsoleMessageWriter.Write(message: \"{message}\")");
10+
}
11+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using System.Collections.Generic;
2+
using System.Diagnostics;
3+
using System.Linq;
4+
5+
namespace ConsoleDI.IEnumerableExample
6+
{
7+
public class ExampleService
8+
{
9+
public ExampleService(
10+
IMessageWriter messageWriter,
11+
IEnumerable<IMessageWriter> messageWriters)
12+
{
13+
Trace.Assert(messageWriter is LoggingMessageWriter);
14+
15+
var dependencyArray = messageWriters.ToArray();
16+
Trace.Assert(dependencyArray[0] is ConsoleMessageWriter);
17+
Trace.Assert(dependencyArray[1] is LoggingMessageWriter);
18+
}
19+
}
20+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
namespace ConsoleDI.IEnumerableExample
2+
{
3+
public interface IMessageWriter
4+
{
5+
void Write(string message);
6+
}
7+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using Microsoft.Extensions.Logging;
2+
3+
namespace ConsoleDI.IEnumerableExample
4+
{
5+
public class LoggingMessageWriter : IMessageWriter
6+
{
7+
private readonly ILogger<LoggingMessageWriter> _logger;
8+
9+
public LoggingMessageWriter(ILogger<LoggingMessageWriter> logger) =>
10+
_logger = logger;
11+
12+
public void Write(string message) =>
13+
_logger.LogInformation(message);
14+
}
15+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using System.Threading.Tasks;
2+
using ConsoleDI.IEnumerableExample;
3+
using Microsoft.Extensions.DependencyInjection;
4+
using Microsoft.Extensions.Hosting;
5+
6+
namespace ConsoleDI.Example
7+
{
8+
class Program
9+
{
10+
static Task Main(string[] args)
11+
{
12+
IHost host = CreateHostBuilder(args).Build();
13+
14+
_ = host.Services.GetService<ExampleService>();
15+
16+
return host.RunAsync();
17+
}
18+
19+
static IHostBuilder CreateHostBuilder(string[] args) =>
20+
Host.CreateDefaultBuilder(args)
21+
.ConfigureServices((_, services) =>
22+
services.AddSingleton<IMessageWriter, ConsoleMessageWriter>()
23+
.AddSingleton<IMessageWriter, LoggingMessageWriter>()
24+
.AddSingleton<ExampleService>());
25+
}
26+
}

0 commit comments

Comments
 (0)