Какова цель метода расширения CreatePerOwinContext в реализации OWIN корпорацией Майкрософт

Я новичок в ASP.NET, и в настоящее время обучение ASP.NET личность. Я знаю, что он построен поверх реализации OWIN Microsoft, и я также все еще учусь этому. Итак, я наткнулся на метод расширения CreatePerOwinContext в коде запуска Owin, и я не вижу четкой цели его использования. Это какой-то контейнер внедрения зависимостей? Какова реальная цель метода? В каком случае его следует применять?

3 ответов


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 запуск вы зарегистрируете обратный вызов:

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

какова реальная цель этого метода? В каком случае следует применены?

чтобы ответить на ваш вопрос более прямо, это бесполезно.

  1. это своего рода фабрика МОК, которую некоторые люди любят использовать.
  2. это заставляет вас использовать их (МОК) по вашему выбору.
  3. (мне не нравится МОК, это похоже на анти-шаблон для людей, которые хотят чувствовать себя теплыми и нечеткими и использовать термин "архитектура.")
  4. но серьезно, этот шаблон не интерфейсы IoC, это статические заводские функции IoC! Чья это была идея? Почему бы просто не использовать заводскую функцию самостоятельно? Теперь вам нужно запомнить (Google) дополнительный вызов API, и когда вы нажимаете F12 на Get, он не принимает вас нигде полезно.

что вы должны делать вместо этого?

лично я поклонник использования OO для этого, помните OO? Пепперидж фарм помнит. С 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 поместили это, у них может быть веская причина, но я сомневаюсь в этом, поэтому давайте пока повторим этот ответ.

обновление

вот почему, почему это там для Microsoft: https://blogs.msdn.microsoft.com/webdev/2014/02/12/per-request-lifetime-management-for-usermanager-class-in-asp-net-identity/

в основном, UserManager и все они построены для такого рода структуры. Проверки безопасности происходят в конвейере, так почему бы не иметь синглтон, связанный с запросом, чтобы уменьшить отходы? Потому что он спрятан.

Я бы все равно рекомендовал создать свой собственный экземпляр контекста db на baseclass, это делает его намного чище использовать. Если вы действительно хотите, у вас может быть свойство в вашем baseclass, которое извлекает синглтон из OwinContext.

сколько времени мы тратим, пытаясь разработать эти причудливые API и разрешить атрибуты и тому подобное, когда все, что мы хотим сделать, это:

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

очевидно, я предпочитаю подробный код, который вы можете видеть.


вы можете использовать typeof чтобы получить такое имя:

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