Skip to content

Commit

Permalink
Edit pass
Browse files Browse the repository at this point in the history
  • Loading branch information
IEvangelist committed Jul 18, 2024
1 parent f818574 commit ca9e240
Showing 1 changed file with 32 additions and 22 deletions.
54 changes: 32 additions & 22 deletions docs/core/extensions/dependency-injection-basics.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ no-loc: [Transient, Scoped, Singleton, Example]
In this article, you create a .NET console app that manually creates a `ServiceCollection` and corresponding `ServiceProvider`. You learn how to register services and resolve them using dependency injection (DI). This article uses the [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection) NuGet package to demonstrate the basics of DI in .NET.

> [!NOTE]
> This article doesn't take advantage of the [Generic Host](generic-host.md) features. For a more comprehensive guide, see the [Use dependency injection](dependency-injection-usage.md) tutorial.
> This article doesn't take advantage of the [Generic Host](generic-host.md) features. For a more comprehensive guide, see [Use dependency injection in .NET](dependency-injection-usage.md).
## Get started

To get started, create a new .NET console application named **DI.Basics**. This can be done in a number of ways, some of the most common approaches are listed in the following:
To get started, create a new .NET console application named **DI.Basics**. Some of the most common approaches for creating a console project are referenced in the following list:

- [Visual Studio: **File > New > Project**](/visualstudio/get-started/csharp/tutorial-console) menu.
- [Visual Studio Code](https://code.visualstudio.com/) and the [C# Dev Kit extension's](https://code.visualstudio.com/docs/csharp/project-management): **Solution Explorer** menu option.
- [.NET CLI: `dotnet new console`](/dotnet/core/tools/dotnet-new-sdk-templates#console) command in the terminal.

Then add the package reference to the [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection) in the project file. Regardless of the approach, ensure the project XML resemembles the following:
You need to add the package reference to the [Microsoft.Extensions.DependencyInjection](https://www.nuget.org/packages/Microsoft.Extensions.DependencyInjection) in the project file. Regardless of the approach, ensure the project resembles the following XML:

:::code language="XML" source="snippets/di/di-basics/di-basics.csproj":::

Expand All @@ -36,11 +36,11 @@ The abstractions for DI in .NET are defined in the [Microsoft.Extensions.Depende
- `IServiceProvider`: Defines a mechanism for retrieving a service object.
- `ServiceDescriptor`: Describes a service with its service type, implementation, and lifetime.

In .NET, DI is managed by adding services and configuring them in an `IServiceCollection`. After services are registered, the `IServiceProvider` instance is created by the `BuildServiceProvider` method. The `IServiceProvider` acts as a container of all the registered services, and it's used to resolve services.
In .NET, DI is managed by adding services and configuring them in an `IServiceCollection`. After services are registered, as `IServiceProvider` instance is built by calling the `BuildServiceProvider` method. The `IServiceProvider` acts as a container of all the registered services, and it's used to resolve services.

## Create services

Not all services are created equally. Some services require a new instance each time they're retrieved (_transient_), while others should be shared across requests (_scoped_) or for the entire lifetime of the app (_singleton_). For more information on service lifetimes, see [Service lifetimes](dependency-injection.md#service-lifetimes).
Not all services are created equally. Some services require a new instance each time that the service container gets them (_transient_), while others should be shared across requests (_scoped_) or for the entire lifetime of the app (_singleton_). For more information on service lifetimes, see [Service lifetimes](dependency-injection.md#service-lifetimes).

Likewise, some services only expose a concrete type, while others are expressed as a contract between an interface and an implementation type. You create several variations of services to help demonstrate these concepts.

Expand Down Expand Up @@ -75,34 +75,43 @@ The last service to create is the _FarewellService.cs_ file, add the following C

:::code source="snippets/di/di-basics/FarewellService.cs":::

The preceding code is a concrete type, it's not an interface. Also, it needs to be `public` so that it's accessible to consumers, whereas other service implementation types were declared as `internal` and `sealed`. This is a means by which to demonstrate that not all services need to be interfaces, and that concrete types can be registered as services. It alsos demonstrates that service implementations can be `sealed` to prevent inheritance, and `internal` to restrict access to the assembly.
The `FarewellService` represents a concrete type, not an interface. It should be declared as `public` to make it accessible to consumers. Unlike other service implementation types that were declared as `internal` and `sealed`, this code demonstrates that not all services need to be interfaces. It also shows that service implementations can be `sealed` to prevent inheritance and `internal` to restrict access to the assembly.

## Update the Program.cs file
## Update the `Program` class

Open the _Program.cs_ file and replace the existing code with the following:
Open the _Program.cs_ file and replace the existing code with the following C# code:

:::code source="snippets/di/di-basics/Program.cs":::

The preceding updated code demonstrates the following:
The preceding updated code demonstrates the how-to:

- Creates a new `ServiceCollection` instance.
- Registers and configures the:
- The `IConsole` using the implemenation factory overload, return a `DefaultConsole` type with the `IsEnabled` set to `true.
- Create a new `ServiceCollection` instance.
- Register and configure services in the `ServiceCollection`:
- The `IConsole` using the implementation factory overload, return a `DefaultConsole` type with the `IsEnabled` set to `true.
- The `IGreetingService` is added with a corresponding implementation type of `DefaultGreetingService` type.
- The `FarewellService` is added as a concrete type.
- Builds the `ServiceProvider` from the `ServiceCollection`.
- Resolves the `IGreetingService` and `FarewellService` services.
- Uses the resolved services to greet and say goodbye to a person named `David`.
- Build the `ServiceProvider` from the `ServiceCollection`.
- Resolve the `IGreetingService` and `FarewellService` services.
- Use the resolved services to greet and say goodbye to a person named `David`.

If you update the `IsEnabled` property of the `DefaultConsole` to `false`, the `Greet` and `Goodbye` methods won't write to the console. This demonstrates that the `IConsole` service is _injected_ into the `IGreetingService` and `FarewellService` services.
If you update the `IsEnabled` property of the `DefaultConsole` to `false`, the `Greet` and `SayGoodbye` methods omit writing to the resulting messages to console. A change like this, helps to demonstrate that the `IConsole` service is _injected_ into the `IGreetingService` and `FarewellService` services as a _dependency_ that influences that apps behavior.

All of these services are registered as singletons, although for this sample, it would have worked identically if they were registered as transient or scoped services. In this contrived example, the service lifetimes don't matter, but in a real-world application, you should carefully consider the lifetime of each service.
All of these services are registered as singletons, although for this sample, it works identically if they were registered as _transient_ or _scoped_ services.

> [!IMPORTANT]
> In this contrived example, the service lifetimes don't matter, but in a real-world application, you should carefully consider the lifetime of each service.
### Service descriptors

The most commonly used APIs for adding services to the `ServiceCollection` are actually lifetime-named generic extension methods, such as, `AddSingleton`, `AddTransient`, and `AddScoped`. These methods are convenience methods that create a `ServiceDescriptor` instance and add it to the `ServiceCollection`. The `ServiceDescriptor` class is a simple class that describes a service with its service type, implementation, and lifetime.
The most commonly used APIs for adding services to the `ServiceCollection` are lifetime-named generic extension methods, such as:

- `AddSingleton<TService>`
- `AddTransient<TService>`
- `AddScoped<TService>`

These methods are convenience methods that create a `ServiceDescriptor` instance and add it to the `ServiceCollection`. The `ServiceDescriptor` class is a simple class that describes a service with its service type, implementation, and lifetime.

For each of the services that you registered in the `ServiceCollection`, you could have used the `Add` method to add a `ServiceDescriptor` instance directly. Consider the following examples:
For each of the services that you registered in the `ServiceCollection`, you could instead call the `Add` method with a `ServiceDescriptor` instance directly. Consider the following examples:

:::code source="snippets/di/di-basics/Program.ServiceDescriptors.cs" id="console":::

Expand All @@ -114,9 +123,10 @@ The preceding code describes the `IGreetingService` service with its service typ

:::code source="snippets/di/di-basics/Program.ServiceDescriptors.cs" id="farewell":::

The preceding code describes the concrete `FarewellService` type as both the service type and implementation type. The service is registered as a singleton service.
The preceding code describes the concrete `FarewellService` type as both the service and implementation types. The service is registered as a singleton service.

## See also

* [Dependency injection guidelines](dependency-injection-guidelines.md)
* [Dependency injection in ASP.NET Core](/aspnet/core/fundamentals/dependency-injection)
- [.NET dependency injection](dependency-injection.md)
- [Dependency injection guidelines](dependency-injection-guidelines.md)
- [Dependency injection in ASP.NET Core](/aspnet/core/fundamentals/dependency-injection)

0 comments on commit ca9e240

Please sign in to comment.