/// <summary>
        /// Redirects the client to the specified file.
        /// </summary>
        public static void ReturnFile(this IDotvvmRequestContext context, Stream stream, string fileName, string mimeType, IEnumerable <KeyValuePair <string, string> > additionalHeaders = null)
        {
            var returnedFileStorage = context.Services.GetService <IReturnedFileStorage>();
            var metadata            = new ReturnedFileMetadata()
            {
                FileName          = fileName,
                MimeType          = mimeType,
                AdditionalHeaders = additionalHeaders?.GroupBy(k => k.Key, k => k.Value)?.ToDictionary(k => k.Key, k => k.ToArray())
            };

            var generatedFileId = returnedFileStorage.StoreFile(stream, metadata).Result;

            context.SetRedirectResponse(context.TranslateVirtualPath("~/dotvvmReturnedFile?id=" + generatedFileId));
            throw new DotvvmInterruptRequestExecutionException(InterruptReason.ReturnFile, fileName);
        }
    /// <summary>
    /// Redirects the client to the specified file.
    /// </summary>
    public static void ReturnFile(this IDotvvmRequestContext context, Stream stream, string fileName, string mimeType, IEnumerable <KeyValuePair <string, string> > additionalHeaders = null)
    {
        var returnedFileStorage = context.Services.GetService <IReturnedFileStorage>();

        if (returnedFileStorage == null)
        {
            throw new DotvvmFileStorageMissingException($"Unable to resolve service for type '{typeof(IReturnedFileStorage).Name}'. " +
                                                        $"Visit https://www.dotvvm.com/docs/tutorials/advanced-returning-files for more details!");
        }

        var metadata = new ReturnedFileMetadata()
        {
            FileName          = fileName,
            MimeType          = mimeType,
            AdditionalHeaders = additionalHeaders?.GroupBy(k => k.Key, k => k.Value)?.ToDictionary(k => k.Key, k => k.ToArray())
        };

        var generatedFileId = returnedFileStorage.StoreFile(stream, metadata).Result;

        context.SetRedirectResponse(context.TranslateVirtualPath("~/dotvvmReturnedFile?id=" + generatedFileId));
        throw new DotvvmInterruptRequestExecutionException(InterruptReason.ReturnFile, fileName);
    }
 /// <summary>
 /// Returns the redirect response and interrupts the execution of current request.
 /// </summary>
 public static void RedirectToUrl(this IDotvvmRequestContext context, string url, bool replaceInHistory = false, bool allowSpaRedirect = false)
 {
     context.SetRedirectResponse(context.TranslateVirtualPath(url), (int)HttpStatusCode.Redirect, replaceInHistory, allowSpaRedirect);
     throw new DotvvmInterruptRequestExecutionException(InterruptReason.Redirect, url);
 }