2015-01-12 5 views
2

Новый проект asp.net mvc с использованием owin, webapi, mvc и DI (SimpleInjector) отлично работает, если я удаляю DI lib из проекта. Однако, после введения, приложение взрывается при регистрации компонентов OWIN для DI. Конфигурация запуска Owin будет удара и работает без ошибок, но когда приходит время, чтобы зарегистрировать зависимости (перечислены ниже), я получаю следующее сообщение об ошибке:ASP.NET MVC 5 + Owin + SimpleInjector

An exception of type 'System.InvalidOperationException' occurred in Microsoft.Owin.Host.SystemWeb.dll but was not handled in user code

Additional information: No owin.Environment item was found in the context.

SimpleInjector Регистрационный код:

container.RegisterPerWebRequest<IUserStore<ApplicationUser>>(() => new UserStore<ApplicationUser>()); 
container.RegisterPerWebRequest<HttpContextBase>(() => new HttpContextWrapper(HttpContext.Current)); 
// app fails on call to line below... 
container.RegisterPerWebRequest(() => container.GetInstance<HttpContextBase>().GetOwinContext()); 
container.RegisterPerWebRequest(() => container.GetInstance<IOwinContext>().Authentication); 
container.RegisterPerWebRequest<DbContext, ApplicationDbContext>(); 

Обновление - Полный Трассировка стека

at System.Web.HttpContextBaseExtensions.GetOwinContext(HttpContextBase context) at WebApplication1.App_Start.SimpleInjectorInitializer.<>c__DisplayClass6.b__2() in b:\temp\WebApplication1\WebApplication1\App_Start\SimpleInjectorInitializer.cs:line 41 at lambda_method(Closure) at SimpleInjector.Scope.CreateAndCacheInstance[TService,TImplementation](ScopedRegistration 2 registration) at SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration 2 registration) at SimpleInjector.Scope.GetInstance[TService,TImplementation](ScopedRegistration 2 registration, Scope scope) at SimpleInjector.Advanced.Internal.LazyScopedRegistration 2.GetInstance(Scope scope) at lambda_method(Closure) at SimpleInjector.InstanceProducer.GetInstance()

+0

Можете ли вы опубликовать полную статистику стека? – Steven

+1

Не удается ли он в точке 'container.Verify()'? – qujck

+0

Ошибка при регистрации зависимостей. Это строка: container.RegisterPerWebRequest (() => container.GetInstance (). Аутентификация); – bbqchickenrobot

ответ

14

Я думаю, что исключение при вызове Verify(). Возможно, на этой линии, но только тогда, когда вызывается делегат.

Простой инжектор позволяет делать регистрацию в любом порядке и, следовательно, не проверяет наличие и правильность зависимостей регистрации. Эта проверка выполняется в первый раз, когда запрашивается экземпляр, или может быть вызвана путем вызова .Verify() в конце процесса регистрации.

Я подозреваю, что вы регистрируете OwinContext только потому, что вам это нужно для получения IAuthenticationManager.

Проблема, с которой вы сталкиваетесь, заключается в том, что OwinContext доступен только при наличии HttpContext. Этот контекст недоступен в момент создания приложения в корне композиции. Вам нужен делегат, который проверяет этап приложения и возвращает компонент, соответствующий этому этапу. Вы могли бы, что регистрируя IAuthenticationManager как:

container.RegisterPerWebRequest<IAuthenticationManager>(() => 
    AdvancedExtensions.IsVerifying(container) 
     ? new OwinContext(new Dictionary<string, object>()).Authentication 
     : HttpContext.Current.GetOwinContext().Authentication); 

Делегат вернет Owin управляется IAuthenticationManager, когда код работает на «нормальной стадии выполнения» и есть HttpContext.

Но при явном вызове Verify() (что очень важно advisable делать!) В конце процесса регистрации нет HttpContext. Поэтому мы создадим новый OwinContext во время проверки контейнера и вернем компонент проверки подлинности из этого недавно созданного OwinContext. Но только если контейнер действительно проверяет!

Полное и подробное описание может быть прочитано here, как уже упоминалось в комментариях.

+0

Вместо фальшивого 'FakeAuthenticationManager' вы, вероятно, можете просто вернуть« новый OwinContext(); ' – janhartmann

+0

Не думайте так, что тип возврата - IAuthenticationManager, поэтому верните новый OwinContext, который выиграл». Furtermore у нового OwinContext не было бы связанного с AuthenticationManager (null), поэтому мы возвращаем пустой. –

+0

Я имею в виду, что я бы вернул 'новый OwinContext(). Autentication', похоже, отлично работает в моем коде. Но я думаю, что я просто верю подделку, если быть уверенным. – janhartmann

0

Хотя вопрос другой, ответ такой же, как my answer here.

Проблема в том, что вы вставляете HttpContextWrapper в свое приложение и пытаетесь использовать его элементы во время инициализации приложения, но в этот момент жизненного цикла приложения HttpContext пока недоступен. HttpContext содержит состояние выполнения, и нет смысла инициализировать приложение в контексте одного конкретного пользователя.

Чтобы обойти эту проблему, вы должны использовать один или несколько Abstract Factories для доступа к HttpContext во время выполнения (когда это доступно), а не при инициализации приложения, и вводить фабрики в свои службы с помощью DI.

Использование ответа Ric .Net может также работать, но оно будет генерировать исключение каждые время, когда приложение инициализируется.

+2

В чем проблема бросания исключения «каждый раз, когда приложение инициализируется»? Инициализация произойдет только один раз. – Steven

+0

Неверный. Приложение инициализируется каждый раз, когда пул приложений истекает. Кроме того, согласно [Best Practices for Exceptions] (http://msdn.microsoft.com/en-us/library/seyhszts%28v=vs.110%29.aspx), вы должны * Проектировать классы, чтобы исключение было никогда не бросается в нормальное использование. * – NightOwl888

+0

Если вам действительно нужен HttpContext, это может быть решением. Но если вы внимательно изучите вопрос, то это не для HttpContext, а для IAuthenticationManager. Я использовал инструкцию try catch. вы также можете выполнить нулевую проверку для HttpContext. Но у этого есть некоторые проблемы его собственных. –

0

Ответ «Ric .Net» указал мне в правильном направлении, но, чтобы изменения в новой SimpleInjector, должны изменить код, как показано ниже (как RegisterPerWebRequest является Obselete):

 container.Register<IAuthenticationManager>(() => AdvancedExtensions.IsVerifying(container) 
        ? new OwinContext(new Dictionary<string, object>()).Authentication 
        : HttpContext.Current.GetOwinContext().Authentication, Lifestyle.Scoped); 

Кроме того, необходимо добавить ниже двух регистраций в контейнер, чтобы позволить «container.Verify()» работать правильно:

 container.Register<ApplicationUserManager>(Lifestyle.Scoped); 
     container.Register<ApplicationSignInManager>(Lifestyle.Scoped); 
Смежные вопросы