我有一个基本上在亚马逊s3中存储文件的类。 这是它的样子(简化)
public class S3FileStore
{
public void PutFile(string ID, Stream content)
{
//do stuff
}
}
在我的客户端应用中,我希望能够致电:
var s3 = new() S3FileStore();
s3.PutFile ("myId", File.OpenRead(@"C:\myFile1"));
s3.PutFile ("myId", File.OpenRead(@"C:\myFile2"));
s3.PutFile ("myId", File.OpenRead(@"C:\myFile3"));
我希望这是一个异步操作 - 我希望S3FileStore能够处理这个问题(我不希望我的调用者必须异步执行PutFile)但是,我希望能够捕获异常/告诉是否每个文件的操作都已完成。
我查看了基于事件的异步调用,尤其是: http://blogs.windowsclient.net/rendle/archive/2008/11/04/functional-shortcuts-2-event-based-asynchronous-pattern.aspx
但是,我看不到如何调用我的PutFile(void)方法?
有没有更好的例子?
答案 0 :(得分:1)
查看此问题的解决方案:Adding cancel ability and exception handling to async code。希望它有所帮助。
答案 1 :(得分:1)
BackgroundWorker
基类可能值得一看,还有线程池:
ThreadPool.QueueUserWorkItem(delegate
{
s3.PutFile ("myId", File.OpenRead(@"C:\myFile1"));
});
这基本上是你对Action / BeginInvoke模式的处理方式。使用BeginInvoke,您还会收到一个IAsyncResult
,您可以在其上调用.WaitOne()
来阻止当前线程,直到操作完成,以防您需要。您将为要保存的每个文件触发新的BeginInvoke
。
如果您需要经常这样做,更复杂的版本可能是将Queue与BackgroundWorker结合使用,例如:
public sealed class S3StoreLikePutFileWorker<TYourData> : BackgroundWorker
{
private AutoResetEvent WakeUpEvent = new AutoResetEvent(false);
private Queue<TYourData> DataQueue = new Queue<TYourData>();
private volatile bool StopWork = false;
public void PutFile(TYourData dataToWrite)
{
DataQueue.Enqueue(dataToWrite);
WakeUpEvent.Set();
}
public void Close()
{
StopWork = true;
WakeUpEvent.Set();
}
private override void OnDoWork(DoWorkEventArgs e)
{
do
{
// sleep until there is something to do
WakeUpEvent.WaitOne();
if(StopWork) break;
// Write data, if available
while(DataQueue.Count > 0)
{
TYourData yourDataToWrite = DataQueue.Dequeue();
// write data to file
}
}
while(!StopWork);
}
}
取决于您需要多少复杂性。
BackgroundWorker支持进度反馈(在构造函数中设置WorkerReportsProgress = true;
),如果有必要,您还可以添加自定义事件来报告错误:
// create a custom EventArgs class that provides the information you need
public sealed class MyEventArgs : EventArgs {
// Add information about the file
}
// ... define the event in the worker class ...
public event EventHandler<MyEventArgs> ErrorOccured;
// ... call it in the worker class (if needed) ...
if(ErrorOccured != null) ErrorOccured(this, new MyEventArgs(/*...*/));