Silverlight 클라이언트에서 Amazon S3로 여러 파일을 직접 업로드하려고합니다. 사용자는 표준 파일 열기 대화 상자에서 파일을 선택하고 한 번에 하나씩 연속적으로 업로드되도록 연결하고 싶습니다. 이것은 응용 프로그램의 여러 장소에서 일어날 수 있으므로 선택한 파일의 IEnumerable이 파일의 IObservable을 노출하므로 UI가 각 파일에 따라 적절하게 응답 할 수 있도록 업로드하는 멋진 유틸리티 클래스로 마무리하려고했습니다. 은 끝났어.Rx를 사용하여 여러 단계의 2 단계 파일 업로드
Silverlight 및 AmazonS3의 모든 보안 요구 사항으로 인해 상당히 복잡합니다. 컨텍스트에 대한 전체 환경을 간단히 설명하려고 시도 하겠지만 코드를 아래에 게시 할 작은 콘솔 응용 프로그램으로이 문제를 재현했습니다.
표준 이벤트 기반 비동기 메서드를 제공하는 Silverlight에서 S3 로의 업로드를 처리하는 타사 유틸리티가 있습니다. 업로드 된 파일 하나당 하나의 유틸리티 인스턴스를 만듭니다. 서명되지 않은 요청 문자열을 만들어 내 서버에 게시하여 개인 키로 서명합니다. 이 서명 요청은 이벤트 기반 비동기 메소드를 사용하는 서비스 프록시 클래스를 통해 발생합니다. 서명 된 요청이 있으면이를 업 로더 인스턴스에 추가하고 업로드를 시작합니다.
나는 Concat을 사용해 보았지만 첫 번째 파일 만 프로세스가 끝난다. Merge를 사용하면 모든 파일이 정상적으로 완료되지만 순차적으로가 아니라 병렬 방식으로 완료됩니다. Merge (2)를 사용하면 모든 파일이 첫 번째 단계를 시작하지만 2 번만 완료되어 완료됩니다.
내가 기대 한 것처럼 행동하지 않기 때문에 분명히 Rx와 관련된 뭔가를 놓치고 있습니다.
namespace RxConcat
{
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reactive.Linq;
using System.Timers;
public class SignCompletedEventArgs : EventArgs
{
public string SignedRequest { get; set; }
}
public class ChainUploader
{
public IObservable<string> StartUploading(IEnumerable<string> files)
{
return files.Select(
file => from signArgs in this.Sign(file + "_request")
from uploadArgs in this.Upload(file, signArgs.EventArgs.SignedRequest)
select file).Concat();
}
private IObservable<System.Reactive.EventPattern<SignCompletedEventArgs>> Sign(string request)
{
Console.WriteLine("Signing request '" + request + "'");
var signer = new Signer();
var source = Observable.FromEventPattern<SignCompletedEventArgs>(ev => signer.SignCompleted += ev, ev => signer.SignCompleted -= ev);
signer.SignAsync(request);
return source;
}
private IObservable<System.Reactive.EventPattern<EventArgs>> Upload(string file, string signedRequest)
{
Console.WriteLine("Uploading file '" + file + "'");
var uploader = new Uploader();
var source = Observable.FromEventPattern<EventArgs>(ev => uploader.UploadCompleted += ev, ev => uploader.UploadCompleted -= ev);
uploader.UploadAsync(file, signedRequest);
return source;
}
}
public class Signer
{
public event EventHandler<SignCompletedEventArgs> SignCompleted;
public void SignAsync(string request)
{
var timer = new Timer(1000);
timer.Elapsed += (sender, args) =>
{
timer.Stop();
if (this.SignCompleted == null)
{
return;
}
this.SignCompleted(this, new SignCompletedEventArgs { SignedRequest = request + "signed" });
};
timer.Start();
}
}
public class Uploader
{
public event EventHandler<EventArgs> UploadCompleted;
public void UploadAsync(string file, string signedRequest)
{
var timer = new Timer(1000);
timer.Elapsed += (sender, args) =>
{
timer.Stop();
if (this.UploadCompleted == null)
{
return;
}
this.UploadCompleted(this, new EventArgs());
};
timer.Start();
}
}
internal class Program
{
private static void Main(string[] args)
{
var files = new[] { "foo", "bar", "baz" };
var uploader = new ChainUploader();
var token = uploader.StartUploading(files).Subscribe(file => Console.WriteLine("Upload completed for '" + file + "'"));
Console.ReadLine();
}
}
}