将HttpContext添加到HangFire中 [英] Add HttpContext into HangFire

查看:61
本文介绍了将HttpContext添加到HangFire中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是HangFire的初学者,并期待每月使用HangFire在我的Web应用程序中调用一些操作.但是这些操作需要HttpContext.

I am a beginner with HangFire and looking forward to using HangFire to call some actions in my web application monthly. But these actions require HttpContext.

然后我的问题是:是否可以在HangFire项目中添加(或创建)httpcontext?

Then my question is: Is there any way to add (or create) a httpcontext in HangFire project?

我尝试用Google搜索,但没有合适的答案. 感谢您的帮助!

I tried to google but no suitable answer. Thanks for your help!

我进行了简短的讨论.遗憾地看到,答案是没有办法". 更新:引用 https://discuss.hangfire. io/t/passing-site-url-to-hangfire-recurrent-jobs/2641

I found a short discussion. Sad to see the answer is "no way". Update: Ref https://discuss.hangfire.io/t/passing-site-url-to-hangfire-recurrent-jobs/2641

推荐答案

我有一个类似的场景,其中系统严重依赖Session,并且我采用了伪造HttpContext并传递会话变量的相同方法.

I have a similar scenario where the system relies heavily on Session, and I took this same approach of faking an HttpContext and passing along session variables.

在我的方法中,我收到一个可序列化的上下文,其中包含所有会话变量:

In my method I receive a serializable context, which contain all session variables:

public static void MyMethod(Hangfire.Server.PerformContext context, Hangfire.IJobCancellationToken cancellationToken, 
        SerializeableHttpContext serializeableHttpContext, ... etc)
{
    using (var fakeContext = serializeableHttpContext.CreateFakeHttpContext()) {
    // ...
    }
}

在入队期间,我将当前上下文传递给可序列化的上下文,该上下文将捕获所有当前变量:

During enqueue, I pass current context to my serializable context, which will capture all current variables:

// null and null are injected by Hangfire
Hangfire.BackgroundJob.Enqueue(() => MyMethod(null, null, new SerializeableHttpContext(System.Web.HttpContext.Current), etc..);

这就是魔术发生的地方.这将保存所有Session变量,并将其还原. 请注意,使用IDispose非常重要,因为您的下一个Hangfire作业不想从上一个作业继承伪造的HttpContext,因此您需要清理HttpContext.

And this is where the magic happens. This will save all Session variables, and will restore them. Please note that using IDispose is important because your next Hangfire job does NOT want to inherit a fake HttpContext from the previous job, so you need to clean up HttpContext.

/// <summary>
/// This serializes HttpContext with primitive Session variables
/// </summary>
[Serializable]
public class SerializeableHttpContext
{
    public Uri RequestUrl { get; set; }
    public Dictionary<string, object> SessionVariables { get; set; }

    /// <summary>
    /// Given a real HttpContext (you can pass System.Web.HttpContext.Current), this saves all useful information 
    /// into this serializable class, so that you can later reuse (restore) a cloned fake HttpContext
    /// </summary>
    /// <param name="httpContext">You'll probably want to pass System.Web.HttpContext.Current</param>
    public SerializeableHttpContext(HttpContext httpContext)
    {
        this.RequestUrl = httpContext.Request.Url;

        // Save all Session variables
        this.SessionVariables = new Dictionary<string, object>();
        foreach (object objkey in httpContext.Session.Keys)
        {
            string key = objkey as string;
            if (key == null || httpContext.Session[key] == null)
                continue;
            Type type = httpContext.Session[key].GetType();

            if (type.IsPrimitive || type == typeof(string))
            {
                try
                {
                    // ignore if not serializable
                    object val = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(httpContext.Session[key]));
                    this.SessionVariables.Add(key, httpContext.Session[key]);
                }
                catch (Exception) { }
            }
        }

    }

    /// This is for internal usage, when deserializing.
    public SerializeableHttpContext()
    {
    }

    /// <summary>
    /// Deserializes into a Fake HttpContext
    /// </summary>
    /// <returns></returns>
    protected HttpContext Deserialize()
    {
        var httpRequest = new HttpRequest("", this.RequestUrl.AbsoluteUri, "");
        var stringWriter = new StringWriter();
        var httpResponse = new HttpResponse(stringWriter);
        var httpContext = new HttpContext(httpRequest, httpResponse);

        var sessionContainer = new HttpSessionStateContainer("id", new SessionStateItemCollection(),
                                                new HttpStaticObjectsCollection(), 10, true,
                                                HttpCookieMode.AutoDetect,
                                                SessionStateMode.InProc, false);

        httpContext.Items["AspSession"] = typeof(HttpSessionState).GetConstructor(
                                    BindingFlags.NonPublic | BindingFlags.Instance,
                                    null, CallingConventions.Standard,
                                    new[] { typeof(HttpSessionStateContainer) },
                                    null)
                            .Invoke(new object[] { sessionContainer });

        // Restore session variables
        if (this.SessionVariables != null)
            foreach (string key in this.SessionVariables.Keys)
                httpContext.Session[key] = this.SessionVariables[key];

        // Restore context variables
        if (this.ContextVariables != null)
            foreach (string key in this.ContextVariables.Keys)
                httpContext.Items[key] = this.ContextVariables[key];

        return httpContext;
    }

    /// <summary>
    /// Deserializes this class back into a fake HttpContext, and automatically sets that into System.Web.HttpContext.Current
    /// Don't forget to DISPOSE this instance at the end, so that the Context is cleared (else Hangfire will reuse this thread with previous HttpContext)
    /// </summary>
    public FakeHttpContext CreateFakeHttpContext()
    {
        return new FakeHttpContext(this.Deserialize());
    }

    public class FakeHttpContext : IDisposable
    {
        HttpContext previousContext;
        public FakeHttpContext(HttpContext context)
        {
            previousContext = HttpContext.Current;
            HttpContext.Current = context;
        }
        public void Dispose()
        {
            HttpContext.Current = previousContext; // previousContext is probably null, but one might be using FakeHttpContexts even inside an existing web context
        }
    }
}


这篇关于将HttpContext添加到HangFire中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆