Microsoft的OWIN实现中的扩展方法CreatePerOwinContext的目的是什么?

我是ASP.NET的新手,目前正在学习ASP.NET身份。 我知道它是build立在微软OWIN实施之上的,我也正在学习。 所以,我遇到了Owin启动代码中的扩展方法CreatePerOwinContext,我没有看到使用它的明确目的。 它是一种dependency injection容器吗? 这个方法的真正目的是什么? 在什么情况下应该适用?

CreatePerOwinContext注册一个静态的callback,你的应用程序将用它来取回一个指定types的新实例。
这个callback将在每个请求中被调用一次,并将对象/对象存储在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; } } 

和你的UserManager的实现:

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

在你的Owin Startup中,你将注册callback:

 // 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) { ... } 

现在,您将能够以简单直接的方式访问数据库上下文和用户pipe理器:

 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>(); 

你可以使用typeof来得到这样的名字:

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

这个方法的真正目的是什么? 在什么情况下应该适用?

要更直接地回答你的问题,这是无用的。

  1. 这是一些IoC工厂,有些人喜欢使用。
  2. 这一个让你使用他们(IoC)在你的select。
  3. (我不喜欢IoC,对于那些想要感觉温暖和模糊,并使用术语“架构”的人来说,感觉就像是反模式)。
  4. 但是严重的是,这个模式并不是IoC接口,而是IoC静态工厂的function! 谁的主意是? 为什么不自己使用工厂function? 现在您必须记住(Google)一个额外的API调用,并且当您在Get上按F12时,它将无处帮助您。

那你应该怎么做呢?

就个人而言,我是使用面向对象的粉丝,记得面向对象? Pepperidge农场记得。 有了OO,你仍然可以控制,你可以debugging,login,并且可以扩展。

 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(); } } } 

所有这些都可能是浪费时间,如果有人find一些微软工程师为什么要这样做的文档,他们可能有一个很好的理由,但是我怀疑它,所以让我们在这个答案上同意。

UPDATE

这就是为什么,为什么它在微软: https : //blogs.msdn.microsoft.com/webdev/2014/02/12/per-request-lifetime-management-for-usermanager-class-in-asp-net-身份/

基本上,UserManager和它们都是为这种结构而build立的。 安全检查发生在pipe道中,为什么没有一个单一的请求链接,以减less浪费? 因为它是隐藏的

我仍然build议在基类上创build自己的数据库上下文的实例,这使得它更清洁。 如果你真的想要,你可以在你的基类中有一个属性来从OwinContext中获取单例。

我们浪费了多less时间来研究这些奇特的API,并授权属性等,当我们所要做的是:

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

显然,我更喜欢详细的代码,你可以看到。