C# 具有返回值的Hangfire后台作业

C# 具有返回值的Hangfire后台作业,c#,asp.net,asynchronous,hangfire,C#,Asp.net,Asynchronous,Hangfire,我从一个转到另一个。在.NET 4.5+Task.Run可以返回Task,这允许我运行返回的任务,而不是void。我通常可以通过访问属性MyReturnedTask.result 我的旧代码示例: public void MyMainCode() { List<string> listStr = new List<string>(); listStr.Add("Bob"); listStr.Add("Kate"); listStr.Add(

我从一个转到另一个。在.NET 4.5+
Task.Run
可以返回
Task
,这允许我运行返回的任务,而不是
void
。我通常可以通过访问属性
MyReturnedTask.result

我的旧代码示例:

public void MyMainCode()
{
    List<string> listStr = new List<string>();
    listStr.Add("Bob");
    listStr.Add("Kate");
    listStr.Add("Yaz");

    List<Task<string>> listTasks = new List<Task<string>>();

    foreach(string str in listStr)
    {
        Task<string> returnedTask = Task.Run(() => GetMyString(str));
        listTasks.Add(returnedTask);
    }

    foreach(Task<string> task in listTasks)
    {
        // using task.Result will cause the code to wait for the task if not yet finished.
        // Alternatively, you can use Task.WaitAll(listTasks.ToArray()) to wait for all tasks in the list to finish.
        MyTextBox.Text += task.Result + Environment.NewLine;
    }
}
private string GetMyString(string str)
{
    // long execution in order to calculate the returned string
    return str + "_finished";
}
public void MyMainCode()
{
List listStr=新列表();
listStr.Add(“Bob”);
添加列表(“凯特”);
添加列表(“Yaz”);
List listTasks=新建列表();
foreach(listStr中的字符串str)
{
Task returnedTask=Task.Run(()=>GetMyString(str));
添加(返回任务);
}
foreach(listTasks中的任务)
{
//如果尚未完成,则使用task.Result将导致代码等待任务。
//或者,您可以使用Task.WaitAll(listTasks.ToArray())等待列表中的所有任务完成。
MyTextBox.Text+=task.Result+Environment.NewLine;
}
}
私有字符串GetMyString(字符串str)
{
//长时间执行以计算返回的字符串
返回str+“_finished”;
}
从Hangfire的页面上我可以看到,你的主要人物是
BackgroundJob.Enqueue(()=>Console.WriteLine(“Fire and forget”)
完美地将代码作为后台作业运行,但显然不支持具有返回值的作业(如上面介绍的代码)。是这样吗?如果没有,我如何调整代码以使用Hangfire

另外,我已经看过了HostingEnvironment.QueueBackgroundWorkItem
(),但它显然缺少相同的功能(后台作业必须是
void

编辑

正如@Dejan所指出的,我想切换到Hangfire的主要原因与.NET人员在.NET 4.5.2中添加
QueueBackgroundWorkItem
的原因相同。这一原因在Scott Hanselman的《关于ASP.NET中的后台任务的伟大》中有很好的描述。所以我要引用这篇文章:

QBWI(QueueBackgroundWorkItem)调度可以在后台运行的任务,而不依赖于 任何要求。这与普通线程池工作项的不同之处在于 ASP.NET自动跟踪已注册的工作项的数量 通过此API当前正在运行,并且ASP.NET运行时将 尝试延迟AppDomain关闭,直到这些工作项完成 执行


一个简单的解决方案是轮询监视API,直到作业完成,如下所示:

    public static Task Enqueue(Expression<Action> methodCall)
    {
        string jobId = BackgroundJob.Enqueue(methodCall);
        Task checkJobState = Task.Factory.StartNew(() =>
        {
            while (true)
            {
                IMonitoringApi monitoringApi = JobStorage.Current.GetMonitoringApi();
                JobDetailsDto jobDetails = monitoringApi.JobDetails(jobId);
                string currentState = jobDetails.History[0].StateName;
                if (currentState != "Enqueued" && currentState != "Processing")
                {
                    break;
                }
                Thread.Sleep(100); // adjust to a coarse enough value for your scenario
            }
        });
        return checkJobState;
    }
公共静态任务排队(表达式方法调用)
{
字符串jobId=BackgroundJob.Enqueue(methodCall);
Task checkJobState=Task.Factory.StartNew(()=>
{
while(true)
{
IMonitoringApi monitoringApi=JobStorage.Current.GetMonitoringApi();
JobDetailsTo jobDetails=monitoringApi.jobDetails(jobId);
字符串currentState=jobDetails.History[0]。StateName;
if(currentState!=“排队”和¤tState!=“处理”)
{
打破
}
Thread.Sleep(100);//根据您的场景调整到足够粗糙的值
}
});
返回checkJobState;
}

注意:当然,在基于Web的场景中,您不能依赖任务的继续(
task.ContinueWith()
)在作业完成后执行更多操作,因为AppDomain可能会关闭-出于同样的原因,您可能首先希望使用Hangfire。

方法的返回值显示在控制面板上作业的信息页面上。如果在相关的db表中查找Hangfire作业,则返回值应存储在其中的字段中。除此之外,我不确定是否可以通过程序访问它。谢谢你指出这一点。我有完全相同的问题。你在这段时间有什么想法吗?还没有。你可以阅读更多关于Scott Hanselman关于ASP.NET中后台任务的文章:我可能很快就会开始赏金,也许我们会得到答案。请注意,Hangfire 1.4.0引入了“如果这是你感兴趣的内容”的概念。谢谢,最后一句关于我切换到Hangfire的原因是完全正确的。重点是,不可能有一个包含返回任务的防弹解决方案。我使用了相同的代码,但仍然失败了几次,大部分时间都在通过。我尝试添加“等待”检查,现在即使没有线程也能正常工作。if(currentState!=“排队”和¤tState!=“正在处理”和¤tState!=“等待”)