1

我有一个 HttpModule,它在每个请求上创建一个 CommunityPrincipal(实现 IPrincipal 接口)对象。我想以某种方式存储每个请求的对象,以便我可以在需要时获取它,而无需进行强制转换或再次创建它。

基本上我想模仿 FormsAuthenticationModule 的工作方式。它在每个请求上为 HttpContext.User 属性分配一个实现 IPrincipal 接口的对象。

我以某种方式希望能够调用等 HttpContext.MySpecialUser (或 MySpecialContext.MySpecialUser - 可以创建静态类),它将返回我的对象​​(特定类型)。

我可以使用扩展方法,但我不知道如何存储对象,以便在请求期间可以访问它。

如何实现?

请注意我想将其存储为特定类型(CommunityPrincipal - 不仅仅是作为对象)。它当然应该只适用于正在处理的当前请求,而不是与所有其他线程/请求共享。

现在我将我的 CommunityPrincipal 对象分配给 HttpModule 中的 HttpContext.User,但是每次我需要使用未在 IPrincipal 接口中定义的 CommunityPrincipal 对象上的属性时,我都需要进行强制转换。

4

3 回答 3

1

我建议您远离将数据耦合到线程本身。您无法控制 asp.net 现在或将来如何使用线程。

数据与请求上下文密切相关,因此它应该与上下文一起定义、生存和消亡。放那个地方正好,在 HttpModule 中实例化对象也是合适的。

演员阵容确实应该不是什么大问题,但是如果您想摆脱这种情况,我强烈建议为此使用 HttpContext 的扩展方法...这正是扩展方法旨在处理的那种情况.

这是我如何实现它:

创建一个静态类来放置扩展方法:

public static class ContextExtensions
{
    public static CommunityPrinciple GetCommunityPrinciple(this HttpContext context)
    {
        if(HttpContext.Current.Items["CommunityPrinciple"] != null)
        {
            return HttpContext.Current.Items["CommunityPrinciple"] as CommunityPrinciple;
        }
    }
}

在您的 HttpModule 中,只需将主体放入上下文项集合中,例如:

HttpContext.Current.Items.Add("CommunityPrincipal", MyCommunityPrincipal); 

这将常规上下文的用户属性保持在自然状态,这样 3rd 方代码、框架代码和您编写的任何其他内容都不会因为您篡改在那里的正常 IPrincipal 而面临风险。该实例仅在其有效的用户请求期间存在。最重要的是,该方法可用于编码,就好像它只是任何常规 HttpContext 成员......并且不需要强制转换。

于 2009-10-07T05:01:31.397 回答
0

将您的自定义主体分配给 Context.User 是正确的。希望您在 Application_AuthenticateRequest 中执行此操作。

提出您的问题,您是否只从 ASPX 页面访问用户对象?如果是这样,您可以为您实现一个包含演员表的自定义基本页面。

public class CommunityBasePage : Page
{
    new CommunityPrincipal User
    {
        get { return base.User as CommunityPrincipal; }
    }
}

然后让您的页面继承自CommunityBasePage,您将能够从 获取所有属性this.User

于 2009-10-08T10:17:07.793 回答
0

由于您已经将对象存储在 HttpContext.User 属性中,因此您真正需要的是实现您的目标的静态方法:-

  public static class MySpecialContext
  {
    public static CommunityPrinciple Community
    {
        get
        {
           return (CommunityPrinciple)HttpContext.Current.User;
        }
    }
  }

现在你可以得到社区原则:-

  var x = MySpecialContext.Community;

但是,似乎要避免很多努力:-

  var x = (CommunityPrinciple)Context.User;

另一种方法是 HttpContext 上的扩展方法:-

  public static class HttpContextExtensions
  {
    public static CommunityPrinciple GetCommunity(this HttpContext o)
    {
      return (CommunityPrinciple)o.User;
    }
  }

使用它:-

  var x = Context.GetCommunity();

这很整洁,但需要您记住在需要它的每个文件的 using 列表中包含定义扩展类的名称空间。

编辑

让我们暂时假设您有一些非常好的理由为什么即使在上面调用的代码内部执行的演员表仍然不可接受(顺便说一句,我真的很想了解是什么情况导致您得出这个结论)。

另一种选择是 ThreadStatic 字段:-

  public class MyModule : IHttpModule
  {
    [ThreadStatic]
    private static CommunityPrinciple _threadCommunity;

    public static CommunityPrinciple Community
    {
        get
        {
           return _threadCommunity;
        }
    }
    // Place here your original module code but instead of (or as well as) assigning
    // the Context.User store in _threadCommunity.
    // Also at the appropriate point in the request lifecyle null the _threadCommunity

  }

用 [ThreadStatic] 修饰的字段将具有每个线程的一个存储实例。因此,多个线程可以修改和读取 _threadCommunity,但每个线程都将在其特定的字段实例上进行操作。

于 2009-08-02T08:16:18.203 回答