2015-09-08 2 views
94

Как вручную разрешить тип с помощью встроенной среды ввода-вывода ASP.NET Core MVC?Устранение экземпляров с помощью ASP.NET Core DI

Настройка контейнера достаточно легко:

public void ConfigureServices(IServiceCollection services) 
{ 
    // ... 

    services.AddTransient<ISomeService, SomeConcreteService>(); 
} 

Но как я могу решить ISomeService без выполнения инъекции? Например, я хочу сделать это:

ISomeService service = services.Resolve<ISomeService>(); 

Там нет таких методов в IServiceCollection.

+0

возможно дубликат [Как решить Instance Внутри ConfigureServices в ASP.NET 5 ] (http://stackoverflow.com/questions/31863981/how-to-resolve-instance-inside-configureservices-in-asp-net-5) –

+1

Do y ou хотят разрешить их в методе 'ConfigureServices()' (с 'IServiceCollection') или просто в любом месте приложения? –

+1

@HenkMollema: Везде внутри автозагрузки на самом деле. – davenewza

ответ

142

Есть несколько вариантов в Startup классе.

инъекционные зависимости
Среды могут впрыскивать службы времени выполнения в конструкторе Startup класса, такие как IHostingEnvironment и IServiceProvider.

Услуги также могут быть введены в метод Configure(). Вы можете добавить произвольное количество параметров после параметра IApplicationBuilder. Вы также можете ввести свои собственные услуги, которые зарегистрированы в методе ConfigureServices() здесь. Однако метод ConfigureServices() не разрешает инъекционные услуги, он принимает только аргумент IServiceCollection.

вручную разрешающие зависимости
Если вы хотите, чтобы вручную разрешить услуги, вы можете позволить времени выполнения впрыснуть IServiceProvider экземпляр в конструктор и метод Configure():

public Startup(IServiceProvider serviceProvider) 
{ 
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>(); 
} 

или

public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider) 
{ 
    var hostingEnv = serviceProvider.GetService<IHostingEnvironment>(); 
} 

Однако, если вам необходимо разрешить службы в методе ConfigureServices(), вам нужно будет отличать t подход. Вы можете создать промежуточный IServiceProvider из IServiceCollection экземпляра, который содержит услуги, которые не зарегистрированы до тех пор:

public void ConfigureService(IServiceCollection services) 
{ 
    services.AddSingleton<ISomeService, SomeService>(); 

    // Build the intermediate service provider 
    var sp = services.BuildServiceProvider(); 
    var service = sp.GetService<ISomeService>(); 
} 

Вам нужен Microsoft.Extensions.DependencyInjection пакета для этого.

+1

@HenkMollema, но что, если я не могу ничего вводить, я имею в виду, что я не могу вводить 'IServiceCollection', какой-то класс, который создается вручную (_out of middleware scope_), планировщик в моем случае, который периодически необходим некоторые службы для создания и отправки электронной почты. –

+7

* предупреждение *, если вам нужно разрешить службы в 'ConfigureServices', и эта услуга является синглом, это будет другой синглтон, который будет использоваться вашим контроллером! Я предполагаю, что это связано с тем, что он использует другой 'IServiceProvider' - чтобы избежать этого, НЕ разрешайте с помощью' BuildServiceProvider' и вместо этого переместите поиск одного синглета из 'ConfigureServices' в' Configure (.. другие параметры, IServiceProvider serviceProvider) 'in' Startup.cs' – wal

+1

@wal хороший пункт. Поскольку это другой экземпляр «IServiceProvider», он создаст новый экземпляр singleton. Это можно избежать, возвращая экземпляр поставщика услуг из метода ConfigureServices, так что это будет контейнер, в котором также используется ваше приложение. –

34

вручную разрешающие экземпляров предполагает использование интерфейса IServiceProvider:

Разрешение зависимостей в Startup.ConfigureServices

public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddTransient<IMyService, MyService>(); 

    var serviceProvider = services.BuildServiceProvider(); 
    var service = serviceProvider.GetService<IMyService>(); 
} 

Разрешающая Зависимости в Startup.Configure

public void Configure(
    IApplicationBuilder application, 
    IServiceProvider serviceProvider) 
{ 
    // By type. 
    var service1 = (MyService)serviceProvider.GetService(typeof(MyService)); 

    // Using extension method. 
    var service2 = serviceProvider.GetService<MyService>(); 

    // ... 
} 

Using Runtime Введенный Услуги

мне типы могут быть введены в качестве параметров методы:

public class Startup 
{ 
    public Startup(
     IHostingEnvironment hostingEnvironment, 
     ILoggerFactory loggerFactory) 
    { 
    } 

    public void ConfigureServices(
     IServiceCollection services) 
    { 
    } 

    public void Configure(
     IApplicationBuilder application, 
     IHostingEnvironment hostingEnvironment, 
     IServiceProvider serviceProvider, 
     ILoggerFactory loggerfactory, 
     IApplicationLifetime applicationLifetime) 
    { 
    } 
} 
+0

Во втором коде, что такое метод расширения? : // Использование метода расширения. –

+1

@AfsharMohebbi «GetService», который является общим, является методом расширения в пространстве имен Microsoft.Extensions.DependencyInjection. –

6

При создании приложения с помощью шаблона вы будете иметь что-то вроде этого на Startup класс:

public void ConfigureServices(IServiceCollection services) 
{ 
    // Add framework services. 
    services.AddApplicationInsightsTelemetry(Configuration); 

    services.AddMvc(); 
} 

Вы можете добавить зависимости есть, например:

services.AddTransient<ITestService, TestService>(); 

Если вы хотите получить доступ к ITestService на своем контроллере, вы можете добавить IServiceProvider на конструктор, и он будет вводиться:

public HomeController(IServiceProvider serviceProvider) 

Затем вы можете разрешить службу вы добавили:

var service = serviceProvider.GetService<ITestService>(); 

Обратите внимание, что для использования универсальной версии, вы должны включать в себя пространство имен с расширениями:

using Microsoft.Extensions.DependencyInjection; 

ITestService.cs

public interface ITestService 
{ 
    int GenerateRandom(); 
} 

Tes tService.cs

public class TestService : ITestService 
{ 
    public int GenerateRandom() 
    { 
     return 4; 
    } 
} 

Startup.cs (ConfigureServices)

public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddApplicationInsightsTelemetry(Configuration); 
    services.AddMvc(); 

    services.AddTransient<ITestService, TestService>(); 
} 

HomeController.cs

using Microsoft.Extensions.DependencyInjection; 

namespace Core.Controllers 
{ 
    public class HomeController : Controller 
    { 
     public HomeController(IServiceProvider serviceProvider) 
     { 
      var service = serviceProvider.GetService<ITestService>(); 
      int rnd = service.GenerateRandom(); 
     } 
0
public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddMvc(); 

    services.AddDbContext<ConfigurationRepository>(options => 
     options.UseSqlServer(Configuration.GetConnectionString("SqlConnectionString"))); 

    services.AddScoped<IConfigurationBL, ConfigurationBL>(); 
    services.AddScoped<IConfigurationRepository, ConfigurationRepository>(); 
} 
+3

Ваши ответы более вероятно будут приняты и одобрены, если вы дадите краткое объяснение * почему * это хороший ответ, а не только фрагмент кода. Это также помогает азбуку быть уверенным, что это фактически отвечает на вопрос, который они задали. –

+0

Кто-то неправильно отметил ваш ответ как некачественный.Вы должны добавить некоторый сопроводительный текст, чтобы объяснить, как работает ваш ответ, чтобы предотвратить дальнейшее пометку и/или downvotes. Ответ только на код [не является некачественным] (https://meta.stackoverflow.com/a/358757/1364007). Он пытается ответить на вопрос? Если нет, отметьте как «не ответ» или рекомендуем удалить (если в очереди просмотра). б) Это технически некорректно? До нисходящий или комментарий. [Из обзора] (https://stackoverflow.com/review/low-quality-posts/18823309). –

Смежные вопросы