public async Task Invoke(HttpContext context)
		{
			bool useMinification = _options.IsMinificationEnabled() && _minificationManagers.Count > 0;
			bool useCompression = _options.IsCompressionEnabled() && _compressionManager != null;

			if (!useMinification && !useCompression)
			{
				await _next.Invoke(context);
				return;
			}

			HttpRequest request = context.Request;
			HttpResponse response = context.Response;

			using (var cachedStream = new MemoryStream())
			{
				Stream originalStream = response.Body;
				response.Body = cachedStream;

				try
				{
					await _next.Invoke(context);
				}
				catch (Exception)
				{
					response.Body = originalStream;
					cachedStream.Clear();

					throw;
				}

				byte[] cachedBytes = cachedStream.ToArray();
				int cachedByteCount = cachedBytes.Length;
				bool isProcessed = false;

				response.Body = originalStream;
				cachedStream.Clear();

				if (request.Method == "GET" && response.StatusCode == 200
					&& _options.IsAllowableResponseSize(cachedByteCount))
				{
					string contentType = response.ContentType;
					string mediaType = null;
					Encoding encoding = null;

					if (contentType != null)
					{
						MediaTypeHeaderValue mediaTypeHeader;

						if (MediaTypeHeaderValue.TryParse(contentType, out mediaTypeHeader))
						{
							mediaType = mediaTypeHeader.MediaType.ToLowerInvariant();
							encoding = mediaTypeHeader.Encoding;
						}
					}

					encoding = encoding ?? Encoding.GetEncoding(0);

					string currentUrl = request.Path.Value;
					QueryString queryString = request.QueryString;
					if (queryString.HasValue)
					{
						currentUrl += queryString.Value;
					}

					string content = encoding.GetString(cachedBytes);
					string processedContent = content;
					IHeaderDictionary responseHeaders = response.Headers;
					bool isEncodedContent = responseHeaders.IsEncodedContent();
					Action<string, string> appendHttpHeader = (key, value) =>
					{
						responseHeaders.Append(key, new StringValues(value));
					};

					if (useMinification)
					{
						foreach (IMarkupMinificationManager minificationManager in _minificationManagers)
						{
							if (mediaType != null && minificationManager.IsSupportedMediaType(mediaType)
								&& minificationManager.IsProcessablePage(currentUrl))
							{
								if (isEncodedContent)
								{
									throw new InvalidOperationException(
										string.Format(
											AspNetCommonStrings.MarkupMinificationIsNotApplicableToEncodedContent,
											responseHeaders["Content-Encoding"]
										)
									);
								}

								IMarkupMinifier minifier = minificationManager.CreateMinifier();

								MarkupMinificationResult minificationResult = minifier.Minify(processedContent, currentUrl, encoding, false);
								if (minificationResult.Errors.Count == 0)
								{
									processedContent = minificationResult.MinifiedContent;
									if (_options.IsPoweredByHttpHeadersEnabled())
									{
										minificationManager.AppendPoweredByHttpHeader(appendHttpHeader);
									}

									isProcessed = true;
								}
							}

							if (isProcessed)
							{
								break;
							}
						}
					}

					if (useCompression && !isEncodedContent
						&& _compressionManager.IsSupportedMediaType(mediaType))
					{
						byte[] processedBytes = encoding.GetBytes(processedContent);

						using (var inputStream = new MemoryStream(processedBytes))
						using (var outputStream = new MemoryStream())
						{
							string acceptEncoding = request.Headers["Accept-Encoding"];
							ICompressor compressor = _compressionManager.CreateCompressor(acceptEncoding);

							using (Stream compressedStream = compressor.Compress(outputStream))
							{
								await inputStream.CopyToAsync(compressedStream);
							}

							byte[] compressedBytes = outputStream.ToArray();
							int compressedByteCount = compressedBytes.Length;

							outputStream.Clear();
							inputStream.Clear();

							responseHeaders["Content-Length"] = compressedByteCount.ToString();
							compressor.AppendHttpHeaders(appendHttpHeader);
							await originalStream.WriteAsync(compressedBytes, 0, compressedByteCount);
						}

						isProcessed = true;
					}
					else
					{
						if (isProcessed)
						{
							byte[] processedBytes = encoding.GetBytes(processedContent);
							int processedByteCount = processedBytes.Length;

							responseHeaders["Content-Length"] = processedByteCount.ToString();
							await originalStream.WriteAsync(processedBytes, 0, processedByteCount);
						}
					}
				}

				if (!isProcessed)
				{
					await originalStream.WriteAsync(cachedBytes, 0, cachedByteCount);
				}
			}
		}
        /// <summary>
        /// Calculatea a size of gzipped code
        /// </summary>
        /// <param name="bytes">Array of bytes</param>
        /// <returns>Size of gzipped code in bytes</returns>
        private static long CalculateGzipSize(byte[] bytes)
        {
            using (var memoryStream = new MemoryStream())
            {
                // the third parameter tells the GZIP stream to leave the base stream open so it doesn't
                // dispose of it when it gets disposed. This is needed because we need to dispose the
                // GZIP stream before it will write ANY of its data.
                using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, true))
                {
                    gzipStream.Write(bytes, 0, bytes.Length);
                }

                long compressedByteCount = memoryStream.Position;
                memoryStream.Clear();

                return compressedByteCount;
            }
        }