Nota
L'accés a aquesta pàgina requereix autorització. Podeu provar d'iniciar la sessió o de canviar els directoris.
L'accés a aquesta pàgina requereix autorització. Podeu provar de canviar els directoris.
En esta guía de inicio rápido, creará una aplicación de consola .NET que crea manualmente un ServiceCollection y un ServiceProvider correspondiente. Aprenderás a registrar y gestionar servicios utilizando inyección de dependencias (DI). En este artículo se usa el paquete NuGet Microsoft.Extensions.DependencyInjection para demostrar los conceptos básicos de la inyección de dependencias en .NET.
Nota:
En este artículo no se aprovechan las características del host genérico . Para obtener una guía más completa, consulte Uso de la inserción de dependencias en .NET.
Comienza
Para empezar, cree una nueva aplicación de consola de .NET denominada DI.Basics. En Visual Studio, elija Archivo > Nuevo > Proyecto o, mediante la CLI de .NET, escriba dotnet new console.
A continuación, agregue una referencia de paquete a Microsoft.Extensions.DependencyInjection en el archivo del proyecto. Después de agregar el paquete, asegúrese de que el proyecto es similar al siguiente XML del archivo DI.Basics.csproj :
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="10.0.5" />
</ItemGroup>
</Project>
Conceptos básicos de inserción de dependencias
La inserción de dependencias es un patrón de diseño que puede usar para quitar dependencias codificadas de forma rígida y hacer que la aplicación sea más fácil de mantener y probar. DI es una técnica para lograr la inversión de control (IoC) entre las clases y sus dependencias.
El paquete NuGet Microsoft.Extensions.DependencyInjection.Abstractions define las abstracciones para la inyección de dependencias en .NET.
- IServiceCollection: define un contrato para una colección de descriptores de servicio.
- IServiceProvider: define un mecanismo para recuperar un objeto de servicio.
- ServiceDescriptor: describe un servicio con su tipo de servicio, implementación y duración.
En .NET, gestiona la DI (Inyección de Dependencias) agregando servicios y configurándolos en un IServiceCollection. Después de registrar los servicios, llame al BuildServiceProvider método para compilar una IServiceProvider instancia.
IServiceProvider actúa como contenedor para todos los servicios registrados y se usa para resolver servicios.
Creación de servicios de ejemplo
No todos los servicios se crean de la misma manera. Algunos servicios necesitan una nueva instancia cada vez que el contenedor de servicios los obtiene (transitorio), mientras que otros deben compartirse entre solicitudes (con alcance) o durante toda la duración de la aplicación (singleton). Para obtener más información sobre la duración del servicio, consulte Vigencias del servicio.
Del mismo modo, algunos servicios solo exponen un tipo concreto, mientras que otros se expresan como un contrato entre una interfaz y un tipo de implementación. Puede crear varias variaciones de servicios para ayudar a demostrar estos conceptos.
Cree un nuevo archivo de C# denominado IConsole.cs y agregue el código siguiente:
public interface IConsole
{
void WriteLine(string message);
}
Este archivo define una IConsole interfaz que expone un único método, WriteLine. A continuación, cree un nuevo archivo de C# denominado DefaultConsole.cs y agregue el código siguiente:
internal sealed class DefaultConsole : IConsole
{
public bool IsEnabled { get; set; } = true;
void IConsole.WriteLine(string message)
{
if (IsEnabled is false)
{
return;
}
Console.WriteLine(message);
}
}
El código anterior representa la implementación predeterminada de la IConsole interfaz. El método WriteLine escribe en la consola de manera condicional según la propiedad IsEnabled.
Sugerencia
La nomenclatura de una implementación es una opción que el equipo de desarrollo debe aceptar. El Default prefijo es una convención común para indicar una implementación predeterminada de una interfaz, pero no es necesaria.
A continuación, cree un archivo IGreetingService.cs y agregue el siguiente código de C#:
public interface IGreetingService
{
string Greet(string name);
}
A continuación, agregue un nuevo archivo de C# denominado DefaultGreetingService.cs y agregue el código siguiente:
internal sealed class DefaultGreetingService(
IConsole console) : IGreetingService
{
public string Greet(string name)
{
var greeting = $"Hello, {name}!";
console.WriteLine(greeting);
return greeting;
}
}
El código anterior representa la implementación predeterminada de la IGreetingService interfaz. La implementación del servicio requiere un IConsole como parámetro de constructor principal. El método Greet realiza las acciones siguientes:
- Crea un
greetingdado elname. - Llama al método
WriteLineen la instanciaIConsole. - Devuelve el
greetingal llamante.
La DefaultGreetingService clase muestra que puede seal implementar servicios para evitar la herencia y usar internal para restringir el acceso al ensamblado.
El último servicio que se va a crear es el archivo FarewellService.cs . Agregue el siguiente código de C# antes de continuar:
public class FarewellService(IConsole console)
{
public string SayGoodbye(string name)
{
var farewell = $"Goodbye, {name}!";
console.WriteLine(farewell);
return farewell;
}
}
FarewellService representa un tipo concreto, no una interfaz. Debe declararlo como public para que sea accesible para los consumidores. A diferencia de otros tipos de implementación de servicio que declara como internal y sealed, este código demuestra que no todos los servicios deben ser interfaces.
Actualización de la Program clase
Abra el archivo Program.cs y reemplace el código existente por el siguiente código de C#:
using Microsoft.Extensions.DependencyInjection;
// 1. Create the service collection.
var services = new ServiceCollection();
// 2. Register (add and configure) the services.
services.AddSingleton<IConsole>(
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
});
services.AddSingleton<IGreetingService, DefaultGreetingService>();
services.AddSingleton<FarewellService>();
// 3. Build the service provider from the service collection.
var serviceProvider = services.BuildServiceProvider();
// 4. Resolve the services that you need.
var greetingService = serviceProvider.GetRequiredService<IGreetingService>();
var farewellService = serviceProvider.GetRequiredService<FarewellService>();
// 5. Use the services
var greeting = greetingService.Greet("David");
var farewell = farewellService.SayGoodbye("David");
El código anterior muestra cómo:
- Cree una nueva
ServiceCollectioninstancia. - Registre y configure servicios en
ServiceCollection:- El
IConsoleservicio mediante la sobrecarga del generador de implementación. Devuelve un tipoDefaultConsolecon la propiedadIsEnabledestablecida entrue. - El servicio
IGreetingServicecon un tipo de implementación deDefaultGreetingServicecorrespondiente. - El
FarewellServiceservicio como un tipo concreto.
- El
- Construir el
ServiceProvidera partir delServiceCollection. - Resuelva los servicios
IGreetingServiceyFarewellService. - Utilice los servicios disponibles para saludar y despedirse de una persona denominada
David.
Si actualiza la propiedad IsEnabled del DefaultConsole a false, los métodos Greet y SayGoodbye omiten escribir los mensajes resultantes en la consola. Este cambio ayuda a demostrar que el IConsole servicio se inserta dentro de los IGreetingService y FarewellService servicios como una dependencia que influye en el comportamiento de la app.
Todos estos servicios se registran como singletons. En este ejemplo, funciona de forma idéntica si los registra como servicios transitorio o con ámbito delimitado.
Importante
En este ejemplo artificioso, las duraciones del servicio no importan. En una aplicación real, considere cuidadosamente la duración de cada servicio.
Ejecutar la aplicación de ejemplo
Para ejecutar la aplicación de ejemplo, presione F5 en Visual Studio o Visual Studio Code o ejecute el dotnet run comando en el terminal. Cuando se complete la aplicación, verá la siguiente salida:
Hello, David!
Goodbye, David!
Descriptores de servicio
Las API más usadas para agregar servicios a ServiceCollection son métodos de extensión genéricos con nombre de duración, como:
AddSingleton<TService>AddTransient<TService>AddScoped<TService>
Estos métodos son métodos útiles que crean una ServiceDescriptor instancia y lo agregan a ServiceCollection.
ServiceDescriptor es una clase sencilla que describe un servicio con su tipo de servicio, tipo de implementación y duración. También puede describir las factorías de implementación y las instancias.
Para cada servicio que registró en ServiceCollection, alternativamente podría llamar al método Add con una instancia ServiceDescriptor directamente. Tenga en cuenta los ejemplos siguientes:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IConsole),
implementationFactory: static _ => new DefaultConsole
{
IsEnabled = true
},
lifetime: ServiceLifetime.Singleton));
El código anterior es equivalente a cómo se registró el servicio IConsole en el ServiceCollection. El Add método agrega una ServiceDescriptor instancia que describe el IConsole servicio. El método ServiceDescriptor.Describe estático se delega en varios ServiceDescriptor constructores. Considere el código equivalente para el IGreetingService servicio:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(IGreetingService),
implementationType: typeof(DefaultGreetingService),
lifetime: ServiceLifetime.Singleton));
El código anterior describe el IGreetingService servicio con su tipo de servicio, el tipo de implementación y la duración. Por último, considere el código equivalente para el FarewellService servicio:
services.Add(ServiceDescriptor.Describe(
serviceType: typeof(FarewellService),
implementationType: typeof(FarewellService),
lifetime: ServiceLifetime.Singleton));
En el código anterior se describe el tipo concreto FarewellService como el servicio y los tipos de implementación. El servicio se registra como un servicio singleton.