Example #1
0
        internal static MultipartContentElement[] Parse(StreamIndexer data, long length, byte[] boundary, Encoding encoding) // Edited to remove HttpRawUploadedContent dependancy
        {
            var httpMultipartContentTemplateParser = new HttpMultipartContentTemplateParser(data, length, boundary, encoding);

            httpMultipartContentTemplateParser.ParseIntoElementList();
            return((MultipartContentElement[])httpMultipartContentTemplateParser.m_elements.ToArray(typeof(MultipartContentElement)));
        }
        public void ProcessRequest(HttpContext context)
        {
            string str = context.Request.Url.ToString();

            // Handler is mapped to all requests to .upl extension.
            // HttpHandler is used over MVC controller action, as request will
            // have been fully uploaded by the action code runs.

            // We process the request using GetBufferlessInputStream() to avoid
            // useing any methods or properties on the request object that would
            // cause ASP.NET to wait for request to be recieved in it's entirety.
            // Calls to certain methods and properties can cause the code to block until
            // full request stream has been recieved by ASP.NET, such as Files,
            // InputStream (buffered version) etc. (http://msdn.microsoft.com/en-us/library/ff406798.aspx)

            // As a result, we can not read parameters from Request.Form without blocking. The
            // signalR connection id is used as the path file name so we can read this value
            // before beginning processing.

            // New BufferlessInputStream functionality in ASP.NET 4.5, don't think this
            // helps me though http://www.asp.net/vnext/overview/aspnet/whats-new

            string signalRConnectionId = Path.GetFileNameWithoutExtension(str);

            // Get a signalR context and client for notifying the UI of progress.

            IHubContext uploadHubContext = GlobalHost.ConnectionManager.GetHubContext <UploadHub>();

            dynamic currentClient = uploadHubContext.Clients.Client(signalRConnectionId);

            ClientUpdateStatus(currentClient, "Preparing to upload");

            bool uploadFailed = false;

            int bytesCopied          = 0;
            int requestContentLength = context.Request.ContentLength;
            int bytesRemaining       = requestContentLength;

            int filesUploaded = 0;

            Task asyncTask = Task.Factory.StartNew(() =>
            {
                var appSettings = ConfigurationManager.AppSettings;

                string fileNameGuid = Guid.NewGuid().ToString();

                string saveDirectoryPath = appSettings["AppSoftware.SignalRFileUploader.UploaderContentFolder"];

                string requestTempSavePath = saveDirectoryPath + @"Temp\" + fileNameGuid + ".upl";

                // Write the request out to our own temp file for processing
                // when complete. This enables the handling of larger files

                using (var fileStream = new FileStream(requestTempSavePath, FileMode.CreateNew))
                {
                    byte[] buffer = new byte[8 * 1024];

                    int length;

                    // Use a bufferless input stream to prevent ASP.NET from blocking
                    // until the entire request has been uploaded.

                    Stream bufferlessInputStream = context.Request.GetBufferlessInputStream();

                    int readSize = buffer.Length;

                    while (bytesRemaining > 0)
                    {
                        // We use a specified read size here rather than full buffer length
                        // because BufferlessInputStream won't know when the stream is fully uploaded.
                        // Attempting to read bytes that are never coming results in a hang. This
                        // is why read size is calculated from bytesRemaining, which is initialy
                        // set to the request content size.

                        length = bufferlessInputStream.Read(buffer, 0, readSize);

                        fileStream.Write(buffer, 0, length);

                        bytesCopied += length;

                        bytesRemaining -= length;

                        if (readSize > bytesRemaining)
                        {
                            readSize = bytesRemaining;
                        }

                        ClientUpdateUploadProgress(currentClient, bytesCopied, requestContentLength);
                    }

                    bufferlessInputStream.Close();

                    fileStream.Close();
                }

                ClientUpdateStatus(currentClient, "Processing temporary data");

                try
                {
                    // Create a FileStream from the raw request data that is currently
                    // persisted to a temporary file. the FileStream is loaded into StreamIndexer
                    // which provides compatibility with HttpMultipartContentTemplateParser
                    // adapted from decompiled .NETs System.Web, while allowing us to
                    // process the raw request data with out fully loading into
                    // memory while we split the multipart content

                    using (var fileStream = new FileStream(requestTempSavePath, FileMode.Open))
                    {
                        byte[] multiPartBoundary = HttpMultipartContentTemplateParser.GetMultipartBoundary(context.Request.ContentType);

                        // Each element maintains a reference to a StreamIndexer, which has a reference to
                        // the file stream that provides access to the raw request data currently saved.
                        // When SaveAsFile is called, the data is streamed out of the fileStream using
                        // positional information stored during parse stage.

                        var multiContentElements = HttpMultipartContentTemplateParser.Parse(
                            new StreamIndexer(fileStream),
                            fileStream.Length,
                            multiPartBoundary,
                            context.Request.ContentEncoding
                            );

                        foreach (var element in multiContentElements)
                        {
                            if (element.IsFile)
                            {
                                element.SaveAsFile(saveDirectoryPath + fileNameGuid + "_" + element.FileName);

                                filesUploaded++;
                            }
                            else
                            {
                                // Optionaly do something with value e.g.

                                // string name = element.Name;
                                // string value = element.GetAsString(context.Request.ContentEncoding);
                            }
                        }
                    }
                }
                finally
                {
                    ClientUpdateStatus(currentClient, "Cleaning up");

                    // Clean up temp file

                    File.Delete(requestTempSavePath);
                }
            }).ContinueWith(task =>
            {
                uploadFailed = task.IsFaulted;
            });

            try
            {
                asyncTask.Wait();
            }
            catch (AggregateException aEx)
            {
                // Set aggregate exception handled, this will otherwise be thrown
                // at finally stage

http:                                   //msdn.microsoft.com/en-GB/library/dd537614.aspx

                aEx.Handle(x => false); // ToDo: Log and set true
            }

            // Final update

            ClientUpdateStatus(currentClient, string.Format("Complete ({0} files uploaded). {1}", filesUploaded, uploadFailed ? "Errors occurred during this upload. Check log files." : String.Empty));
            ClientComplete(currentClient);

            // Send a response, which redirects the iframe. Sending a no content
            // response seems to cause issue with subsequent uploads in firefox at least

            context.Response.StatusCode = 204;
        }
 internal static MultipartContentElement[] Parse(StreamIndexer data, long length, byte[] boundary, Encoding encoding) // Edited to remove HttpRawUploadedContent dependancy
 {
     var httpMultipartContentTemplateParser = new HttpMultipartContentTemplateParser(data, length, boundary, encoding);
     httpMultipartContentTemplateParser.ParseIntoElementList();
     return (MultipartContentElement[])httpMultipartContentTemplateParser.m_elements.ToArray(typeof(MultipartContentElement));
 }