我们有一个用户可以添加工作的工作队列。添加工作项时,上下文是用户(HttpContext
)。但它是一个后台线程,它轮询队列并按顺序逐个执行项目。
我无法存储用户,因为当HttpContext
被处置时,Principal对象
可以在worker中运行的代码需要Principal对PrincipalPermissions
等内容是正确的。
此外,终身管理(IoC)使用HttpContext
InRequest
范围,是否可以使用正确的主体等重新创建HttpContext
。
修改 伪造HttpContext对于生命时间管理来说是一个很好的功能,我可以解决这个问题。 但是我们的后端代码在很大程度上取决于拥有正确的线程用户主体,因为我们使用它来验证用户是否可以访问系统的该部分。 如果有人可以回答如何使用身份,角色和IsAuthenticated状态存储用户主体并稍后在另一个线程上使用,那么我会将其标记为
答案 0 :(得分:1)
从HttpContext
使用有状态数据的最佳做法是创建自己的应用程序特定上下文,在构造函数中接受HttpContext
(依赖注入)。
您的业务逻辑永远不应该依赖于HttpContext
,而是您的新应用程序特定上下文(可能是使用HttpContext
中的信息创建的)。
这不仅可以解决您的上述问题,还可以提高代码的可测试性。
示例:
public class MyApplicationContext
{
public IPrincipal ContextPrincipal { get; set; }
public MyApplicationContext(HttpContext httpContext)
{
// Store the current user principal & identity
ContextPrincipal = httpContext.User;
// Need to grab anything else from the HttpContext? Do it here!
// That could be cookies, Http request header values, query string
// parameters, session state variables, etc.
//
// Once you gather up any other stateful data, store it here in
// your application context object as the HttpRequest can't be passed
// to another thread.
}
}
public class MyHttpHandler : IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
// Return false in case your Managed Handler cannot be reused for another request.
// Usually this would be false in case you have some state information preserved per request.
get { return true; }
}
public void ProcessRequest(HttpContext context)
{
// Do some work on another thread using the ThreadPool
ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork), new MyApplicationContext(context));
}
public void DoWork(object state)
{
// Grab our state info which should be an instance of an
// MyApplicationContext.
MyApplicationContext context = (MyApplicationContext) state;
// Assign this ThreadPool thread's current principal according
// to our passed in application context.
Thread.CurrentPrincipal = context.ContextPrincipal;
// Check if this user is authenticated.
if (context.ContextPrincipal.Identity.IsAuthenticated)
{
var userName = context.ContextPrincipal.Identity.Name;
}
// Check if this user is an administrator.
if (context.ContextPrincipal.IsInRole("Administrator"))
{
}
// Do some long-ish process that we need to do on the threadpool
// after the HttpRequest has already been responded to earlier.
//
// This would normally be some fancy calculation/math, data
// operation or file routines.
for (int i = 0; i < 30; i++)
{
Thread.Sleep(1000);
}
}
#endregion
}
IPrincipal
和IIdentity
接口都没有明确提供dispose方法。所以他们都应该保持对它们的引用。但是,我还没有测试过上面的代码,我只为这个问题写了它。
如果通过一些糟糕的设计他们实际上依赖于底层数据库连接来查询角色成员资格,那么您只需要在应用程序上下文的构造函数中评估它,而HttpContext和asp.net表单身份验证提供程序是仍然没有处置/关闭。
您始终可以拆分主体和标识,并重新创建GenericPrincipal
和GenericIdentity
的新实例,甚至可以创建实现IIdentity
的应用程序标识类。这里有很多定制/扩展的空间。
答案 1 :(得分:0)
public void TestMethod1()
{
System.Net.WebClient client = new System.Net.WebClient();
client.BaseAddress = "http://www.teejoo.com";
//Invoke your function here
client.OpenReadAsync(new Uri("http://www.teejoo.com/YourLogicalPage.aspx"));
//Pur your logical in your page, so you can use httpContext
client.OpenReadCompleted += new System.Net.OpenReadCompletedEventHandler(client_OpenReadCompleted);
}
void client_OpenReadCompleted(object sender, System.Net.OpenReadCompletedEventArgs e)
{
//to Check the response HERE
}
答案 2 :(得分:0)
为什么不使用辅助课程来保存您需要的信息?您可以在Web请求期间使用适当的值创建它,并将其作为参数传递给后台工作程序。
由于内部server session state,无法克隆HTTPContext
对象。即使它是可能的,在真正的HTTP请求之外使用它只是为了检查值似乎不是一个好的解决方案。