2013-12-02 4 views
0

У меня есть этот класс обслуживания:ObjectDisposedException при попытке загрузить файл

public delegate string AsyncMethodCaller(string id, HttpPostedFileBase file); 

public class ObjectService : IDisposable 
{ 
    private readonly IObjectRepository repository; 
    private readonly IAmazonS3 client; 
    private readonly string bucketName; 

    private static object syncRoot = new object(); 
    private static IDictionary<string, int> processStatus { get; set; } 

    public ObjectService(string accessKey, string secretKey, string bucketName) 
    { 
     var credentials = new BasicAWSCredentials(accessKey, secretKey); 

     this.bucketName = bucketName; 
     this.client = new AmazonS3Client(credentials, RegionEndpoint.EUWest1); 
     this.repository = new ObjectRepository(this.client, this.bucketName); 

     if (processStatus == null) 
      processStatus = new Dictionary<string, int>(); 
    } 

    public IList<S3Object> GetAll() 
    { 
     return this.repository.GetAll(); 
    } 

    public S3Object Get(string key) 
    { 
     return this.GetAll().Where(model => model.Key.Equals(key, StringComparison.OrdinalIgnoreCase)).SingleOrDefault(); 
    } 

    /// <summary> 
    /// Note: You can upload objects of up to 5 GB in size in a single operation. For objects greater than 5 GB you must use the multipart upload API. 
    /// Using the multipart upload API you can upload objects up to 5 TB each. For more information, see http://docs.aws.amazon.com/AmazonS3/latest/dev/uploadobjusingmpu.html. 
    /// </summary> 
    /// <param name="id">Unique id for tracking the upload progress</param> 
    /// <param name="bucketName">The name of the bucket that the object is being uploaded to</param> 
    /// <param name="file">The file that will be uploaded</param> 
    /// <returns>The unique id</returns> 
    public string Upload(string id, HttpPostedFileBase file) 
    { 
     var reader = new BinaryReader(file.InputStream); 
     var data = reader.ReadBytes((int)file.InputStream.Length); 
     var stream = new MemoryStream(data); 
     var utility = new TransferUtility(client); 

     var request = new TransferUtilityUploadRequest() 
     { 
      BucketName = this.bucketName, 
      Key = file.FileName, 
      InputStream = stream 
     }; 

     request.UploadProgressEvent += (sender, e) => request_UploadProgressEvent(sender, e, id); 
     utility.Upload(request); 

     return id; 
    } 

    private void request_UploadProgressEvent(object sender, UploadProgressArgs e, string id) 
    { 
     lock (syncRoot) 
     { 
      processStatus[id] = e.PercentDone; 
     } 
    } 

    public void Add(string id) 
    { 
     lock (syncRoot) 
     { 
      processStatus.Add(id, 0); 
     } 
    } 

    public void Remove(string id) 
    { 
     lock (syncRoot) 
     { 
      processStatus.Remove(id); 
     } 
    } 

    public int GetStatus(string id) 
    { 
     lock (syncRoot) 
     { 
      if (processStatus.Keys.Count(x => x == id) == 1) 
      { 
       return processStatus[id]; 
      } 
      else 
      { 
       return 100; 
      } 
     } 
    } 

    public void Dispose() 
    { 
     this.repository.Dispose(); 
     this.client.Dispose(); 
    } 
} 

и мой контроллер выглядит следующим образом:

public class _UploadController : Controller 
{ 
    public void StartUpload(string id, HttpPostedFileBase file) 
    { 
     var bucketName = CompanyProvider.CurrentCompanyId(); 

     using (var service = new ObjectService(ConfigurationManager.AppSettings["AWSAccessKey"], ConfigurationManager.AppSettings["AWSSecretKey"], bucketName)) 
     { 
      service.Add(id); 

      var caller = new AsyncMethodCaller(service.Upload); 
      var result = caller.BeginInvoke(id, file, new AsyncCallback(CompleteUpload), caller); 
     } 
    } 

    public void CompleteUpload(IAsyncResult result) 
    { 
     var caller = (AsyncMethodCaller)result.AsyncState; 
     var id = caller.EndInvoke(result); 
    } 

    // 
    // GET: /_Upload/GetCurrentProgress 

    public JsonResult GetCurrentProgress(string id) 
    { 
     try 
     { 
      var bucketName = CompanyProvider.CurrentCompanyId(); 
      this.ControllerContext.HttpContext.Response.AddHeader("cache-control", "no-cache"); 

      using (var service = new ObjectService(ConfigurationManager.AppSettings["AWSAccessKey"], ConfigurationManager.AppSettings["AWSSecretKey"], bucketName)) 
      { 
       return new JsonResult { Data = new { success = true, progress = service.GetStatus(id) } }; 
      } 
     } 
     catch (Exception ex) 
     { 
      return new JsonResult { Data = new { success = false, error = ex.Message } }; 
     } 
    } 
} 

Теперь, я обнаружил, что иногда я получаю ошибку ObjectDisposedException при попытке загрузить файл в этой строке: var data = reader.ReadBytes ((int) file.InputStream.Length);. Я читал, что я не должен использовать , используя ключевое слово из-за асинхронных вызовов, но все же кажется, что он удаляет поток.

Может ли кто-нибудь сказать мне, почему?

Update 1

Я изменил мой контроллер к этому:

private ObjectService service = new ObjectService(ConfigurationManager.AppSettings["AWSAccessKey"], ConfigurationManager.AppSettings["AWSSecretKey"], CompanyProvider.CurrentCompanyId()); 

public void StartUpload(string id, HttpPostedFileBase file) 
{    
    service.Add(id); 

    var caller = new AsyncMethodCaller(service.Upload); 
    var result = caller.BeginInvoke(id, file, new AsyncCallback(CompleteUpload), caller); 
} 

public void CompleteUpload(IAsyncResult result) 
{ 
    var caller = (AsyncMethodCaller)result.AsyncState; 
    var id = caller.EndInvoke(result); 

    this.service.Dispose(); 
} 

, но я все еще получаю ошибку на file.InputStream линии.

Update 2

Проблема, кажется, с BinaryReader. Я изменил код, чтобы выглядеть следующим образом:

 var inputStream = file.InputStream; 
     var i = inputStream.Length; 
     var n = (int)i; 

     using (var reader = new BinaryReader(inputStream)) 
     { 
      var data = reader.ReadBytes(n); 
      var stream = new MemoryStream(data); 

      var request = new TransferUtilityUploadRequest() 
      { 
       BucketName = this.bucketName, 
       Key = file.FileName, 
       InputStream = stream 
      }; 

      try 
      { 
       request.UploadProgressEvent += (sender, e) => request_UploadProgressEvent(sender, e, id); 
       utility.Upload(request); 
      } 
      catch 
      { 
       file.InputStream.Dispose(); // Close our stream 
      } 
     } 

Если загрузка не удается, и я стараюсь, чтобы повторно загрузить элемент, то есть, когда выбрасывается ошибка. Это похоже на то, что элемент заблокирован или что-то в этом роде.

+0

вы пытались удалить с помощью для 'StartUpload'? –

ответ

0

Вы отправляете службу с помощью инструкции, когда вы вызываете службу с помощью BeginInvoke.

using (var service = new ObjectService(ConfigurationManager.AppSettings["AWSAccessKey"], ConfigurationManager.AppSettings["AWSSecretKey"], bucketName)) 
     { 
      service.Add(id); 

      var caller = new AsyncMethodCaller(service.Upload); 
      var result = caller.BeginInvoke(id, file, new AsyncCallback(CompleteUpload), caller); 
     } 

Вы должны распоряжаться вашу службу, когда дело сделано:

var service = new ObjectService(ConfigurationManager.AppSettings["AWSAccessKey"], ConfigurationManager.AppSettings["AWSSecretKey"], bucketName) 

public void StartUpload(string id, HttpPostedFileBase file) 
    { 
     var bucketName = CompanyProvider.CurrentCompanyId(); 


      service.Add(id); 

      var caller = new AsyncMethodCaller(service.Upload); 
      var result = caller.BeginInvoke(id, file, new AsyncCallback(CompleteUpload), caller); 

    } 

    public void CompleteUpload(IAsyncResult result) 
    { 

    var caller = (AsyncMethodCaller)result.AsyncState; 
    var id = caller.EndInvoke(result); 
    service.Close(); 
     service.Dispose(); 
    } 

Кроме того, ваш файл может быть поврежден, попробуйте этот код:

byte[] buffer = new byte[file.InputStream.Length]; 
file.InputStream.Seek(0, SeekOrigin.Begin); 
file.InputStream.Read(buffer, 0, file.InputStream.Length); 
+0

Я получаю сообщение об ошибке в файле. InputStream. Вы уверены, что это то, что вызывает его? Я попытался внести изменения, и я все равно получаю ту же ошибку. – r3plica

+0

Вы также можете поместить в конструктор контроллера. Будьте осторожны, чтобы не уничтожить объект. –

+0

Файл может быть поврежден. Также проверьте файл, прочитав файл с помощью метода InputStream.Seek. –

Смежные вопросы