public virtual void ExecuteResultBody(ControllerContext context, ResumingRequest resumingRequest)
        {
            WriteCommonHeaders(context, resumingRequest);

            if (ShouldProceedAfterEvaluatingPreconditions(context.HttpContext, resumingRequest))
            {
                using (FileContents)
                {
                    if (resumingRequest.IsRangeRequest)
                        WritePartialContent(context, FileContents, resumingRequest);
                    else
                        WriteFullContent(context, FileContents);
                }
            }
        }
        public override void ExecuteResult(ControllerContext context)
        {
            if (context == null)
                throw new ArgumentNullException("context");

            ResumingRequest resumingRequest = new ResumingRequest(context.HttpContext, FileContents.Length);
            ExecuteResultBody(context, resumingRequest);
        }
        protected virtual bool ShouldProceedAfterEvaluatingPreconditions(HttpContextBase context, ResumingRequest resumingRequest)
        {
            var request = context.Request;
            string check;
            DateTimeOffset preconditionDateTime;

            if (!string.IsNullOrEmpty(check = (request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderIfRange)])))
            {
                if (DateTimeOffset.TryParse(check, out preconditionDateTime))
                {
                    if ((LastModified.Value - preconditionDateTime).TotalSeconds > 1)
                    {
                        //The request had a date check; requested entity is newer so we return the full entity
                        resumingRequest.Ranges = null;
                    }
                }
                else
                {
                    if (!check.Equals(EntityTag))
                    {
                        //The request had an entity tag; it didn't match our tag so we return the full entity
                        resumingRequest.Ranges = null;
                    }
                }
            }

            if (!string.IsNullOrEmpty(check = (request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderIfMatch)])))
            {
                IEnumerable<string> entitiesTags = check.Split(',');

                if ((string.IsNullOrEmpty(EntityTag) && entitiesTags.Count() > 0) ||
                     (!entitiesTags.Any(entity => entitiesTags.Equals(EntityTag))))
                {
                    context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed;
                    return false;
                }
            }

            //If we have an EntityTag and the header has * or a matching tag:
            //  If the request is GET or HEAD, we have to return NotModified;
            //  Else we have to return PreconditionFailed
            //Else we allow continued processing for If-Modified check
            if (!string.IsNullOrEmpty(check = (request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderIfNoneMatch)])))
            {
                IEnumerable<string> entitiesTag = check.Split(',');
                if ((!string.IsNullOrEmpty(EntityTag) && entitiesTag.Contains("*")) ||
                    (entitiesTag.Any(entity => entity.Equals(this.EntityTag))))
                {
                    if (context.Request.RequestType == "GET" ||
                         context.Request.RequestType == "HEAD")
                    {
                        context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                        return false;
                    }
                    else
                    {
                        context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed;
                        return false;
                    }
                }
            }

            if (!string.IsNullOrEmpty(check = (request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderIfUnmodifiedSince)])))
            {
                //If the resource changed since (valid) supplied date, return PreconditionFailed
                //Else proceed
                if (DateTimeOffset.TryParse(check, out preconditionDateTime))
                {
                    if (!LastModified.HasValue ||
                        ((LastModified.Value - preconditionDateTime).TotalSeconds > 0))
                    {
                        //Resource is newer or we don't know for sure.
                        context.Response.StatusCode = (int)HttpStatusCode.PreconditionFailed;
                        return false;
                    }
                }
            }

            if (!string.IsNullOrEmpty(check = (request.Headers[HttpWorkerRequest.GetKnownRequestHeaderName(HttpWorkerRequest.HeaderIfModifiedSince)])))
            {
                //If the resource changed since (valid) supplied date, return NotModified
                //Ele proceed
                if (DateTimeOffset.TryParse(check, out preconditionDateTime))
                {
                    if (LastModified.HasValue)
                    {
                        if ((LastModified.Value - preconditionDateTime).TotalSeconds < 1)
                        {
                            context.Response.StatusCode = (int)HttpStatusCode.NotModified;
                            return false;
                        }
                    }
                }
            }

            return true;
        }
        /// <summary>
        /// Writes the common headers to the response stream.
        /// </summary>
        /// <param name="context">The executing controller context.</param>
        protected virtual void WriteCommonHeaders(ControllerContext context, ResumingRequest resumingRequest)
        {
            if (resumingRequest.IsMultipartRequest)
            {
                context.HttpContext.Response.ContentType = string.Format("multipart/byteranges; boundary={0}", MultipartBoundary);
            }
            else
            {
                context.HttpContext.Response.ContentType = ContentType;
            }

            context.HttpContext.Response.AddHeader(
                 HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderAcceptRanges),
                 "bytes");

            if (!string.IsNullOrEmpty(resumingRequest.FileName))
            {
                    context.HttpContext.Response.AddHeader(
                          "Content-Disposition", string.Format(CustomDispositionType ?? "inline" + "; filename=\"{0}\"",
                          !string.IsNullOrWhiteSpace(CustomDisposition) ? CustomDisposition
                          :resumingRequest.FileName));
            }

            if (!string.IsNullOrEmpty(this.EntityTag))
            {
                context.HttpContext.Response.AddHeader(
                     HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderEtag),
                     this.EntityTag);
            }

            if (LastModified.HasValue)
            {
                context.HttpContext.Response.AddHeader(
                     HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderLastModified),
                     LastModified.Value.ToString("R"));
            }
        }
        /// <summary>
        /// Write specific byte ranges to the output stream specified by the ResumableDownloadRequest object.
        /// </summary>
        /// <param name="context">The executing controller context.</param>
        /// <param name="fileContent">The stream from which the byte data is read.</param>
        // See http://www.w3.org/Protocols/rfc1341/7_2_Multipart.html for multipart format information
        public virtual void WritePartialContent(ControllerContext context, Stream fileContent, ResumingRequest resumingRequest)
        {
            var response = context.HttpContext.Response;

            response.StatusCode = (int)HttpStatusCode.PartialContent;

            if (!resumingRequest.IsMultipartRequest)
                context.HttpContext.Response.AddHeader(
                     HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentRange),
                     string.Format("bytes {0}-{1}/{2}",
                          resumingRequest.Ranges.First().StartByte,
                          resumingRequest.Ranges.First().EndByte,
                          fileContent.Length)
                     );

            foreach (var range in resumingRequest.Ranges)
            {
                if (!response.IsClientConnected)
                    return;

                if (resumingRequest.IsMultipartRequest)
                {
                    response.Output.WriteLine(string.Format("--{0}", MultipartBoundary));
                    response.Output.WriteLine(string.Format("{0}: {1}",
                         HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentType),
                         ContentType));
                    response.Output.WriteLine(string.Format("{0}: bytes {1}-{2}/{3}",
                         HttpWorkerRequest.GetKnownResponseHeaderName(HttpWorkerRequest.HeaderContentRange),
                         resumingRequest.Ranges.First().StartByte,
                         resumingRequest.Ranges.First().EndByte,
                         fileContent.Length));
                    response.Output.WriteLine();
                }

                WriteBinaryData(context, fileContent, range.StartByte, range.EndByte);

                if (resumingRequest.IsMultipartRequest)
                    response.Output.WriteLine();
            }

            if (resumingRequest.IsMultipartRequest)
            {
                response.Output.WriteLine(string.Format("--{0}--", MultipartBoundary));
                response.Output.WriteLine();
            }
        }