web-dev-qa-db-ja.com

MicrosoftによるOWIN実装の拡張メソッドCreatePerOwinContextの目的は何ですか

私はASP.NETの初心者であり、現在ASP.NET Identityを学んでいます。 MicrosoftによるOWIN実装の上に構築されていることは知っていますが、それもまだ学んでいます。そのため、Owinスタートアップコードで拡張メソッドCreatePerOwinContextに出会いましたが、それを使用する明確な目的がわかりません。ある種の依存性注入コンテナですか?メソッドの本当の目的は何ですか?どのような場合に適用する必要がありますか?

48
Next Developer

CreatePerOwinContext は、指定したタイプの新しいインスタンスを取得するためにアプリケーションが使用する静的コールバックを登録します。
このコールバックはリクエストごとに1回呼び出され、オブジェクトをOwinContextに保存するため、全体で使用できます。アプリケーション。

IdentityDbContext の独自の実装を定義したとしましょう。

public class ApplicationDatabaseContext : IdentityDbContext<MyApplicationUser, MyRole, Guid, MyUserLogin, MyUserRole, MyUserClaim>
{
    public ApplicationDatabaseContext() : base("<connection string>")
    {
    }

    public static ApplicationDatabaseContext Create()
    {
        return new ApplicationDatabaseContext();
    }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
        base.OnModelCreating(modelBuilder);

        // Customize your table creation here.

            #region USERS - INFOS

        modelBuilder.Entity<UserInfo>()
            .Property(p => p.FirstName)
            .HasColumnType("varchar")
            .HasMaxLength(70);

        modelBuilder.Entity<UserInfo>()
            .Property(p => p.LastName)
            .HasColumnType("varchar")
            .HasMaxLength(70);

        modelBuilder.Entity<UserInfo>()
            .Property(p => p.Address)
            .HasColumnType("varchar")
            .HasMaxLength(100);

        modelBuilder.Entity<UserInfo>()
            .Property(p => p.City)
            .HasColumnType("varchar")
            .HasMaxLength(100);

        modelBuilder.Entity<UserInfo>()
            .ToTable("UsersInfo");

        #endregion  
        }

        public DbSet<UserInfo> UsersInfo { get; set; }
}

serManager の実装:

public class ApplicationUserManager : UserManager<MyApplicationUser, Guid>
{
    public ApplicationUserManager(IUserStore<MyApplicationUser, Guid> store) : base(store)
        {
        }

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

            manager.UserValidator = new UserValidator<MyApplicationUser, Guid>(manager)
            {
                AllowOnlyAlphanumericUserNames = false,
                RequireUniqueEmail = true
            };

            manager.PasswordValidator = new PasswordValidator()
            {
                RequiredLength = 6,
                RequireNonLetterOrDigit = false,    
                // RequireDigit = true,
                RequireLowercase = false,
                RequireUppercase = false,
            };

            var dataProtectionProvider = options.DataProtectionProvider;

            if (dataProtectionProvider != null)
            {
                manager.UserTokenProvider = new DataProtectorTokenProvider<MyApplicationUser, Guid>(dataProtectionProvider.Create("PasswordReset"));
            }

            return (manager);
        }
}

OwinStartupで、コールバックを登録します。

// IAppBuilder app

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

静的メソッドを呼び出します:

public static ApplicationDatabaseContext Create()
{
    return new ApplicationDatabaseContext();
}

そして

public static ApplicationUserManager Create(IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context)
{
    ...
}

これで、簡単な方法でデータベースコンテキストとユーザーマネージャーにアクセスできるようになります。

ApplicationDatabaseContext dbContext = context.OwinContext.Get<ApplicationDatabaseContext>();
ApplicationUserManager userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();

ApiController(WebApiを使用している場合):

IAuthenticationManager authenticationManager = HttpContext.Current.GetOwinContext().Authentication;
ApplicationUserManager applicationUserManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
65
LeftyX

メソッドの本当の目的は何ですか?どのような場合に適用する必要がありますか?

あなたの質問にもっと直接答えるためには、これは無意味です。

  1. ある種のIoCファクトリーであり、一部の人々はこれを使用しています。
  2. これにより、自分の選択よりも彼ら(IoC)を使用することができます。
  3. (私はIoCが好きではありません。暖かくあいまいに感じ、「アーキテクチャ」という用語を使用したい人にとってはアンチパターンのように感じます。)
  4. しかし、真剣に、このパターンはIoCインターフェースではなく、IoC静的ファクトリー関数です!それは誰の考えですか?ファクトリー機能を自分で使用しないのはなぜですか?ここで、追加のAPI呼び出し(Google)を覚えておく必要があり、GetでF12を押すと、役に立たなくなります。

代わりに何をすべきですか?

個人的に、私はOOを使用することのファンです、OOを覚えていますか?Pepperidgeファームは覚えています。OOを使用すると、制御を維持し、デバッグ、ログ、および拡張できます。

public class BaseApiController : ApiController
{
    private AppDbContext _db = null;

    protected AppDbContext db
    {
        get
        {
            if (_db == null)
            {
                _db = AppDbContext.Create(); //Hey look a proper factory that you can extend with other overloads! And I can debug this line - neat!
            }
            return _db;
        }

    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            if (_db != null)
                _db.Dispose();
        }
    }

}

これはすべて時間の無駄になる可能性があります。Microsoftのエンジニアがこれを入れたドキュメントを誰かが見つけた場合、正当な理由がある可能性がありますが、私はそれを疑います。

更新1

Microsoftが存在する理由、理由は次のとおりです。 https://blogs.msdn.Microsoft.com/webdev/2014/02/12/per-request-lifetime-management-for-usermanager-class-in- asp-net-identity /

基本的に、UserManagerとそれらすべては、この種の構造用に構築されています。セキュリティチェックはパイプラインで行われるので、無駄を減らすために、シングルトンをリクエストにリンクしないのはなぜですか?隠されているからです。

基本クラスでdbコンテキストの独自のインスタンスを作成することを引き続きお勧めします。本当に必要な場合は、OwinContextからシングルトンを取得するプロパティをベースクラスに含めることができます。

私たちがやりたいのは、これらの派手なAPIや認証属性などを試行するのにどれだけの時間を浪費するかです。

public void DoSomething()
{
   DemandAuthenticated();
   DemandAuthorised(typeof(somethingClass), "DoSomething");
}

明らかに、私はあなたが見ることができる冗長なコードを好む。

更新2

EFコンテキストはシングルトンとして保持されるべきではなく、IoCまたはリポジトリパターンを介して保持されるべきではありません。

一般的に、はいIoCは状況に適しています。しかし、特にdbContextの場合は?いや.

1)EF DBコンテキストは作業単位であり、短命でなければなりません。長時間実行し続けると、オブジェクトキャッシュによりクエリの速度が低下し、基になるデータベースへの更新/挿入が遅くなります。寿命が短いように設計されています。 2)また、EFコンテキストは既に疎結合です。接続文字列のコンテキストの背後でRDBMSを変更できます。メモリのみを使用することもできます。 3)EFには、非常に柔軟で表現力豊かで、タイプセーフなLINQがあります。 4)データベースは、IoCのビジネスレベルのサービスではなく、サービスがデータベースとの通信に使用するツールです。おそらく、IoC経由でアクセスされる何らかの種類のサービスIEmailを持っている可能性があります。ただし、クエリの完了後すぐに破棄される新しいEFコンテキストを使用して、内部データベースにアクセスする必要があります。 5)上記の1〜4を考えると、最初にEFを使用する利点をすべて損なう中間インターフェイスレイヤー(サービスまたはリポジトリ)を望まないでしょう。

4
Todd

typeofを使用して、次のような名前を取得できます。

HttpContext.GetOwinContext().Get<ApplicationDbContext>(typeof(ApplicationDbContext).ToString());
2
charlie Francis