Хорошо, у меня в предыдущем вопросе/настройке было слишком много переменных, поэтому я разделяю это на его компоненты с голыми костями.Null User on 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
, поэтому оно равно null, так и должно быть.
Позже у меня есть ActionFilter, который проверяет через ISecurityService
, если текущий пользователь согласился с текущей версией TermsOfUse для сайта, если они не перенаправлены на страницу, чтобы сначала согласиться с ними.
Все это прекрасно работало в структуре map 2.x. Для моей миграции в StructureMap3 я установил пакет Nuget StructureMap.MVC5, чтобы ускорить работу для меня.
Когда мой код попадает в строку моего ActionFilter для проверки условий использования, у меня есть это.
var securityService = DependencyResolver.Current.GetService<ISecurityService>();
agreed = securityService.CheckLoginAgreedToTermsOfUse();
Внутри CheckLoginAgreedToTermsOfUse()
, мой экземпляр CurrentUser
является недействительным. Несмотря на то, что это было бы заметно, и моя точка останова внутри getCurrentUser() никогда не попадает. Это почти так, как если бы это было предрешено, так как в последний раз это было нулевым, хотя на этот раз оно разрешилось бы.
Я как бы не понял, почему getCurrentUser()
никогда не вызывается по запросу ISecurityService
. Я даже попытался явно наклеить .LifecycleIs<UniquePerRequestLifecycle>()
на мой крючок для обработки ICurrentUser
без эффекта.
UPDATE: Хорошо, так что только хэдз-ап, я начал использовать метод, принятый ниже, и пока он отлично работает, он не разрешил мою основную проблему. Оказывается, новый StructureMap.MVC5
, основанный на StructureMap3
, использует NestedContainers. Какая область их запросов на время жизни NestedContainer, независимо от того, по умолчанию является Transient. Поэтому, когда я впервые обратился к HttpContextBase
, он вернет тот же самый экземпляр для остальной части запроса (хотя позже в течение срока действия запроса контекст изменился. Вам нужно либо не использовать NestedContainer (который, как я понять это усложнит ситуацию ASP.NET vNext), или вы явно задали жизненный цикл отображения For<>().Use<>()
, чтобы предоставить вам новый экземпляр для каждого запроса. Обратите внимание, что эта область видимости для NestedContainer вызывает проблемы с контроллерами, а также в MVC. В то время как пакет StructureMap.MVC5
обрабатывает это с помощью ControllerConvention
, он не обрабатывает представления, а рекурсивные виды или представления, используемые несколько раз, также могут вызвать проблемы. Я все еще ищу постоянное исправление проблемы Views, на данный момент я вернусь к DefaultContainer
.
Не могли бы вы вывести код для вашей реализации ISecurityService? – NightOwl888
У меня было слишком много переменных, которые могли бы привести к возможной помощи по неправильному пути. Теперь я упростил вопрос о проблеме с голой костью. –