在请求期间访问/使用相同的对象 - asp.net
Posted
技术标签:
【中文标题】在请求期间访问/使用相同的对象 - asp.net【英文标题】:Access/use the same object during a request - asp.net 【发布时间】:2010-11-14 05:48:11 【问题描述】:我有一个 HttpModule,它在每个请求上创建一个 CommunityPrincipal(实现 IPrincipal 接口)对象。我想以某种方式存储每个请求的对象,以便我可以在需要时获取它,而无需进行强制转换或再次创建它。
基本上我想模仿 FormsAuthenticationModule 的工作方式。 它在每次请求时为 HttpContext.User 属性分配一个实现 IPrincipal 接口的对象。
我希望能够以某种方式调用等 HttpContext.MySpecialUser(或 MySpecialContext.MySpecialUser - 可以创建静态类),它将返回我的对象(特定类型)。
我可以使用扩展方法,但我不知道如何存储对象,以便在请求期间可以访问它。
如何做到这一点?
请注意我想将它存储为特定类型(CommunityPrincipal - 不仅仅是作为对象)。 它当然应该只适用于正在处理的当前请求,而不是与所有其他线程/请求共享。
现在我将我的 CommunityPrincipal 对象分配给 HttpModule 中的 HttpContext.User,但是每次我需要使用未在 IPrincipal 接口中定义的 CommunityPrincipal 对象的属性时,我都需要进行强制转换。
【问题讨论】:
【参考方案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);
这将常规上下文的用户属性保持在自然状态,这样第三方代码、框架代码和您编写的任何其他内容就不会因为您篡改在那里的正常 IPrincipal 而面临风险。该实例仅在其有效的用户请求期间存在。最重要的是,该方法可用于编码,就好像它只是任何常规 HttpContext 成员......并且不需要强制转换。
【讨论】:
感谢您的回复。我将对象作为 IPrincipal 存储在 context.user 上,然后使用扩展方法对任何类型进行显式转换。这似乎是我能得到的最好的。我希望有可能以某种方式创建我可以使用的特定类型的属性,例如 context.user,而不是使用扩展方法或通过 HttpContext.Items 将其作为对象存储在 HttpContext 上。显然不是。【参考方案2】:将您的自定义主体分配给 Context.User 是正确的。希望您在 Application_AuthenticateRequest 中执行此操作。
关于您的问题,您是否仅从 ASPX 页面访问用户对象?如果是这样,您可以为您实现一个包含演员表的自定义基本页面。
public class CommunityBasePage : Page
new CommunityPrincipal User
get return base.User as CommunityPrincipal;
然后让您的页面从CommunityBasePage
继承,您将能够从this.User
访问您的所有属性。
【讨论】:
感谢您的回复。这也是一个好主意。我通常会在控制器或视图中使用它,因此我可以创建可以继承的自定义视图和自定义控制器。谢谢。【参考方案3】:由于您已经将对象存储在 HttpContext.User 属性中,因此您真正需要的是实现您的目标的静态方法:-
public static class MySpecialContext
public static CommunityPrinciple Community
get
return (CommunityPrinciple)HttpContext.Current.User;
现在你可以得到 CommunityPrinciple:-
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,但每个线程都将在其特定的字段实例上进行操作。
【讨论】:
感谢您的回复。这就是我已经在做的事情:)。我要问的是,每次我需要使用 CommunityPrincipal 对象时,是否有办法避免显式强制转换。如果有某种技术可以将其存储为 CommunityPrincipal 并使其在每次请求时都可用。等等我正在考虑创建一个静态类,它是每个线程“创建”的(ThreadStaticAttribute),但我不知道这是否会是一个安全问题,因为我必须确保在每个请求结束时删除对象作为线程被共享/重用。以上是关于在请求期间访问/使用相同的对象 - asp.net的主要内容,如果未能解决你的问题,请参考以下文章