Нулевой пользователь на HttpContext, полученный из StructureMap
Хорошо, в моем предыдущем вопросе / настройке было слишком много переменных, так что я разбираю это до простых компонентов.
Учитывая код ниже, используя StructureMap3 ...
//IoC setup
For<HttpContextBase>().UseSpecial(x => x.ConstructedBy(y => HttpContext.Current != null ? new HttpContextWrapper(HttpContext.Current) : null ));
For<ICurrentUser>().Use<CurrentUser>();
//Classes used
public class CurrentUser : ICurrentUser
{
public CurrentUser(HttpContextBase httpContext)
{
if (httpContext == null) return;
if (httpContext.User == null) return;
var user = httpContext.User;
if (!user.Identity.IsAuthenticated) return;
UserId = httpContext.User.GetIdentityId().GetValueOrDefault();
UserName = httpContext.User.Identity.Name;
}
public Guid UserId { get; set; }
public string UserName { get; set; }
}
public static class ClaimsExtensionMethods
public static Guid? GetIdentityId(this IPrincipal principal)
{
//Account for possible nulls
var claimsPrincipal = principal as ClaimsPrincipal;
if (claimsPrincipal == null)
return null;
var claimsIdentity = claimsPrincipal.Identity as ClaimsIdentity;
if (claimsIdentity == null)
return null;
var claim = claimsIdentity.FindFirst(x => x.Type == ClaimTypes.NameIdentifier);
if (claim == null)
return null;
//Account for possible invalid value since claim values are strings
Guid? id = null;
try
{
id = Guid.Parse(claim.Value);
}
catch (ArgumentNullException) { }
catch (FormatException) { }
return id;
}
}
Как это возможно в окне Watch?
У меня есть веб-приложение, которое я обновляю для использования StructureMap 3.x из 2.x, но у меня странное поведение в зависимости от конкретной зависимости.
У меня есть ISecurityService, который я использую для проверки некоторых вещей, когда пользователь запрашивает страницу. Этот сервис зависит от небольшого интерфейса, который я назвал ICurrentUser. Реализация класса довольно проста, на самом деле это может быть структура.
public interface ICurrentUser
{
Guid UserId { get; }
string UserName { get; }
}
Это получается путем внедрения зависимости с использованием приведенного ниже кода.
For<ICurrentUser>().Use(ctx => getCurrentUser(ctx.GetInstance<HttpContextBase>()));
For<HttpContextBase>().Use(() => getHttpContext());
private HttpContextBase getHttpContext()
{
return new HttpContextWrapper(HttpContext.Current);
}
private ICurrentUser getCurrentUser(HttpContextBase httpContext)
{
if (httpContext == null) return null;
if (httpContext.User == null) return null; // <---
var user = httpContext.User;
if (!user.Identity.IsAuthenticated) return null;
var personId = user.GetIdentityId().GetValueOrDefault();
return new CurrentUser(personId, ClaimsPrincipal.Current.Identity.Name);
}
Когда приходит запрос, сначала происходит проверка подлинности моего сайта, что зависит отISecurityService
, Это происходит внутри OWIN и, кажется, происходит раньшеHttpContext.User
был заселен, так что это ноль, пусть будет так.
Позже у меня есть ActionFilter, который проверяет, черезISecurityService
, если текущий пользователь согласился с текущей версией TermsOfUse для сайта, в противном случае они перенаправляются на страницу, чтобы сначала согласиться с ними.
Все это прекрасно работало в Structuremap 2.x. Для перехода на StructureMap3 я установил пакет Nuget StructureMap.MVC5, чтобы ускорить процесс.
Когда мой код попадает в строку в моем ActionFilter для проверки условий использования, у меня есть это.
var securityService = DependencyResolver.Current.GetService<ISecurityService>();
agreed = securityService.CheckLoginAgreedToTermsOfUse();
ВнутриCheckLoginAgreedToTermsOfUse()
мой примерCurrentUser
нулевой. Несмотря на то, что это было бы успешно, и моя точка останова внутри getCurrentUser (), похоже, никогда не была достигнута. Это почти так, как если бы это было предрешено, так как в прошлый раз оно было нулевым, хотя на этот раз все решилось бы.
Я немного сбит с толку, почемуgetCurrentUser()
никогда не вызывается по запросуISecurityService
, Я даже пытался явно придерживаться.LifecycleIs<UniquePerRequestLifecycle>()
на моей связи для обработкиICurrentUser
без эффекта.
ОБНОВЛЕНИЕ: Хорошо, только наперед, я начал использовать метод, принятый ниже, и, хотя до сих пор он работал отлично, он не решил мою основную проблему. Оказывается, новыйStructureMap.MVC5
на основеStructureMap3
, использует NestedContainers. Какие области их запросов на время жизни NestedContainer, независимо от того, что по умолчанию Transient. Поэтому, когда я просилHttpContextBase
в первый раз он затем вернет тот же экземпляр для остальной части запроса (хотя позже в течение срока службы запроса контекст изменился. Вам нужно либо не использовать NestedContainer (что, как я понимаю, усложнит ситуацию) ASP.NET vNext) или вы явно задаете жизненный циклFor<>().Use<>()
отображение, чтобы дать вам новый экземпляр для каждого запроса. Обратите внимание, что эта область видимости для NestedContainer также вызывает проблемы с контроллерами в MVC. В то время какStructureMap.MVC5
пакет обрабатывает это сControllerConvention
, он не обрабатывает представления, и рекурсивные представления или представления, используемые несколько раз, могут также вызвать проблемы. Я все еще ищу постоянное решение проблемы с представлениями, на данный момент я вернулся кDefaultContainer
.