Подтвердить что ты не робот

IServiceProvider в ядре ASP.NET

Я начинаю изучать изменения в ASP.NET 5 (vNext) и не может найти, как получить IServiceProvider, например, в методе "Модель"

public class Entity 
{
     public void DoSomething()
     { 
           var dbContext = ServiceContainer.GetService<DataContext>(); //Where is ServiceContainer or something like that ?
     }
}

Я знаю, мы настраиваем службы при запуске, но где все службы сбора остаются или IServiceProvider?

4b9b3361

Ответ 1

Вы должны ввести пространство имен Microsoft.Extensions.DependencyInjection чтобы получить доступ к универсальному

GetService<T>();

метод расширения, который должен использоваться на

IServiceProvider 

Также обратите внимание, что вы можете напрямую внедрять сервисы в контроллеры в ASP.NET 5. Смотрите пример ниже.

public interface ISomeService
{
    string ServiceValue { get; set; }
}

public class ServiceImplementation : ISomeService
{
    public ServiceImplementation()
    {
        ServiceValue = "Injected from Startup";
    }

    public string ServiceValue { get; set; }
}

Startup.cs

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

HomeController

using Microsoft.Extensions.DependencyInjection;
...
public IServiceProvider Provider { get; set; }
public ISomeService InjectedService { get; set; }

public HomeController(IServiceProvider provider, ISomeService injectedService)
{
    Provider = provider;
    InjectedService = Provider.GetService<ISomeService>();
}

Любой подход может быть использован для получения доступа к услуге. Дополнительные сервисные расширения для Startup.cs

AddInstance<IService>(new Service())

Один экземпляр дается все время. Вы несете ответственность за создание начального объекта.

AddSingleton<IService, Service>()

Создается один экземпляр, и он действует как синглтон.

AddTransient<IService, Service>()

Новый экземпляр создается каждый раз, когда он вводится.

AddScoped<IService, Service>()

Один экземпляр создается внутри текущей области HTTP-запроса. Это эквивалентно Singleton в текущем контексте.

Обновлено 18 октября 2018 года

Смотрите: aspnet GitHub - ServiceCollectionServiceExtensions.cs

Ответ 2

Я не думаю, что хорошая идея для объекта (или модели) иметь доступ к любой службе.

У контроллеров, с другой стороны, есть доступ к любой зарегистрированной службе в их конструкторах, и вам не нужно беспокоиться об этом.

public class NotifyController : Controller
{
    private static IEmailSender emailSender = null;
    protected static ISessionService session = null;
    protected static IMyContext dbContext = null;
    protected static IHostingEnvironment hostingEnvironment = null;

    public NotifyController(
                IEmailSender mailSenderService,
                IMyContext context,
                IHostingEnvironment env,
                ISessionService sessionContext)
    {
        emailSender = mailSenderService;
        dbContext = context;
        hostingEnvironment = env;
        session = sessionContext;
    }
}

Ответ 3

используйте GetRequiredService вместо GetService, например, пример в учебниках Core для ASP.NET(https://docs.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/working-with-sql)

документация по методу:

https://docs.microsoft.com/en-us/aspnet/core/api/microsoft.extensions.dependencyinjection.serviceproviderserviceextensions#Microsoft_Extensions_DependencyInjection_ServiceProviderServiceExtensions_GetRequiredService__1_System_IServiceProvider_

using Microsoft.Extensions.DependencyInjection;

      using (var context = new ApplicationDbContext(serviceProvicer.GetRequiredService<DbContextOptions<ApplicationDbContext>>()))

Ответ 4

Как правило, вы хотите, чтобы DI делал свое дело и вводил это для вас:

public class Entity 
{
    private readonly IDataContext dbContext;

    // The DI will auto inject this for you
    public class Entity(IDataContext dbContext)
    {
        this.dbContext = dbContext;
    }

     public void DoSomething()
     {
         // dbContext is already populated for you
         var something = dbContext.Somethings.First();
     }
}

Однако Entity должен быть автоматически создан для вас... как Controller или ViewComponent. Если вам нужно вручную создать экземпляр этого файла из места, где этот dbContext недоступен для вас, вы можете сделать это:

using Microsoft.Extensions.PlatformAbstractions;

public class Entity 
{
    private readonly IDataContext dbContext;

    public class Entity()
    {
        this.dbContext = (IDataContext)CallContextServiceLocator.Locator.ServiceProvider
                            .GetService(typeof(IDataContext));
    }

     public void DoSomething()
     {
         var something = dbContext.Somethings.First();
     }
}

Но просто для того, чтобы подчеркнуть, это считается анти-шаблоном, и его следует избегать, если это абсолютно необходимо. И... рискуя сделать некоторые шаблоны людьми действительно расстроены... если все остальное не удается, вы можете добавить static IContainer в вспомогательный класс или что-то еще и назначить его в своем классе StartUp в методе ConfigureServices: MyHelper.DIContainer = builder.Build(); И это действительно уродливый способ сделать это, но иногда вам просто нужно заставить его работать.

Ответ 5

Вместо того, чтобы использовать вашу службу inline, попробуйте ввести ее в конструктор.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddTransient(typeof(DataContext));
    }
}

public class Entity
{
    private DataContext _context;

    public Entity(DataContext context)
    {
        _context = context;
    }

    public void DoSomething()
    {
        // use _context here
    }
}

Я также предлагаю прочитать информацию о том, что означает AddTransient, так как это существенно повлияет на то, как ваше приложение использует экземпляры DbContext. Это шаблон, называемый Injection of Dependency. Чтобы привыкнуть, требуется некоторое время, но вы никогда не захотите возвращаться, как только вы это сделаете.

Ответ 6

Я думаю, что ОП становится запутанным. Сущности должны быть как можно более "тонкими". Они должны стараться не содержать логику и/или внешние ссылки, кроме свойств навигации. Посмотрите на некоторые общие шаблоны, такие как шаблон репозитория, который помогает абстрагировать вашу логику от самих сущностей.