C# NancyFx+;信号机&x2B;使用进度的异步进度报告<;T>;
我半鄙视地向你求助。。。我一直在尝试使用SignalR、.NET4.5中的Async和progress将一些进度报告构建到NancyFx应用程序中。我的主要灵感来自这篇文章: 我对代码进行了一些定制,使其也支持进度步骤报告,而不仅仅是百分比 问题在于:我有一个名为ReviewSetup.SetupAsync(………,IProgress progress)的繁重任务,它是使用ProgressJobManager.Instance.DoJobAsync方法从Nancy模块调用的。我将IProgress作为SetupAsync方法的最终参数传入。我为Progress.ProgressChanged设置了一个EventHandler,每当我从SetupAsync()方法中报告一些进度时,都应该调用它 正如您在下面的代码中所看到的,我在ProgressJobManager.Instance.DoJobAsync()方法中连接了事件处理程序,这可能是在执行上下文/线程方面出现问题的地方之一 ProgressChanged进度事件的EventHandler通过调用ReportStep()方法更新ProgressJob。这些方法永远不会被调用,因为它们在我设置的任何断点上都不会中断,我认为这也是由于SetupAsync()方法在不同的线程上执行,因此无法使用提供的参数IProgress progress返回报告 未正确调用进度报告的问题会级联到ProgressJob.StepAdded事件,因此JobManger无法捕获该事件,因此无法通知ProgressHub向客户端发送消息,通知他们进度更新 上面提到的文章要求在ProgressJobManager.Instance.DoJobAsync()方法中完成所有繁重的工作(以及报告进度)。这很好,但我想调用ReviewSetup.SetupAsync()方法并让该方法报告进度。。。我希望你们还和我在一起:-)。我真的很想了解一下.NET4.5中的异步功能。我可能想把它构建成一个更复杂的应用程序,但这是我和我的自我之间的事:-) 无论如何,我的问题是:C# NancyFx+;信号机&x2B;使用进度的异步进度报告<;T>;,c#,asp.net,signalr,async-await,nancy,C#,Asp.net,Signalr,Async Await,Nancy,我半鄙视地向你求助。。。我一直在尝试使用SignalR、.NET4.5中的Async和progress将一些进度报告构建到NancyFx应用程序中。我的主要灵感来自这篇文章: 我对代码进行了一些定制,使其也支持进度步骤报告,而不仅仅是百分比 问题在于:我有一个名为ReviewSetup.SetupAsync(………,IProgress progress)的繁重任务,它是使用ProgressJobManager.Instance.DoJobAsync方法从Nancy模块调用的。我将IProgres
- 我是否以完全错误的方式处理了这个问题
- 这是一个ExecutionContext/thread问题吗?因为我对async/await的所有方面都有丰富的经验,通过更好地理解.NET4.5中的async的工作原理,可以很容易地解决这个问题?如果是这样,请给我指出正确的方向!:-)李>
public class ProgressStatus
{
public bool IsComplete { get; set; }
public int Percentage { get; set; }
public string Step { get; set; }
}
快速浏览代码表明问题出在reviewsetupapimule.cs中,您可以调用
setup.setup
,但不要等待它返回的任务。第二个问题(可能是问题中的输入错误)是ReviewSetup.cs中的方法称为SetupAsync
当您不等待任务时,调用代码将在任务完成之前继续运行。在这种情况下,这将导致作业管理器认为作业已完成,并将其从列表中删除。-是的,第一个确实是一个输入错误,调用安装程序的先前非异步版本()方法。-在调用代码中不等待SetupAsync方法是有意义的,但调用代码如何继续,并将能够返回作业(带有id),以便客户端挂接作业并订阅进度更新?如果我等待SetupAsync()方法,作业刚刚完成后是否不会返回?\n此处的魔法酱位于ProgressJobManager.Instance.DoJobAsync中。它使用Task.Run在后台线程上运行lambda。这就是DoJobAsync能够立即返回作业对象的原因。
Post["/newasync"] = parameters =>
{
this.RequiresAuthentication();
try
{
//removed some stuff
var progresss = new Progress<ProgressStatus>();
var job = ProgressJobManager.Instance.DoJobAsync(j =>
{
//EventHandler bound at the wrong moment/on the wrong thread?
progresss.ProgressChanged += delegate(object sender, ProgressStatus status)
{
j.ReportStep(status.Step);
if (status.IsComplete == true)
{
j.ReportComplete();
}
};
setup.Setup(config, setupModel.NotebookGuid, setupModel.TagGuids, user, setupModel.ReviewName, progresss);
});
//this method needs to keep executing so it can return the job.Id, needed by the client to track its progress.
return Response.AsJson(job).WithStatusCode(HttpStatusCode.OK);
}
catch (Exception ex)
{
return HttpStatusCode.BadRequest;
}
};
public class ProgressJob
{
public event EventHandler<EventArgs> ProgressChanged;
public event EventHandler<EventArgs> StepAdded;
public event EventHandler<EventArgs> Completed;
private volatile int _progress;
private volatile bool _completed;
private volatile List<string> _steps;
private CancellationTokenSource _cancellationTokenSource;
public List<string> Steps
{
get
{
return _steps;
}
}
public ProgressJob(string id)
{
Id = id;
_cancellationTokenSource = new CancellationTokenSource();
_steps = new List<string>();
_completed = false;
}
public string Id { get; private set; }
public int Progress
{
get { return _progress; }
}
public bool IsComplete
{
get { return _completed; }
}
public CancellationToken CancellationToken
{
get { return _cancellationTokenSource.Token; }
}
public Progress<ProgressStatus> ProgressStatus { get; set; }
public void ReportProgress(int progress)
{
if (_progress != progress)
{
_progress = progress;
OnProgressChanged();
}
}
public void ReportStep(string step)
{
_steps.Add(step);
OnStepAdded();
}
public void ReportComplete()
{
if (!IsComplete)
{
_completed = true;
OnCompleted();
}
}
protected virtual void OnCompleted()
{
var handler = Completed;
if (handler != null) handler(this, EventArgs.Empty);
}
protected virtual void OnProgressChanged()
{
var handler = ProgressChanged;
if (handler != null) handler(this, EventArgs.Empty);
}
protected virtual void OnStepAdded()
{
var handler = StepAdded;
if (handler != null) handler(this, EventArgs.Empty);
}
public void Cancel()
{
_cancellationTokenSource.Cancel();
}
}
public class ProgressJobManager
{
public static ProgressJobManager Instance;
private IHubContext _hubContext;
private IProgressJobDataProvider _jobDataProvider;
public ProgressJobManager(IProgressJobDataProvider jobDataProvider)
{
_jobDataProvider = jobDataProvider;
_hubContext = GlobalHost.ConnectionManager.GetHubContext<ProgressHub>();
}
public ProgressJob DoJobAsync(Action<ProgressJob> action)
{
var job = new ProgressJob(Guid.NewGuid().ToString());
_jobDataProvider.AddJob(job);
job.ProgressStatus = new Progress<ProgressStatus>();
Task.Factory.StartNew(() =>
{
action(job);
job.ReportComplete();
job = _jobDataProvider.DeleteJob(job);
},
TaskCreationOptions.LongRunning);
BroadcastJobStatus(job);
return job;
}
private void BroadcastJobStatus(ProgressJob job)
{
job.ProgressChanged += HandleProgressChanged;
job.Completed += HandleJobCompleted;
job.StepAdded += HandleStepAdded;
}
private void HandleJobCompleted(object sender, EventArgs e)
{
var job = (ProgressJob)sender;
_hubContext.Clients.Group(job.Id).JobCompleted(job.Id);
job.ProgressChanged -= HandleProgressChanged;
job.Completed -= HandleJobCompleted;
job.StepAdded -= HandleStepAdded;
}
private void HandleProgressChanged(object sender, EventArgs e)
{
var job = (ProgressJob)sender;
_hubContext.Clients.Group(job.Id).ProgressChanged(job.Id, job.Progress);
}
private void HandleStepAdded(object sender, EventArgs e)
{
var job = (ProgressJob)sender;
var step = job.Steps[job.Steps.Count - 1];
_hubContext.Clients.Group(job.Id).StepAdded(job.Id, step);
}
public ProgressJob GetJob(string id)
{
return _jobDataProvider.GetJob(id);
}
}
public class ProgressHub : Hub
{
public void TrackJob(string jobId)
{
Groups.Add(Context.ConnectionId, jobId);
}
public void CancelJob(string jobId)
{
var job = ProgressJobManager.Instance.GetJob(jobId);
if (job != null)
{
job.Cancel();
}
}
public void ProgressChanged(string jobId, int progress)
{
Clients.Group(jobId).ProgressChanged(jobId, progress);
}
public void JobCompleted(string jobId)
{
Clients.Group(jobId).JobCompleted(jobId);
}
public void StepAdded(string jobId, string step)
{
Clients.Group(jobId).StepAdded(jobId, step);
}
}
public class ProgressStatus
{
public bool IsComplete { get; set; }
public int Percentage { get; set; }
public string Step { get; set; }
}