简体   繁体   English

工作队列和用户上下文

[英]Worker queue and user context

We have a worker queue that a user can add work to. 我们有一个工作人员队列,用户可以向其中添加工作。 When the worker item is added the context is the users ( HttpContext ). 添加工作程序项后,上下文即为用户( HttpContext )。 But its a background thread that polls the queue and executes the items one by one in order. 但是它是一个后台线程,该线程轮询队列并依次逐项执行各项。

I cant just store the User because when the HttpContext is disposed so will the Principal object 我不能只存储用户,因为在处理HttpContext时,主体对象也会这样

The code that can run in the worker needs the Principal to be correct for stuff like PrincipalPermissions etc. 可以在工作程序中运行的代码需要Principal对于PrincipalPermissions等东西是正确的。

Also, Lifetime management (IoC) uses the HttpContext for InRequest scopes, is it possible to recreate a HttpContext with the correct principal etc. 此外,生命周期管理(IoC)将HttpContext用于InRequest范围,是否可以使用正确的主体等重新创建HttpContext

edit: Faking HttpContext is just a nice to have feature for Life time management, this I can work around. 编辑:伪造HttpContext只是一个很好的功能,可以用于生命周期管理,这个我可以解决。 But our backend code heavily depends on having the correct user principal for the thread since we use this to validate if user has access to that part of the system. 但是我们的后端代码在很大程度上取决于线程的正确用户主体,因为我们使用它来验证用户是否有权访问系统的那部分。 I would mark as answer if someone can answer how to store a user principal with identity, roles and IsAuthenticated state and later use that on another thread 如果有人可以回答如何存储具有身份,角色和IsAuthenticated状态的用户主体,然​​后在另一个线程上使用它, 我将标记为答案

Your best practice for consuming stateful data from the HttpContext is to create your own application specific context which accepts an HttpContext in the constructor (Dependency Injected). HttpContext使用状态数据的最佳实践是创建自己的应用程序特定上下文,该上下文在构造函数中接受HttpContext (依赖注入)。

Your business logic should never be dependent on an HttpContext but rather your new application specific context (which may have been created using info from an HttpContext ). 您的业​​务逻辑永远不应依赖于HttpContext ,而应依赖于新的应用程序特定的上下文(该上下文可能是使用HttpContext信息创建的)。

This will not only solve your above problems, but also increase testability of your code. 这不仅可以解决您上面的问题,而且可以提高代码的可测试性。

Example: 例:

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
}

Neither the IPrincipal nor IIdentity interface explicitly offer a dispose method. IPrincipalIIdentity接口均未明确提供处理方法。 So they should both be ok to keep a reference to them. 因此,他们俩都应该保留对其的引用。 However, I haven't tested the above code, I wrote it just for this question. 但是,我没有测试上面的代码,我只是为这个问题写的。

If by some poor design they actually do depend on an underlying database connection to query the roles membership, you'd simply have to evaluate that earlier in the constructor of your application context while the HttpContext and asp.net forms authentication provider are still non disposed/closed. 如果经过某种糟糕的设计,他们实际上确实依赖于基础数据库连接来查询角色成员身份,则只需在应用上下文的构造函数中更早地对其进行评估,而HttpContext和asp.net表单身份验证提供程序仍未使用/关闭。

You can always take apart the principal and identity and recreate a new instance of GenericPrincipal and GenericIdentity or even create your application Identity class which implements IIdentity . 您始终可以拆分主体和身份,并重新创建GenericPrincipalGenericIdentity的新实例,甚至创建实现IIdentity应用程序Identity类。 There is lots of room for customization/extension here. 这里有大量的自定义/扩展空间。

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
}

Why don't you use an auxiliar class to hold the information you need? 您为什么不使用辅助类来保存所需的信息? You can create it during the web request with the appropriate values and pass it down as an argument to the background worker. 您可以在Web请求期间使用适当的值创建它,并将其作为参数传递给后台工作程序。

Cloning the HTTPContext object is not possible because of the internal server session state . 由于内部服务器会话状态 ,因此无法克隆HTTPContext对象。 Even if it were possible, using it outside of a real HTTP request just to check for values doesn't seem like a good solution. 即使有可能,在真正的HTTP请求之外使用它来检查值似乎也不是一个好的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM