簡體   English   中英

嘗試上傳文件時出現ObjectDisposedException

[英]ObjectDisposedException when trying to upload a file

我有這個服務班:

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 } };
        }
    }
}

現在,我發現有時在嘗試在此行上載文件時出現錯誤ObjectDisposedExceptionvar data = reader.ReadBytes((int)file.InputStream.Length); 我讀到,由於異步調用,我不應該使用using關鍵字,但是它似乎仍在處理流。

誰能告訴我為什么?

更新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行上收到錯誤。

更新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
            }
        }

如果上傳失敗,而我嘗試重新上傳該項目,那就是拋出錯誤時。 就像物品被鎖住了一樣。

使用BeginInvoke調用服務時,將使用using語句來處理服務。

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM