This is a migrated thread and some comments may be shown as answers.

Upload or ZIP is locking file

1 Answer 54 Views
Upload
This is a migrated thread and some comments may be shown as answers.
Dejan
Top achievements
Rank 1
Dejan asked on 06 Oct 2011, 01:39 PM

I’m trying to fulfill requirements:

 

  1. Select a ZIP file on Silverlight side
  2. Upload it to server
  3. Unpack it
  4. Search over extracted file and find manifest.xml
  5. Collect information from manifest
  6. Zip file itself it not required anymore and can be deleted from server file system.
  7. Return information from manifest to Silverlight calling page

 

For that purpose I implemented following handler:

 

/// <summary>
    /// Handler for managing files uploaded by LearningObjectUploadWindow.xaml
    /// </summary>
    public class RadUploadLearningObjectHandler : Telerik.Windows.RadUploadHandler
    {
        /// <summary>
        /// this dictionary will be used to transfer data extracted from zip file to calling silverlight control
        /// </summary>
        private Dictionary<string, object> _dict;
  
        /// <summary>
        /// files are sent in chunks of data
        /// </summary>
        /// <param name="filePath"></param>
        /// <param name="position"></param>
        /// <param name="buffer"></param>
        /// <param name="contentLength"></param>
        /// <param name="savedBytes"></param>
        /// <returns></returns>
        public override bool SaveChunkData(string filePath, long position, byte[] buffer, int contentLength, out int savedBytes)
        {
            if (this.IsNewFileRequest())
            {
                PrepareStorageFolder();
            }
  
            bool result = base.SaveChunkData(filePath, position, buffer, contentLength, out savedBytes);
  
  
            // Checks if this is the last chunk of each file
            if (this.IsFinalFileRequest())
            {
                // Get the names of all the files that have been uploaded so far
                string uploadedFiles = this.GetQueryParameter("UploadedFiles");
  
                //if the file is successfully uploaded
                if (result)
                {
                    // attach the name of the last file
                    uploadedFiles += this.GetFilePath();
  
                    // format the string
                    uploadedFiles = uploadedFiles.Replace(@"\\", @"\");
  
                    // create a collection of filenames
                    string[] fileNames = uploadedFiles.Split('\n');
  
                    ProcessUploadedFiles(fileNames);
                }
            }
  
            return result;
        }
  
  
        /// <summary>
        /// after files are uploaded and before additional informations are transfered to calling silverlight control 
        /// </summary>
        /// <param name="fileNames"></param>
        private void ProcessUploadedFiles(string[] fileNames)
        {
            _dict = base.GetAssociatedData();
  
            foreach (var filename in fileNames)
            {
                if (filename.EndsWith(".zip"))
                {
                    _dict.Add("FileType", "ZIP");
  
                    string folderPath = this.GetTargetFolder();
  
                    //extract all files from archieve
                    using (var package = ZipPackage.OpenFile(filename, FileAccess.Read))
                    {
                        foreach (var entry in package.ZipPackageEntries)
                        {
                            if (entry.Attributes != FileAttributes.Directory)
                            {
                                UnpackAnSaveFile(entry, folderPath);
                            }
                        }
                    }
  
  
                    //PROBLEM!
                    //File is locked by exctractor (or by handler) for a while so it can not be deleted at this moment
                    //todo dkos 20111006 find a way to exctract and delete zip file using another aproach
                    File.Delete(filename);
  
                    //read manifest file
                    var manifestFileName = folderPath + "\\manifest.xml";
  
                    if (File.Exists(manifestFileName))
                    {
                        ExtractDataFromManifest(manifestFileName);
                    }
  
                }
                else
                {
                    _dict.Add(Constants.LEARNING_OBJECT_START_PATH_KEY, this.GetFileName());
                    _dict.Add(Constants.LEARNING_OBJECT_TYPE_KEY, "DOCU");
                }
            }
        }
  
        /// <summary>
        /// return all data added to dictionary in ProcessUploadedFiles()
        /// </summary>
        /// <returns></returns>
        public override Dictionary<string, object> GetAssociatedData()
        {
            return _dict;
        }
  
        /// <summary>
        /// reading info from manifest file
        /// </summary>
        /// <param name="manifestPath"></param>
        private void ExtractDataFromManifest(string manifestPath)
        {
  
            try
            {
                // try to load the manifest.xml file
                XmlDocument doc = new XmlDocument();
                doc.Load(manifestPath);
                XmlElement root = (XmlElement)doc.GetElementsByTagName("manifest")[0];
  
                // get obligate startUrl
                var startUrl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_START_PATH_KEY)[0].InnerText;
  
                _dict.Add(Constants.LEARNING_OBJECT_START_PATH_KEY, startUrl);
  
  
                // set the optional defaults:
  
                // ..short name
                XmlNodeList nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_SHORT_NAME_KEY);
                if (nl.Count == 1)
                    if (nl[0].InnerText.Length > 10)
                        _dict.Add(Constants.LEARNING_OBJECT_SHORT_NAME_KEY, nl[0].InnerText.Substring(0, 10));
                    else
                        _dict.Add(Constants.LEARNING_OBJECT_SHORT_NAME_KEY, nl[0].InnerText);
  
                // ..name
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_NAME_KEY);
                if (nl.Count == 1)
                    _dict.Add(Constants.LEARNING_OBJECT_NAME_KEY, nl[0].InnerText);
  
                // ..description
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_DESCRIPTION_KEY);
                if (nl.Count == 1)
                    _dict.Add(Constants.LEARNING_OBJECT_DESCRIPTION_KEY, nl[0].InnerText);
  
                // ..languageId
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_LANGUAGE_KEY);
                if (nl.Count == 1)
                    _dict.Add(Constants.LEARNING_OBJECT_LANGUAGE_KEY, nl[0].InnerText);
  
                // ..keywords
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_KEYWORDS_KEY);
                if (nl.Count == 1)
                    _dict.Add(Constants.LEARNING_OBJECT_KEYWORDS_KEY, nl[0].InnerText);
  
                // ..type
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_TYPE_KEY);
                if (nl.Count == 1)
                    _dict.Add(Constants.LEARNING_OBJECT_TYPE_KEY, nl[0].InnerText.ToUpper());
  
                // ..workTimeMinutes
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_WORK_TIME_MINUTES_KEY);
                if (nl.Count == 1)
                    try
                    {
                        _dict.Add(Constants.LEARNING_OBJECT_WORK_TIME_MINUTES_KEY, int.Parse(nl[0].InnerText));
                    }
                    catch (Exception exc)
                    {
                        throw new Exception("workTimeMinutes property is not integer", exc);
                    }
  
                // ..contentAuthor
                nl = root.GetElementsByTagName(Constants.LEARNING_OBJECT_CONTENT_AUTHOR_KEY);
                if (nl.Count == 1)
                    _dict.Add(Constants.LEARNING_OBJECT_CONTENT_AUTHOR_KEY, nl[0].InnerText);
  
  
            }
            catch (Exception ex)
            {
                throw new Exception("Error in reading manifest file", ex);
            }
  
  
  
        }
  
        /// <summary>
        /// exctracting each file from zip archive
        /// </summary>
        /// <param name="entry"></param>
        /// <param name="folderPath"></param>
        private static void UnpackAnSaveFile(ZipPackageEntry entry, string folderPath)
        {
            Stream reader = entry.OpenInputStream();
            var fileName = folderPath + "\\" + entry.FileNameInZip;
  
            var directoryName = Path.GetDirectoryName(fileName);
  
            if (directoryName != null)
            {
                if (!Directory.Exists(directoryName))
                {
                    Directory.CreateDirectory(directoryName);
                }
  
                FileStream writer = File.Create(folderPath + "\\" + entry.FileNameInZip);
  
                int size = 2048;
                byte[] data = new byte[2048];
                while (true)
                {
                    size = reader.Read(data, 0, data.Length);
                    if (size > 0)
                        writer.Write(data, 0, size);
                    else
                        break;
                }
                writer.Close();
            }
  
        }
  
  
        internal void PrepareStorageFolder()
        {
            string folderPath = this.GetTargetFolder();
            if (Directory.Exists(folderPath))
            {
  
                //todo dkos 20111006 choose: do we want to delete old content or to move it into archive
                //note: both proces will fail if modification is immediately after old content is uploaded (problem with locking ZIP archive - lines: 85-96) 
  
  
                //move to archive
                var dest = folderPath + "_" + DateTime.Now.ToString("yyyyMMdd_hhmmss");
                Directory.Move(folderPath, dest);
  
                //delete
                //Directory.Delete(folderPath,true);
            }
  
            Directory.CreateDirectory(folderPath);
            if (!Directory.Exists(folderPath))
            {
                throw new DirectoryNotFoundException(folderPath);
            }
        }
    }

 

 

 

Problem starts when I want to delete ZIP file (line 100: //File.Delete(filename);)

 

I can live with the fact that ZIP file remains on the server but there is another scenario:

If user wants to modify Learning Object by uploading new archive, entire content in (existing) folder has to be deleted first.
But piece of code:

 

internal void PrepareStorageFolder()
        {
            string folderPath = this.GetTargetFolder();
            if (Directory.Exists(folderPath))
            {
  
                //todo dkos 20111006 choose: do we want to delete old content or to move it into archive
                //note: both proces will fail if modification is immediately after old content is uploaded (problem with locking ZIP archive - lines: 85-96) 
  
  
                //move to archive
                var dest = folderPath + "_" + DateTime.Now.ToString("yyyyMMdd_hhmmss");
                Directory.Move(folderPath, dest);
  
                //delete
                //Directory.Delete(folderPath,true);
            }
  
            Directory.CreateDirectory(folderPath);
            if (!Directory.Exists(folderPath))
            {
                throw new DirectoryNotFoundException(folderPath);
            }
        }

 

 

Fails with same error if I try to modify Learning Object immediately after uploading it:

 

{"The process cannot access the file 'D:\\Projects\\KV-Reform\\Organizer\\production\\src\\T2LOrganizer.Web\\app\\learn_catalog\\content\\e2b00a83-df4b-4c10-b2c8-0269a7a0e7b9\\ST_711_08d.zip' because it is being used by another process."}

 

   at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)

   at System.IO.File.Delete(String path)

   at T2LOrganizer.Web.AspHandlers.RadUploadLearningObjectHandler.ProcessUploadedFiles(String[] fileNames) in D:\Projects\KV-Reform\Organizer\production\src\T2LOrganizer.Web\AspHandlers\RadUploadLearningObjectHandler.ashx.cs:line 100

   at T2LOrganizer.Web.AspHandlers.RadUploadLearningObjectHandler.SaveChunkData(String filePath, Int64 position, Byte[] buffer, Int32 contentLength, Int32& savedBytes) in D:\Projects\KV-Reform\Organizer\production\src\T2LOrganizer.Web\AspHandlers\RadUploadLearningObjectHandler.ashx.cs:line 60

   at Telerik.Windows.RadUploadHandler.ProcessStream()

 

If I try later (e.g. 10 minutes after) everything is fine.

Something is blocking uploaded file for a while: handler it selves or ZipPackage.

 

Any idea how to solve this?

Thanks in advance.

 

Dekos

 

1 Answer, 1 is accepted

Sort by
0
Accepted
Tina Stancheva
Telerik team
answered on 11 Oct 2011, 12:01 PM
Hello Dejan,

In order to get over this issue you can change the method used to open the ZipPackage. Instead of using the OpenFile() method, you can use the Open() method:
foreach (var filename in fileNames)
{
    if (filename.EndsWith(".zip"))
    {
        _dict.Add("FileType", "ZIP");
        FileStream fileStream = new FileStream(filename, FileMode.Open);
        string folderPath = this.GetTargetFolder();
 
        //extract all files from archieve
        using (var package = ZipPackage.Open(fileStream, FileAccess.Read))
        {
            foreach (var entry in package.ZipPackageEntries)
            {
                if (entry.Attributes != FileAttributes.Directory)
                {
                    UnpackAnSaveFile(entry, folderPath);
                }
            }
        }
        ...
    }
    ...
}

Give this a try and let us know if you still experience any issues. In the meantime we will investigate further the file access issue you reported. And as a small sign of appreciation fro bringing it to our attention, I updated your Telerik account.

Best wishes,
Tina Stancheva
the Telerik team

Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

Tags
Upload
Asked by
Dejan
Top achievements
Rank 1
Answers by
Tina Stancheva
Telerik team
Share this question
or