Простая идентификация инжектора UserManager<AppUser, Int32> Ошибка регистрации
Я следую за Onion Architecture и использую Identity Framework. В моем основном проекте у меня есть:
public interface IUserRepository : IDisposable
{
// Repository methods.......
}
В моей Архитектуре. Репозиторий у меня есть
public class UserRepository : IUserRepository
{
// This is Identity UserManager
private readonly UserManager<AppUser, int> _userManager;
private readonly IAuthenticationManager _authenticationManager;
private bool _disposed;
public UserRepository(UserManager<User, int> userManager,
IAuthenticationManager authenticationManager)
{
_userManager = userManager;
_authenticationManager = authenticationManager;
}
}
В моем проекте разрешения зависимостей у меня есть:
[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(IocConfig),
"RegisterDependencies")]
namespace AdShad.Infrastructure.DependencyResolution
{
public class IocConfig
{
public static void RegisterDependencies()
{
var container = new Container();
container.RegisterWebApiRequest<IUnitOfWork, UnitOfWork>();
container.RegisterWebApiRequest<IUserRepository, UserRepository>();
container.RegisterManyForOpenGeneric(typeof(IRepository<>),
typeof(BaseRepository<>).Assembly);
container.RegisterWebApiRequest<IEntitiesContext, MyContext>();
container.RegisterWebApiRequest(
() => HttpContext.Current.GetOwinContext().Authentication);
container.Verify();
HttpConfiguration config = new HttpConfiguration
{
DependencyResolver =
new SimpleInjectorWebApiDependencyResolver(container)
};
}
}
}
На container.Verify()
Я получаю следующую ошибку:
Исключение типа "System.InvalidOperationException" произошло в SimpleInjector.dll, но не было обработано в коде пользователя
Дополнительная информация: конфигурация неверна. Не удалось создать экземпляр для типа IUserRepository. Зарегистрированный делегат для типа IUserRepository выдал исключение. Не удалось найти регистрацию для типа UserManager и не удалось сделать неявную регистрацию. Конструктор типа UserManager содержит параметр типа IUserStore с именем "store", который не зарегистрирован. Убедитесь, что IUserStore зарегистрирован, или измените конструктор UserManager.
Может ли кто-нибудь подсказать мне, что я делаю неправильно и что мне нужно сделать, чтобы это исправить?
1 ответ
Сообщение об исключении говорит:
Конструктор типа UserManager
содержит параметр типа IUserStore с именем "store", который не зарегистрирован. Убедитесь, что IUserStore зарегистрирован, или измените конструктор UserManager.
Исключение предполагает, что вы должны зарегистрироваться IUserStore<AppUser, int>
, поскольку UserManager<AppUser, int>
зависит от этого. Так, например, вы можете сделать следующую регистрацию:
// UserStore<TUser> is defined in Microsoft.AspNet.Identity.EntityFramework.
// Do note that UserStore<TUser> implements IUserStore<TUser, string>, so
// this Entity Framework provider requires a string. If you need int, you
// might have your own store and need to build your own IUserStore implemenation.
container.Register<IUserStore<AppUser, string>>(
() => new UserStore<AppUser>>(),
Lifestyle.Scoped);
Однако, согласно этой статье, вы не должны автоматически подключать типы фреймворков, такие как UserManager<TUser, TKey>
, но вместо этого используйте ручную регистрацию, создав такой тип самостоятельно. Например:
container.Register<UserManager<AppUser, string>>(
() => new UserManager<AppUser, string>(new UserStore<AppUser>()),
Lifestyle.Scoped);
Было бы еще лучше воздержаться от использования типов из внешних библиотек (таких как UserManager<TUser, TKey>
) прямо в вашем основном приложении. Тем более, что вы практикуете луковую архитектуру. Эта архитектура продвигает принципы SOLID и описывает концепцию портов и адаптеров. Порт - это абстракция, определяемая вашим приложением, которая позволяет шлюз во внешний домен или библиотеку. Адаптер - это реализация такой абстракции, которая фактически подключается к этому внешнему домену или библиотеке. Это именно то, что описывает Принцип обращения зависимостей (один из пяти принципов SOLID).
Так что вместо того, чтобы позволить UserRepository
зависит от типа структуры, такой как UserManager<TUser, TKey>
пусть это зависит от специально определенной абстракции с очень узко определенной и единственной ответственностью. Адаптер для этой абстракции может в свою очередь использовать UserManager<TUser, TKey>
,
В зависимости от того, что UserRepository
действительно, вы могли бы даже рассмотреть это UserRepository
сам адаптер. В этом случае, давая UserRepository
напрямую зависит от UserManager<TUser, TKey>
Это хорошо. В этом случае, скрывая UserManager<TUser, TKey>
за дополнительной абстракцией просто возникает дополнительный / ненужный слой абстракции.
Но тем не менее, адаптер может не только напрямую зависеть от UserManager<TUser, TKey>
, но он может просто контролировать создание и уничтожение UserManager<TUser, TKey>
сам. Другими словами, ваш UserRepository
может выглядеть следующим образом:
// NOTE: Do not let IUserRepository implement IDisposable. This violates
// the Dependency Inversion Principle.
// NOTE2: It's very unlikely that UserRepository itself needs any disposal.
public class UserRepository : IUserRepository
{
// This is Identity UserManager
private readonly IAuthenticationManager _authenticationManager;
public UserRepository(IAuthenticationManager authenticationManager)
{
_authenticationManager = authenticationManager;
}
public void Delete(AppUser user) {
// Here we create and dispose the UserManager during the execution
// of this method.
using (manager = new UserManager<AppUser, string>(
new UserStore<AppUser>())) {
manager.DeleteAsync(user).Result;
}
}
}
В обсуждениях Simple Injector есть интересное описание о том, как работать с Identity и шаблоном Visual Studio по умолчанию. А вот Stackru q/a об идентичности, который может вас заинтересовать.