private static void PrepForReExecute(HttpContext context, UploadErrorsModel uploadErrorsModel) { // Clear request context.Request.Method = "POST"; context.Request.Body = Stream.Null; var query = new Dictionary <string, StringValues> { [nameof(uploadErrorsModel.Errors)] = uploadErrorsModel.Errors }; context.Request.QueryString = QueryString.Create(query); context.Request.ContentType = "text/plain"; // Set route data var routeData = new { controller = "Upload", action = "Frame", id = context.GetRouteValue("fileIdentifier") }; foreach (IRouter router in context.GetRouteData().Routers.Reverse()) { VirtualPathContext virtualPathContext = new VirtualPathContext(context, new RouteValueDictionary(), new RouteValueDictionary(routeData)); VirtualPathData data = router.GetVirtualPath(virtualPathContext); if (data != null) { context.Request.Path = new PathString(data.VirtualPath); return; } } }
private static void PrepForReExecute(HttpContext context, UploadErrorsModel uploadErrorsModel) { // Clear request context.Request.Method = "POST"; context.Request.Body = Stream.Null; if (uploadErrorsModel.Errors?.Length > 0) { Dictionary <string, StringValues> query = new Dictionary <string, StringValues> { [nameof(uploadErrorsModel.Errors)] = uploadErrorsModel.Errors }; context.Request.QueryString = QueryString.Create(query); } else { context.Request.QueryString = new QueryString(); } // Reset the request in its most basic form context.Request.ContentType = "text/plain"; context.Request.PathBase = "/"; context.Request.Path = "/"; // Set endpoint and associated routing data const string continuationEndpoint = "AfterUploadCompletionFrame"; IEndpointAddressScheme <string> svc = context.RequestServices.GetRequiredService <IEndpointAddressScheme <string> >(); IEnumerable <Endpoint> endpoints = svc.FindEndpoints(continuationEndpoint); bool hasSetEndpoint = false; foreach (Endpoint endpoint in endpoints) { if (hasSetEndpoint) { throw new InvalidOperationException($"Multiple endpoints {continuationEndpoint}"); } // Prepare routing values MVC uses for view lookups ControllerActionDescriptor?actionDescriptor = endpoint.Metadata.GetMetadata <ControllerActionDescriptor>(); if (actionDescriptor != null) { RouteData routeData = context.GetRouteData(); foreach (KeyValuePair <string, string?> routeValue in actionDescriptor.RouteValues) { routeData.Values[routeValue.Key] = routeValue.Value; } } // Set to endpoint to use later context.SetEndpoint(endpoint); hasSetEndpoint = true; } if (!hasSetEndpoint) { throw new InvalidOperationException($"Unable to find continuation endpoint {continuationEndpoint}"); } }
public IActionResult Frame(FileIdentifier fileIdentifier, UploadErrorsModel model) { if (model?.Errors != null) { foreach (string modelError in model.Errors) { this.ModelState.AddModelError(modelError, modelError); } } if (!this.ModelState.IsValid) { return(this.View("FrameError", model)); } return(this.View("FrameComplete", fileIdentifier)); }
public async Task ExecuteAsync(HttpContext context) { FileIdentifier identifier = FileIdentifier.FromString(context.GetRouteValue("fileIdentifier")?.ToString() ?? throw new InvalidOperationException("No ID")); this._logger.LogInformation(LogEvents.NewUpload, "New upload of file with id {0}", identifier); // We have already the ID, so we can set some progress UploadProgress progress = new UploadProgress { Current = 0, StartTime = DateTime.UtcNow, Total = context.Request.ContentLength ?? -1 }; this._uploadProgressManager.SetProgress(identifier, progress); // Initialize reading request MediaTypeHeaderValue contentType = GetContentType(context); string boundary = GetBoundary(contentType); MultipartReader reader = new MultipartReader(boundary, context.Request.Body); reader.BodyLengthLimit = (long?)this._fileStoreOptions.Value?.MaximumFileSize.Megabytes().Bytes; // Delegate actual request parsing // ... after the request "completes" we re-execute to send the final response to the browser try { await using (context.RequestAborted.Register(context.Abort)) { await this._uploadManager.StoreAsync(identifier, reader, context.RequestAborted); } PrepForReExecute(context, new UploadErrorsModel()); } catch (UploadCryptoArgumentOrderException) { PrepForReExecute(context, UploadErrorsModel.CreateFromMessage("Invalid order of cryptographic parameters: file was uploaded before password.")); } catch (Exception ex) { UploadErrorsModel errors = UploadErrorsModel.CreateFromMessage(ex.Message); this._logger.LogError(LogEvents.UploadFailed, "Detected failed upload - passing error to child handler: {0}", ex); PrepForReExecute(context, errors); } await ReExecuteAsync(context); }