好的,我之前的问题/设置有太多变量,所以我将其剥离为它的基本组件。
鉴于下面使用 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;
}
}
在“监视”窗口中这怎么可能?
我有一个 Web 应用程序,我正在从 2.x 升级到使用 StructureMap 3.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,它通过 a 检查ISecurityService
当前用户是否同意该站点的当前版本的使用条款,如果不是,他们将被重定向到页面以首先同意他们。
这一切在结构图 2.x 中运行良好。为了迁移到 StructureMap3,我安装了 Nuget 包 StructureMap.MVC5 来帮助我加快速度。
当我的代码到达我的 ActionFilter 中检查使用条款的行时,我有这个。
var securityService = DependencyResolver.Current.GetService<ISecurityService>();
agreed = securityService.CheckLoginAgreedToTermsOfUse();
在里面CheckLoginAgreedToTermsOfUse()
,我的实例CurrentUser
是空的。即使它会成功,而且我在 getCurrentUser() 中的断点似乎永远不会被击中。这几乎就像已成定局,因为上次它是 null ,即使这次它会解决。
我有点困惑,为什么getCurrentUser()
从来没有要求ISecurityService
. 我什至尝试在我的连接上明确粘贴一个.LifecycleIs<UniquePerRequestLifecycle>()
以进行处理ICurrentUser
,但没有任何效果。
更新:好的,请注意,我已经开始使用下面接受的方法,虽然到目前为止效果很好,但它并没有解决我的核心问题。原来新的StructureMap.MVC5
,基于StructureMap3
,使用 NestedContainers。无论默认值是 Transient,它们的请求范围都是 NestedContainer 的生命周期。因此,当我第一次请求HttpContextBase
时,它将为请求的其余部分返回相同的实例(即使在请求生命周期的后期,上下文已经改变。你需要要么不使用 NestedContainer (据我所知它会使事情复杂化 ASP.NET vNext),或者您明确设置For<>().Use<>()
映射为每个请求提供一个新实例。请注意,每个 NestedContainer 的这个作用域会导致控制器以及 MVC 中的问题。虽然StructureMap.MVC5
包用 处理这个ControllerConvention
,但它不处理视图,递归视图或多次使用的视图也可能会给您带来问题。我仍在寻找 Views 问题的永久解决方案,目前我已恢复到DefaultContainer
.