Подтвердить что ты не робот

Как подключить контейнер Autofac к ASP. Идентификация NET 2.1

Я изучил новые функции новой версии ASP.NET Identity 2.1, и одним из ее усовершенствований являются новые функции IoC, интегрированные в промежуточное ПО OWIN. Одно из предложений, которое я посмотрел в примерах, это следующее:

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", которые "магически" вводятся в функцию, которую Im не удалось вытащить в мой контейнер IoC.

Есть ли у кого-нибудь лучшее обходное решение для этой реализации?

4b9b3361

Ответ 1

Я начинаю с установленной сборки MVC5 и использую AutoFac в качестве контейнера IoC. Похоже, я пытаюсь достичь аналогичной цели, как вы, поэтому позвольте мне объяснить, что я сделал. Как отказ от ответственности, я довольно новичок в использовании IoC и Identity.

Я считаю, что IOwinContext не нужен в роли IoC, если вы используете свой собственный - я переключился на регистрацию моего ApplicationUserManager с помощью AutoFac. Для этого я должен был:

Удалите строки CreatePerOwinContext из Startup.Auth, так как я зарегистрирую ApplicationDbContext и ApplicationUserManager в AutoFac.

//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`
}

Установите AccountController для того, чтобы один конструктор принял ApplicationUserManager в качестве аргумента и сломал свойство UserManager, которое захватывает ApplicationUserManager из OwinContext.

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

Зарегистрируйте все с помощью AutoFac, включая экземпляр IdentityFactoryOptions.

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

Это грубое резюме. Возможно, я пропустил еще пару трюков, которые мне пришлось сделать по пути.

Ответ 2

Ответ Ben отвечает на общую идею, но он вручную создает экземпляр DbContext и использует этот экземпляр при регистрации остальных типов. IMO, это плохая идея (нельзя использовать один и тот же вечный контекст db для ВСЕХ запросов).

Комментарий Derek является большим улучшением, но он не передает контекст базы данных в хранилище пользователей, что приводит к ошибкам, таким как "Тип объекта ApplicationUser не является частью модели для текущего контекста".

Я включил свой код ниже, для справки - он действительно похож на Derek's.

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

Ответ 3

Для справки, как вы можете подключить все, используя 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:

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

Да, это не достаточно хорошо, но в то же время мы можем использовать объект той же области действия, что и в процессе регистрации autofac.

Ответ 5

Теперь подробно описано Интеграция MVC5 Owin в Документах по AutoFac:

"

  • Делайте все, что нужно для стандартной интеграции MVC - регистрируйте контроллеры, устанавливайте преобразователь зависимостей и т.д.
  • Настройте приложение с базовой интеграцией Autofac OWIN.
  • Добавьте ссылку на пакет Autofac.Mvc5.Owin NuGet.
  • В классе запуска приложения зарегистрируйте промежуточное ПО Autofac MVC после регистрации базового промежуточного программного обеспечения Autofac.

    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 answer