使用注入的参数使Hangfire RecurringTask入队

时间:2018-09-26 17:53:58

标签: c# .net hangfire

我有一个解决方案,我想建立一组通过Hangfire运行的Method调用。我想编写一个遍历集合的注册类,并创建RecurringJobs。

我有代码可以在其中指示静态Action方法的表达式起作用,并创建Action静态方法的表达式。

假设我有以下代码:

public static class Test
{
    public static void Test1() {}
    public static void Test2() {}
    public static void Test3(IDependency dependency) {}
    public static void Test4(IDependency dependency) {}

    public static void TestWrapper(Action<IDependency> test)
    {
        IDependency dependency = ExternalMethodToFetchFromIOC();
        test(dependency);
    }

    public static IDependency ExternalMethodToFetchFromIOC()
    {
        return new Dependency();
    }
}

注册Action方法时一切正常:

public static class HangfireReg
{
    public static void RegisterThings()
    {
        List<Action> collection = new List<Action>
        {
            Test.Test1,
            Test.Test2,
        }

        foreach(Action action in collection)
        {
             BackgroundJob.Enqueue(() => action);
        }
    }
}

在依赖注入方面遇到麻烦;如果我使用一种方法来包装调用,则Hang​​fire会抱怨:

  

作业方法参数中不支持匿名函数,委托和lambda表达式:很难序列化它们及其所有作用域。

public static class HangfireReg
{
    public static void RegisterThings()
    {
        List<Action<IDependency>> collection = new List<Action<IDependency>>
        {
            Test.Test3,
            Test.Test4,
        }

        foreach(Action<IDependency> action in collection)
        {
             BackgroundJob.Enqueue(() => Test.TestWrapper(action));
        }
    }
}

最后,如果我尝试使用显式类型手动构建Lambda表达式,则会遇到另一个错误(我当时想我可以绕过Type及其MethodInfo进行注册,而不是):

  

从范围''引用的类型为'IDependency'的'variable'dependency',但未定义'

public static class HangfireReg
{
    public static void RegisterThings()
    {
        {
            Type targetType = typeof(Test);
            MethodInfo testMethod = targetType.GetMethod(nameof(Test.Test4), BindingFlags.Static | BindingFlags.Public);
            MethodInfo fetchDependency = targetType.GetMethod(nameof(Test.ExternalMethodToFetchFromIOC), BindingFlags.Static | BindingFlags.Public);

            //IDependency dependency = Test.ExternalMethodToFetchFromIOC();
            ParameterExpression dependencyVar = Expression.Variable(typeof(IDependency), "dependency");
            MethodCallExpression call = Expression.Call(fetchDependency);
            BinaryExpression assignedInstance = Expression.Assign(dependencyVar, call);

            //Test.Test4(dependency);
            MethodCallExpression invoke = Expression.Call(testMethod, assignedInstance);

            //{ IDependency dependency = Test.ExternalMethodToFetchFromIOC(); Test.Test4(dependency); }
            Expression<Action> action = Expression.Lambda<Action>(invoke);
            BackgroundJob.Enqueue(action);
        }
    }
}

(对于它的价值,这就是Lambda的外观,被视为DebugView):

.Lambda #Lambda1<System.Action>()
{
    .Call Test.Test4
        (
            $config = .Call Test.ExternalMethodToFetchFromIOC()
        )
}

Hangfire的依赖项注入需要一个通用类型,该类型需要在编译时就知道,并且需要调用该类型的方法之一,因此我不能在集合中真正使用Type。 / p>

我是否有任何方法可以在Action<IDependency>的动态集合上进行迭代,而无需在入队时知道IDependency的值,因此IoC的 some 模式可以注入参数?

编辑:更正lambda以达到我的预期。

我收到一个错误:

  

表达式主体应为MethodCallExpression类型:

public static class HangfireReg
{
    public static void RegisterThings()
    {
        {
            Type targetType = typeof(Test);
            MethodInfo testMethod = targetType.GetMethod(nameof(Test.Test4), BindingFlags.Static | BindingFlags.Public);
            MethodInfo fetchDependency = targetType.GetMethod(nameof(Test.ExternalMethodToFetchFromIOC), BindingFlags.Static | BindingFlags.Public);

            //IDependency dependency = Test.ExternalMethodToFetchFromIOC();
            ParameterExpression dependencyVar = Expression.Variable(typeof(IDependency), "dependency");
            MethodCallExpression call = Expression.Call(fetchDependency);
            BinaryExpression assignedInstance = Expression.Assign(dependencyVar, call);

            //Test.Test4(dependency);
            MethodCallExpression invoke = Expression.Call(testMethod, dependencyVar);

            //{ IDependency dependency = Test.ExternalMethodToFetchFromIOC(); Test.Test4(dependency); }
            BlockExpression fullCall = Expression.Block(assignedInstance, invoke);
            Expression<Action> action = Expression.Lambda<Action>(fullCall);
            BackgroundJob.Enqueue(action);
        }
    }
}

产生以下结果的一个lambda:

.Lambda #Lambda1<System.Action>() {
    .Block() {
        $dependency = .Call Test.ExternalMethodToFetchFromIOC();
        .Call Test.Test4($dependency)
    }
}

0 个答案:

没有答案