首页 文章

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

提问于
浏览
45

我是ASP.NET的新手,目前正在学习ASP.NET身份 . 我知道它 Build 在微软的OWIN实现之上,我也在学习 . 所以,我在Owin启动代码中遇到了扩展方法CreatePerOwinContext,我没有看到使用它的明确目的 . 它是某种依赖注入容器吗?该方法的真正目的是什么?在什么情况下应该应用它?

3 回答

  • 61

    CreatePerOwinContext注册一个静态回调,您的应用程序将使用该回调来获取指定类型的新实例 .
    每个请求将调用一次此回调,并将对象/对象存储在 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 中,您将注册回调:

    // 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>();
    
  • 2

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

    为了更直接地回答你的问题,这是没用的 .

    • 这是某种人喜欢使用的IoC工厂 .

    • 这个让你使用他们的(IoC)而不是你的选择 .

    • (我不喜欢IoC,对于那些想要感到温暖和模糊并且使用术语"architecture"的人来说,感觉就像一个反模式 . )

    • 但是说真的,这个模式不是那个想法吗?为什么不自己使用Factory功能?现在你必须记住(谷歌)额外的API调用,当你在 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();
            }
        }
    
    }
    

    所有这些都可能是浪费时间,如果有人找到一些文档,为什么微软的工程师会把它放进去,他们可能有充分的理由,但我对此表示怀疑,所以让我们在此期间提出这个答案 .

    UPDATE

    这里有's the why, why it'在那里为微软: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");
    }
    

    显然,我更喜欢你能看到的详细代码 .

  • 4

    您可以使用 typeof 获取如下名称:

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

相关问题