web-dev-qa-db-ja.com

ASP.NET CoreのIServiceProvider

ASP.NET 5(vNext))の変更を学習し始め、「モデル」のメソッドなどでIServiceProviderを取得する方法を見つけることができません

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

起動時にサービスを構成しますが、すべてのサービスコレクションが残っているのはIServiceProviderですか?

28
Sam

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 Requestスコープ内に単一のインスタンスが作成されます。現在のスコープコンテキストのシングルトンと同等です。

2018年10月18日に更新

参照: aspnet GitHub-ServiceCollectionServiceExtensions.cs

49
Jaime Still

エンティティ(またはモデル)がサービスにアクセスするのは良い考えではないと思います。

一方、コントローラーは、コンストラクターで登録されたサービスにアクセスできるので、心配する必要はありません。

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;
    }
}
4

aSP.NET Coreの例のように、GetServiceの代わりにGetRequiredServiceを使用しますチュートリアル( 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
juFo

一般的に、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は、ControllerViewComponentのように自動的にインスタンス化する必要があります。この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();そして、これは本当にい方法ですが、動作させる必要がある場合もあります。

2
Serj Sagan

サービスをインラインで取得する代わりに、コンストラクタに挿入してみてください。

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
    }
}

また、アプリケーションがDbContextのインスタンスを共有する方法に大きな影響を与えるため、AddTransientの意味を調べることをお勧めします。これは Dependency Injection と呼ばれるパターンです。慣れるまでには時間がかかりますが、一度戻ってしまうことはありません。

1
Anton

OPは混乱していると思います。エンティティは可能な限り「薄く」する必要があります。ロジックやナビゲーションプロパティ以外の外部参照を含めないようにする必要があります。エンティティ自体からロジックを抽象化するのに役立つリポジトリパターンなどの一般的なパターンを検索します

0
Robert Perry