如何在.Net Core控制台应用程序中使用Microsoft.Extensions.DependencyInjection?

时间:2018-12-18 01:24:44

标签: c# xamarin dependency-injection .net-core console-application

我有一个要在.NET Core支持的所有平台(Xamarin,Windows,Mac)上运行的库。为此,我需要一个跨平台的DI来处理特定于平台的自定义项,例如存储,安全性等。

我为Microsoft.Extensions.DependencyInjection看到的所有示例都包含ASP.NET Core的代码。控制台应用程序是否存在任何等效/受支持的方案?

(理想情况下)我希望用于控制台的DI框架适用于ASP.NET Core,Xamarin和Win32

错误示例

我使用this code作为.NET Core应用程序的基础。看来ServiceCollection应该是公开的,但是当我在Mac上使用Xamarin时,缺少IServiceCollection(ServiceCollection)的默认实现:

enter image description here

2 个答案:

答案 0 :(得分:2)

我基本上像这样使用它:

安装nuget Microsoft.Extensions.DependencyInjection

然后在Program.cs中

using Microsoft.Extensions.DependencyInjection;

 public class Program
    {
        public static void Main(string[] args)
        {

            var services = new ServiceCollection()
                .AddSingleton<WhateverType>(new WhateverType());

            var serviceProvider = services.BuildServiceProvider();


            serviceProvider.GetService<WhateverType>().DoWork();
        }
    }

答案 1 :(得分:-5)

Microsoft.Extensions.DependencyInjection链接简介

https://docs.microsoft.com/en-us/archive/msdn-magazine/2016/june/essential-net-dependency-injection-with-net-core

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1

https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions.addtransient?view=dotnet-plat-ext-3.1

https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicecollectionserviceextensions.addscoped?view=dotnet-plat-ext-3.1

https://docs.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.activatorutilities?view=dotnet-plat-ext-3.1

Microsoft.Extensions.DependencyInjection示例

using Microsoft.Extensions.DependencyInjection;

public class Program
{
    public static void Main(string[] args)
    {

        var services = new ServiceCollection();

        services.AddSingleton<WhateverType>(new WhateverType());
        services.AddScoped<IMyDependency, MyDependency>();
        services.AddTransient<IOperationTransient, Operation>();  

        services.AddInstance<ILoggerFactory>(new Logging.LoggerFactory());
        ILoggingFactory loggingFactor = services.GetRequiredService<ILoggerFactory>();
        ILoggingFactory loggingFactor2 = services.GetService<ILoggingFactory>();

        var serviceProvider = services.BuildServiceProvider();                     
        serviceProvider.GetService<WhateverType>().DoWork();
    }
}

Microsoft.Extensions.DependencyInjection示例

public interface IOperation
{
    Guid OperationId { get; }
}

public interface IOperationTransient : IOperation
{
}

public interface IOperationScoped : IOperation
{
}

public interface IOperationSingleton : IOperation
{
}

public interface IOperationSingletonInstance : IOperation
{
}




public class Operation : IOperationTransient, 
    IOperationScoped, 
    IOperationSingleton, 
    IOperationSingletonInstance
{
    public Operation() : this(Guid.NewGuid())
    {
    }

    public Operation(Guid id)
    {
        OperationId = id;
    }

    public Guid OperationId { get; private set; }
}





public class OperationService
{
    public OperationService(
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance instanceOperation)
    {
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = instanceOperation;
    }

    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }
}



public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));

    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}



public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(
        IMyDependency myDependency, 
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _myDependency = myDependency;
        OperationService = operationService;
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = singletonInstanceOperation;
    }

    public OperationService OperationService { get; }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public async Task OnGetAsync()
    {
        await _myDependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}


using System;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

public class Program
{
    public static async Task Main(string[] args)
    {
        var host = CreateHostBuilder(args).Build();

        using (var serviceScope = host.Services.CreateScope())
        {
            var services = serviceScope.ServiceProvider;

            try
            {
                var serviceContext = services.GetRequiredService<MyScopedService>();
                // Use the context here
            }
            catch (Exception ex)
            {
                var logger = services.GetRequiredService<ILogger<Program>>();
                logger.LogError(ex, "An error occurred.");
            }
        }

        await host.RunAsync();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}



------------
public class Host
{
  public static void Main()
  {
    IServiceCollection serviceCollection = new ServiceCollection();
    ConfigureServices(serviceCollection);
    Application application = new Application(serviceCollection);
    // Run
    // ...
  }
  static private void ConfigureServices(IServiceCollection serviceCollection)
  {
    ILoggerFactory loggerFactory = new Logging.LoggerFactory();
    serviceCollection.AddInstance<ILoggerFactory>(loggerFactory);
  }
}
public class Application
{
  public IServiceProvider Services { get; set; }
  public ILogger Logger { get; set; }
    public Application(IServiceCollection serviceCollection)
  {
    ConfigureServices(serviceCollection);
    Services = serviceCollection.BuildServiceProvider();
    Logger = Services.GetRequiredService<ILoggerFactory>()
            .CreateLogger<Application>();
    Logger.LogInformation("Application created successfully.");
  }
  public void MakePayment(PaymentDetails paymentDetails)
  {
    Logger.LogInformation(
      $"Begin making a payment { paymentDetails }");
    IPaymentService paymentService =
      Services.GetRequiredService<IPaymentService>();
    // ...
  }
  private void ConfigureServices(IServiceCollection serviceCollection)
  {
    serviceCollection.AddSingleton<IPaymentService, PaymentService>();
  }
}
public class PaymentService: IPaymentService
{
  public ILogger Logger { get; }
  public PaymentService(ILoggerFactory loggerFactory)
  {
    Logger = loggerFactory?.CreateLogger<PaymentService>();
    if(Logger == null)
    {
      throw new ArgumentNullException(nameof(loggerFactory));
    }
    Logger.LogInformation("PaymentService created");
  }
}


--------

IPaymentService paymentService = Services.GetRequiredService<IPaymentService>()
----------

public void Configure(IApplicationBuilder app, IOptions<MyOptions> options)
{
    ...
}

--------

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    ...
}

-----------

public class IndexModel : PageModel
{
    private readonly IMyDependency _myDependency;

    public IndexModel(
        IMyDependency myDependency, 
        OperationService operationService,
        IOperationTransient transientOperation,
        IOperationScoped scopedOperation,
        IOperationSingleton singletonOperation,
        IOperationSingletonInstance singletonInstanceOperation)
    {
        _myDependency = myDependency;
        OperationService = operationService;
        TransientOperation = transientOperation;
        ScopedOperation = scopedOperation;
        SingletonOperation = singletonOperation;
        SingletonInstanceOperation = singletonInstanceOperation;
    }

    public OperationService OperationService { get; }
    public IOperationTransient TransientOperation { get; }
    public IOperationScoped ScopedOperation { get; }
    public IOperationSingleton SingletonOperation { get; }
    public IOperationSingletonInstance SingletonInstanceOperation { get; }

    public async Task OnGetAsync()
    {
        await _myDependency.WriteMessage(
            "IndexModel.OnGetAsync created this message.");
    }
}



-----------

public void ConfigureServices(IServiceCollection services)
{
    services.AddRazorPages();

    services.AddScoped<IMyDependency, MyDependency>();
    services.AddTransient<IOperationTransient, Operation>();
    services.AddScoped<IOperationScoped, Operation>();
    services.AddSingleton<IOperationSingleton, Operation>();
    services.AddSingleton<IOperationSingletonInstance>(new Operation(Guid.Empty));

    // OperationService depends on each of the other Operation types.
    services.AddTransient<OperationService, OperationService>();
}



-----------------

var services = new ServiceCollection();

services.AddTransient < SauceBearnaise > ();

ServiceProvider container =
 services.BuildServiceProvider(validateScopes: true);

IServiceScope scope = container.CreateScope();

SauceBearnaise sauce = scope.ServiceProvider.GetRequiredService < SauceBearnaise > ();

 ILoggingFactory loggingFactor = serviceProvider.GetService<ILoggingFactory>();


var services = new ServiceCollection();

services.AddTransient < IIngredient, SauceBearnaise > ();

var container = services.BuildServiceProvider(true);

IServiceScope scope = container.CreateScope();

IIngredient sauce = scope.ServiceProvider
 .GetRequiredService < IIngredient > ();



object Create(ControllerContext context);

Type controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();

Type controllerType = context.ActionDescriptor.ControllerTypeInfo.AsType();
return scope.ServiceProvider.GetRequiredService(controllerType);


services.AddTransient < IIngredient, SauceBearnaise > ();



services.AddTransient < SauceBearnaise > ();
services.AddTransient < IIngredient > (
 c => c.GetRequiredService < SauceBearnaise > ());




services.AddTransient < SauceBearnaise > ();
services.AddTransient < IIngredient > (
 c => c.GetRequiredService < SauceBearnaise > ());




services.AddTransient < SauceBearnaise > ();
services.AddTransient < IIngredient, SauceBearnaise > ();



services.AddSingleton < SauceBearnaise > ();
services.AddSingleton < IIngredient, SauceBearnaise > ();



services.AddTransient < IIngredient, SauceBearnaise > ();
services.AddTransient < ICourse, Course > ();



services.AddTransient < IIngredient, SauceBearnaise > ();
services.AddTransient < IIngredient, Steak > ();



Assembly ingredientsAssembly = typeof(Steak).Assembly;

var ingredientTypes =
 from type in ingredientsAssembly.GetTypes()
where!type.IsAbstract
where typeof(IIngredient).IsAssignableFrom(type)
select type;

foreach(var type in ingredientTypes) {
 services.AddTransient(typeof(IIngredient), type);
}





Assembly ingredientsAssembly = typeof(Steak).Assembly;

var ingredientTypes =
 from type in ingredientsAssembly.GetTypes()
where!type.IsAbstract
where typeof(IIngredient).IsAssignableFrom(type)
where type.Name.StartsWith("Sauce")
select type;

foreach(var type in ingredientTypes) {
 services.AddTransient(typeof(IIngredient), type);
}






Assembly policiesAssembly = typeof(DiscountPolicy).Assembly;

var policyTypes =
 from type in policiesAssembly.GetTypes()
where type.Name.EndsWith("Policy")
select type;

foreach(var type in policyTypes) {
 services.AddTransient(type.BaseType, type);
}




public interface ICommandService < TCommand > {
 void Execute(TCommand command);
}



public class AdjustInventoryService: ICommandService < AdjustInventory > {
 private readonly IInventoryRepository repository;

 public AdjustInventoryService(IInventoryRepository repository) {
  this.repository = repository;
 }

 public void Execute(AdjustInventory command) {
  var productId = command.ProductId;

  ...
 }
}




Assembly assembly = typeof(AdjustInventoryService).Assembly;

var mappings =
 from type in assembly.GetTypes()
where!type.IsAbstract
where!type.IsGenericType
from i in type.GetInterfaces()
where i.IsGenericType
where i.GetGenericTypeDefinition() ==
 typeof(ICommandService < > )
select new {
 service = i, type
};

foreach(var mapping in mappings) {
 services.AddTransient(
  mapping.service,
  mapping.type);
}




services.AddSingleton < SauceBearnaise > ();



services.AddSingleton < IIngredient, SauceBearnaise > ();




using(IServiceScope scope = container.CreateScope()) {
 IMeal meal = scope.ServiceProvider
  .GetRequiredService < IMeal > ();

 meal.Consume();

}




services.AddScoped < IIngredient, SauceBearnaise > ();




container.Dispose();


public enum Spiciness {
 Mild,
 Medium,
 Hot
}



services.AddSingleton(
 typeof(Spiciness), Spiciness.Medium);

services.AddTransient < ICourse, ChiliConCarne > ();



public class Flavoring {
 public readonly Spiciness Spiciness;
 public readonly bool ExtraSalty;

 public Flavoring(Spiciness spiciness, bool extraSalty) {
  this.Spiciness = spiciness;
  this.ExtraSalty = extraSalty;
 }
}




var flavoring = new Flavoring(Spiciness.Medium, extraSalty: true);
services.AddSingleton < Flavoring > (flavoring);

container.AddTransient < ICourse, ChiliConCarne > ();




services.AddTransient < ICourse > (c => new ChiliConCarne(Spiciness.Hot));



public static IServiceCollection AddTransient < TService > (
 this IServiceCollection services,
 Func < IServiceProvider, TService > implementationFactory)
where TService: class;




internal JunkFood(string name)



public static class JunkFoodFactory {
 public static JunkFood Create(string name) {
  return new JunkFood(name);
 }
}


public ChiliConCarne(Spiciness spiciness)

public enum Spiciness {
 Mild,
 Medium,
 Hot
}



services.AddSingleton(
 typeof(Spiciness), Spiciness.Medium);

services.AddTransient < ICourse, ChiliConCarne > ();



public class Flavoring {
 public readonly Spiciness Spiciness;
 public readonly bool ExtraSalty;

 public Flavoring(Spiciness spiciness, bool extraSalty) {
  this.Spiciness = spiciness;
  this.ExtraSalty = extraSalty;
 }
}




var flavoring = new Flavoring(Spiciness.Medium, extraSalty: true);
services.AddSingleton < Flavoring > (flavoring);

container.AddTransient < ICourse, ChiliConCarne > ();





services.AddTransient < ICourse > (c => new ChiliConCarne(Spiciness.Hot));




public static IServiceCollection AddTransient < TService > (
 this IServiceCollection services,
 Func < IServiceProvider, TService > implementationFactory)
where TService: class;




internal JunkFood(string name)




public static class JunkFoodFactory {
 public static JunkFood Create(string name) {
  return new JunkFood(name);
 }
}








services.AddTransient < IMeal > (c => JunkFoodFactory.Create("chicken meal"));




services.AddTransient < IIngredient, SauceBearnaise > ();
services.AddTransient < IIngredient, Steak > ();







IEnumerable < IIngredient > ingredients =
 scope.ServiceProvider.GetServices < IIngredient > ();


IEnumerable < IIngredient > ingredients = scope.ServiceProvider
 .GetRequiredService < IEnumerable < IIngredient >> ();



public ThreeCourseMeal(ICourse entrée, ICourse mainCourse, ICourse dessert)







services.AddTransient < IMeal > (c => new ThreeCourseMeal(
 entrée: c.GetRequiredService < Rillettes > (),
 mainCourse: c.GetRequiredService < CordonBleu > (),
 dessert: c.GetRequiredService < CrèmeBrûlée > ()));



public ThreeCourseMeal(
 ICourse entrée,
 ICourse mainCourse,
 ICourse dessert,
 ...
)




services.AddTransient < IMeal > (c =>
 ActivatorUtilities.CreateInstance < ThreeCourseMeal > (
  c,
  new object[] {
   c.GetRequiredService < Rillettes > (),
    c.GetRequiredService < CordonBleu > (),
    c.GetRequiredService < MousseAuChocolat > ()
  }));



public static T CreateInstance < T > (
 IServiceProvider provider,
 params object[] parameters);



public Meal(IEnumerable < ICourse > courses)


services.AddTransient < ICourse, Rillettes > ();
services.AddTransient < ICourse, CordonBleu > ();
services.AddTransient < ICourse, MousseAuChocolat > ();

services.AddTransient < IMeal, Meal > ();



services.AddScoped < Rillettes > ();
services.AddTransient < LobsterBisque > ();
services.AddScoped < CordonBleu > ();
services.AddScoped < OssoBuco > ();
services.AddSingleton < MousseAuChocolat > ();
services.AddTransient < CrèmeBrûlée > ();

services.AddTransient < ICourse > (
 c => c.GetRequiredService < Rillettes > ());
services.AddTransient < ICourse(
 c => c.GetRequiredService < LobsterBisque > ());
services.AddTransient < ICourse > (
 c => c.GetRequiredService < CordonBleu > ());
services.AddTransient < ICourse(
 c => c.GetRequiredService < OssoBuco > ());
services.AddTransient < ICourse > (
 c => c.GetRequiredService < MousseAuChocolat > ());
services.AddTransient < ICourse(
 c => c.GetRequiredService < CrèmeBrûlée > ());

services.AddTransient < IMeal > (c = new Meal(
 new ICourse[] {
  c.GetRequiredService < Rillettes > (),
   c.GetRequiredService < CordonBleu > (),
   c.GetRequiredService < MousseAuChocolat > ()
 }));






services.AddTransient < IIngredient > (c =>
 ActivatorUtilities.CreateInstance < Breading > (
  c,
  ActivatorUtilities
  .CreateInstance < VealCutlet > (c)));



services.AddTransient < IIngredient > (c =>
 ActivatorUtilities.CreateInstance < Breading > (
  c,
  ActivatorUtilities
  .CreateInstance < HamCheeseGarlic > (
   c,
   ActivatorUtilities
   .CreateInstance < VealCutlet > (c))));







new Breading(
 new HamCheeseGarlic(
  new VealCutlet()));



Assembly assembly = typeof(AdjustInventoryService).Assembly;

var mappings =
 from type in assembly.GetTypes()
where!type.IsAbstract
where!type.IsGenericType
from i in type.GetInterfaces()
where i.IsGenericType
where i.GetGenericTypeDefinition() ==
 typeof(ICommandService < > )
select new {
 service = i, implementation = type
};

foreach(var mapping in mappings) {
 Type commandType =
  mapping.service.GetGenericArguments()[0];

 Type secureDecoratoryType =
  typeof(SecureCommandServiceDecorator < > )
  .MakeGenericType(commandType);
 Type transactionDecoratorType =
  typeof(TransactionCommandServiceDecorator < > )
  .MakeGenericType(commandType);
 Type auditingDecoratorType =
  typeof(AuditingCommandServiceDecorator < > )
  .MakeGenericType(commandType);

 services.AddTransient(mapping.service, c =>
  ActivatorUtilities.CreateInstance(
   c,
   secureDecoratoryType,
   ActivatorUtilities.CreateInstance(
    c,
    transactionDecoratorType,
    ActivatorUtilities.CreateInstance(
     c,
     auditingDecoratorType,
     ActivatorUtilities.CreateInstance(
      c,
      mapping.implementation)))));
}







public class CompositeNotificationService: INotificationService {
 private readonly IEnumerable < INotificationService > services;

 public CompositeNotificationService(
  IEnumerable < INotificationService > services) {
  this.services = services;
 }

 public void OrderApproved(Order order) {
  foreach(INotificationService service in this.services) {
   service.OrderApproved(order);
  }
 }
}




services.AddTransient < OrderApprovedReceiptSender > ();
services.AddTransient < AccountingNotifier > ();
services.AddTransient < OrderFulfillment > ();

services.AddTransient < INotificationService > (c =>
 new CompositeNotificationService(
  new INotificationService[] {
   c.GetRequiredService < OrderApprovedReceiptSender > (),
    c.GetRequiredService < AccountingNotifier > (),
    c.GetRequiredService < OrderFulfillment > (),
  }));




Assembly assembly = typeof(OrderFulfillment).Assembly;

Type[] types = (
  from type in assembly.GetTypes() where!type.IsAbstract where typeof(INotificationService).IsAssignableFrom(type) select type)
 .ToArray();

foreach(Type type in types) {
 services.AddTransient(type);
}

services.AddTransient < INotificationService > (c =>
 new CompositeNotificationService(
  types.Select(t =>
   (INotificationService) c.GetRequiredService(t))
  .ToArray()));





Type[] types = (
  from type in assembly.GetTypes() where!type.IsAbstract where typeof(INotificationService)
  .IsAssignableFrom(type) where type != typeof(CompositeNotificationService) select type)
 .ToArray();




Type[] types = (
  from type in assembly.GetTypes() where!type.IsAbstract where typeof(INotificationService).IsAssignableFrom(type) where type != typeof(CompositeNotificationService) where type => !IsDecoratorFor < INotificationService > (type) select type)
 .ToArray();






private static bool IsDecoratorFor < T > (Type type) {
 return typeof(T).IsAssignableFrom(type) &&
  type.GetConstructors()[0].GetParameters()
  .Any(p => p.ParameterType == typeof(T));
}





public class CompositeSettings {
 public Type[] AllHandlerTypes {
  get;
  set;
 }
}

public class CompositeEventHandler < TEvent >
 : IEventHandler < TEvent > {
  private readonly IServiceProvider provider;
  private readonly CompositeSettings settings;

  public CompositeEventHandler(
   IServiceProvider provider,
   CompositeSettings settings) {
   this.provider = provider;
   this.settings = settings;
  }

  public void Handle(TEvent e) {
   foreach(var handler in this.GetHandlers()) {
    handler.Handle(e);
   }
  }

  IEnumerable < IEventHandler < TEvent >> GetHandlers() {
   return
   from type in this.settings.AllHandlerTypes
   where typeof(IEventHandler < TEvent > )
   .IsAssignableFrom(type)
   select(IEventHandler < TEvent > )
   ActivatorUtilities.CreateInstance(
    this.provider, type);
  }
 }






var handlerTypes =
 from type in assembly.GetTypes()
where!type.IsAbstract
where!type.IsGenericType
let serviceTypes = type.GetInterfaces()
 .Where(i => i.IsGenericType &&
  i.GetGenericTypeDefinition() ==
  typeof(IEventHandler < > ))
where serviceTypes.Any()
select type;

services.AddSingleton(new CompositeSettings {
 AllHandlerTypes = handlerTypes.ToArray()
});

services.AddTransient(
 typeof(IEventHandler < > ),
 typeof(CompositeEventHandler < > ));