web-dev-qa-db-ja.com

AutofacコンテナーをASPにプラグインする方法。 NET Identity 2.1

ASP.NET Identity 2.1の新バージョンの新機能を検討してきましたが、その拡張機能の1つは、OWINミドルウェアに統合された新しいIoC機能です。例で見た文章の1つは次のとおりです。

app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

この文は、例で提供されているマネージャー実装の新しいインスタンスを返す関数デリゲートを受け取ります。

 public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options,
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>())); 

これらのマネージャーに必要な依存関係を挿入するためにコンテナーを使用できないため、個人的にはこの実装が好きではありません。

また、「IdentityFactoryOptions」と「IOwinContext」があり、これらは「魔法のように」関数に挿入されますが、IoCコンテナーにプルできません。

この実装で誰かがより良い回避策を持っていますか?

38
renelopez

すぐに使用できるMVC5インストールから開始し、AutoFacをIoCコンテナーとして使用しています。私はあなたと同じような目標を達成しようとしているようですので、私がやったことを説明させてください。免責事項として、IoCを使用することとIdentityを使用することはかなり新しいです。

独自のものを使用している場合、IoCとしての役割ではIOwinContextは不要だと思います-AutoFacでApplicationUserManagerを登録するように切り替えました。これを達成するために私はしなければなりませんでした:

AutoFacにApplicationDbContextApplicationUserManagerを登録するので、Startup.AuthからCreatePerOwinContextの行を削除します。

//app.CreatePerOwinContext(ApplicationDbContext.Create);
//app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);

ApplicationUserManagerコンストラクター引数を変更し、Create関数からのすべてを含めました。

public ApplicationUserManager(IUserStore<ApplicationUser> store, IdentityFactoryOptions<ApplicationUserManager> options)
        : base(store)
{
    //all the code from the 'Create' function here, using `this` for `manager`
}

ApplicationUserManagerを引数として取り、UserManagerからApplicationUserManagerを取得するOwinContextプロパティを破棄する単一のコンストラクターを持つようにAccountControllerを設定します。

private ApplicationUserManager _userManager; //every thing that needs the old UserManager property references this now
public AccountController(ApplicationUserManager userManager) 
{
    _userManager = userManager;
}

IdentityFactoryOptionsのインスタンスを含むすべてをAutoFacに登録します。

var x = new ApplicationDbContext();
builder.Register<ApplicationDbContext>(c => x);
builder.Register<UserStore<ApplicationUser>>(c => new UserStore<ApplicationUser>(x)).AsImplementedInterfaces();
builder.Register<IdentityFactoryOptions<ApplicationUserManager>>(c => new IdentityFactoryOptions<ApplicationUserManager>()
{
    DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
});
builder.RegisterType<ApplicationUserManager>();

それが大まかな要約です。私は途中でやらなければならなかったいくつかの他の微調整を逃したかもしれません。

48
Ben Bartle

ベンの答えは一般的な考え方を正しくしますが、DbContextを手動でインスタンス化し、残りの型を登録するときにこのインスタンスを使用します。 IMO、それは悪い考えです(すべての要求に同じ永遠のdbコンテキストを使用するべきではありません)。

Derekのコメントは大幅に改善されましたが、データベースコンテキストをユーザーストアに渡さないため、「エンティティタイプApplicationUserは現在のコンテキストのモデルの一部ではありません」などのエラーが発生します。

参照用に以下のコードを含めました-これはデレクのものと非常に似ています。

builder.RegisterType<MyApplicationContext>().AsSelf().InstancePerRequest()
//...

builder.RegisterType<ApplicationUserManager>().AsSelf().InstancePerRequest();
builder.RegisterType<ApplicationSignInManager>().AsSelf().InstancePerRequest();
builder.Register(c => new UserStore<ApplicationUser>(c.Resolve<MyApplicationContext>())).AsImplementedInterfaces().InstancePerRequest();
builder.Register(c => HttpContext.Current.GetOwinContext().Authentication).As<IAuthenticationManager>();
builder.Register(c => new IdentityFactoryOptions<ApplicationUserManager>
{
    DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("Application​")
}); 
29
Vlad Iliescu

参考までに、Unityを使用してすべてを接続する方法を次に示します。

var container = new UnityContainer();

container.RegisterType<MyDbContext>(new InjectionConstructor("ConnectionStringName"));

container.RegisterType<IAuthenticationManager>(
   new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));

container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
   new InjectionConstructor(typeof(MyDbContext)));

container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(
   new InjectionConstructor(typeof(MyDbContext)));

container.RegisterType<IdentityFactoryOptions<ApplicationUserManager>>(new InjectionFactory(x =>
   new IdentityFactoryOptions<ApplicationUserManager>
   {
      DataProtectionProvider = new Microsoft.Owin.Security.DataProtection.DpapiDataProtectionProvider("ApplicationName")
   }));

container.RegisterType<ApplicationSignInManager>();

DependencyResolver.SetResolver(new UnityDependencyResolver(container));
4

Autofac DocsでのMVC5 Owin統合 の詳細:

  • 標準のMVC統合のためのすべてのことを行います-コントローラーの登録、依存関係リゾルバーの設定など.
  • 基本的なAutofac OWIN統合を使用してアプリをセットアップします。
  • Autofac.Mvc5.Owin NuGetパッケージへの参照を追加します。
  • アプリケーションのスタートアップクラスで、ベースAutofacミドルウェアを登録した後、Autofac MVCミドルウェアを登録します。

    public class Startup
    {
      public void Configuration(IAppBuilder app)
      {
       var builder = new ContainerBuilder();
    
      // STANDARD MVC SETUP:
    
      // Register your MVC controllers.
      builder.RegisterControllers(typeof(MvcApplication).Assembly);
    
      // Run other optional steps, like registering model binders,
      // web abstractions, etc., then set the dependency resolver
      // to be Autofac.
      var container = builder.Build();
      DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
    
      // OWIN MVC SETUP:
    
      // Register the Autofac middleware FIRST, then the Autofac MVC middleware.
      app.UseAutofacMiddleware(container);
      app.UseAutofacMvc();
      }
    }
    

RoleManagerラッパーもあるので追加しました:

builder.RegisterType<RoleStore<IdentityRole>>().As<IRoleStore<IdentityRole, string>>();

SO回答

2
OzBob

Autofacサービスロケーターを使用して回避策を管理しました。

app.CreatePerOwinContext(() => DependencyResolver.Current.GetService<ApplicationUserManager>());

はい、それは十分ではありませんが、その間に、autofac登録プロセスで宣言されたのと同じスコープをオブジェクトを使用できます。

1
atthakorn