Asked by:
File not downloaded throw web api - and no errors ?

Question
-
User-1846805900 posted
Hi
i try to download file throw web api with resume support - i use this example as guide Implement resume download in asp.net
in my web api controller i use code:
public IHttpActionResult Post(EnContactUsVm contactToAdd) { // save new data in database var newContact = new TblContactUs { ContactEmail = contactToAdd.ContactEmail, ContactMessage = contactToAdd.ContactMessage }; _db.tblContactUS.Add(newContact); _db.SaveChanges(); // Get File const string filename = "DrasatTrader-Trial.exe"; var path = HttpContext.Current.Server.MapPath($"~/{filename}"); Downloader.DownloadFile(HttpContext.Current, path); return Ok(); }
but nothing happen code fired and nothing ! ?
so what could be the problem here please and how i can make it working ?
i create new class HttpResponseHeader.cs:
internal class HttpResponseHeader { public string AcceptRanges { get; set;} public string Connection { get; set; } public string ContentDisposition { get; set; } public Encoding ContentEncoding { get; set; } public string ContentLength { get; set; } public string ContentRange { get; set; } public string ContentType { get; set; } public string Etag { get; set; } public string LastModified { get; set; } }
and other class Downloader.cs
public class Downloader { public static void DownloadFile(HttpContext httpContext, string filePath) { if (!IsFileExists(filePath)) { httpContext.Response.StatusCode = 404; return; } var fileInfo = new FileInfo(filePath); if (fileInfo.Length > int.MaxValue) { httpContext.Response.StatusCode = 413; return; } // Get the response header information by the http request. var responseHeader = GetResponseHeader(httpContext.Request, fileInfo); if (responseHeader == null) { return; } var fileStream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); try { SendDownloadFile(httpContext.Response, responseHeader, fileStream); } catch (HttpException ex) { httpContext.Response.StatusCode = ex.GetHttpCode(); } finally { fileStream.Close(); } } /// <summary> /// Check whether the file exists. /// </summary> /// <param name="filePath"></param> /// <returns></returns> private static bool IsFileExists(string filePath) { var fileExists = false; if (!string.IsNullOrEmpty(filePath)) { if (File.Exists(filePath)) { fileExists = true; } } return fileExists; } /// <summary> /// Get the response header by the http request. /// </summary> /// <param name="httpRequest"></param> /// <param name="fileInfo"></param> /// <returns></returns> private static HttpResponseHeader GetResponseHeader(HttpRequest httpRequest, FileInfo fileInfo) { if (httpRequest == null) { return null; } if (fileInfo == null) { return null; } long startPosition = 0; var contentRange = ""; var fileName = fileInfo.Name; var fileLength = fileInfo.Length; var lastUpdateTimeStr = fileInfo.LastWriteTimeUtc.ToString(CultureInfo.CurrentCulture); var eTag = HttpUtility.UrlEncode(fileName, Encoding.UTF8) + " " + lastUpdateTimeStr; var contentDisposition = "attachment;filename=" + HttpUtility.UrlEncode(fileName, Encoding.UTF8)?.Replace("+", "%20"); if (httpRequest.Headers["Range"] != null) { var range = httpRequest.Headers["Range"].Split('=', '-'); startPosition = Convert.ToInt64(range[1]); if (startPosition < 0 || startPosition >= fileLength) { return null; } } if (httpRequest.Headers["If-Range"] != null) { if (httpRequest.Headers["If-Range"].Replace("\"", "") != eTag) { startPosition = 0; } } var contentLength = (fileLength - startPosition).ToString(); if (startPosition > 0) { contentRange = $" bytes {startPosition}-{fileLength - 1}/{fileLength}"; } var responseHeader = new HttpResponseHeader { AcceptRanges = "bytes", Connection = "Keep-Alive", ContentDisposition = contentDisposition, ContentEncoding = Encoding.UTF8, ContentLength = contentLength, ContentRange = contentRange, ContentType = "application/octet-stream", Etag = eTag, LastModified = lastUpdateTimeStr }; return responseHeader; } /// <summary> /// Send the download file to the client. /// </summary> /// <param name="httpResponse"></param> /// <param name="responseHeader"></param> /// <param name="fileStream"></param> private static void SendDownloadFile(HttpResponse httpResponse, HttpResponseHeader responseHeader, Stream fileStream) { if (httpResponse == null || responseHeader == null) { return; } if (!string.IsNullOrEmpty(responseHeader.ContentRange)) { httpResponse.StatusCode = 206; // Set the start position of the reading files. var range = responseHeader.ContentRange.Split(' ', '=', '-'); fileStream.Position = Convert.ToInt64(range[2]); } httpResponse.Clear(); httpResponse.Buffer = false; httpResponse.AppendHeader("Accept-Ranges", responseHeader.AcceptRanges); httpResponse.AppendHeader("Connection", responseHeader.Connection); httpResponse.AppendHeader("Content-Disposition", responseHeader.ContentDisposition); httpResponse.ContentEncoding = responseHeader.ContentEncoding; httpResponse.AppendHeader("Content-Length", responseHeader.ContentLength); if (!string.IsNullOrEmpty(responseHeader.ContentRange)) { httpResponse.AppendHeader("Content-Range", responseHeader.ContentRange); } httpResponse.ContentType = responseHeader.ContentType; httpResponse.AppendHeader("Etag", "\"" + responseHeader.Etag + "\""); httpResponse.AppendHeader("Last-Modified", responseHeader.LastModified); var buffer = new byte[10240]; var fileLength = Convert.ToInt64(responseHeader.ContentLength); // Send file to client. while (fileLength > 0) { if (httpResponse.IsClientConnected) { var length = fileStream.Read(buffer, 0, 10240); httpResponse.OutputStream.Write(buffer, 0, length); httpResponse.Flush(); fileLength = fileLength - length; } else { fileLength = -1; } } } }
Thursday, April 7, 2016 2:21 PM
All replies
-
User36583972 posted
Hi a.amin,
ASP.NET Web API provides out of the box support for streaming binary files to the client. You can try the following tutorials to build download service.
1: ASP.NET Web API file download service with resume support:
http://piotrwalat.net/file-download-service-with-resume-support-using-asp-net-web-api/
2: File upload download service with ASP.NET Web API and Windows Phone background file transfer:
Then, try to debug your program again. You could also share us more relevant debug information to us.
Best Regards,
Yohann Lu
Friday, April 8, 2016 6:16 AM -
User-1846805900 posted
Thanks Yohann Lu
i try both link you sent to me but nothing - i don't know why it's not working
from this link : http://piotrwalat.net/file-download-service-with-resume-support-using-asp-net-web-api/
i have add in my project (ContentInfo.cs, FileProvider.cs, IFileProvider.cs, PartialReadFileStream.cs)
and in my web api controller i have add :
public HttpResponseMessage Get(string fileName) { if (!FileProvider.Exists(fileName)) { //if file does not exist return 404 throw new HttpResponseException(HttpStatusCode.NotFound); } long fileLength = FileProvider.GetLength(fileName); ContentInfo contentInfo = GetContentInfoFromRequest(this.Request, fileLength); var stream = new PartialReadFileStream(FileProvider.Open(fileName), contentInfo.From, contentInfo.To); var response = new HttpResponseMessage(); response.Content = new StreamContent(stream); SetResponseHeaders(response, contentInfo, fileLength, fileName); return response; } private ContentInfo GetContentInfoFromRequest(HttpRequestMessage request, long entityLength) { var result = new ContentInfo { From = 0, To = entityLength - 1, IsPartial = false, Length = entityLength }; RangeHeaderValue rangeHeader = request.Headers.Range; if (rangeHeader != null && rangeHeader.Ranges.Count != 0) { //we support only one range if (rangeHeader.Ranges.Count > 1) { //we probably return other status code here throw new HttpResponseException(HttpStatusCode.RequestedRangeNotSatisfiable); } RangeItemHeaderValue range = rangeHeader.Ranges.First(); if (range.From.HasValue && range.From < 0 || range.To.HasValue && range.To > entityLength - 1) { throw new HttpResponseException(HttpStatusCode.RequestedRangeNotSatisfiable); } result.From = range.From ?? 0; result.To = range.To ?? entityLength - 1; result.IsPartial = true; result.Length = entityLength; if (range.From.HasValue && range.To.HasValue) { result.Length = range.To.Value - range.From.Value + 1; } else if (range.From.HasValue) { result.Length = entityLength - range.From.Value + 1; } else if (range.To.HasValue) { result.Length = range.To.Value + 1; } } return result; } private void SetResponseHeaders(HttpResponseMessage response, ContentInfo contentInfo, long fileLength, string fileName) { response.Headers.AcceptRanges.Add("bytes"); response.StatusCode = contentInfo.IsPartial ? HttpStatusCode.PartialContent : HttpStatusCode.OK; response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment"); response.Content.Headers.ContentDisposition.FileName = fileName; response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream"); response.Content.Headers.ContentLength = contentInfo.Length; if (contentInfo.IsPartial) { response.Content.Headers.ContentRange = new ContentRangeHeaderValue(contentInfo.From, contentInfo.To, fileLength); } }
and i call action as:
public IHttpActionResult SaveNewTrial(EnTrialVm trialToAdd) { var newTrial = new TblTrial { FirstName = trialToAdd.FirstName, LastName = trialToAdd.LastName, TrialEmail = trialToAdd.TrialEmail }; _db.tblTrials.Add(newTrial); _db.SaveChanges(); // here i call Get HttpResponseMessage To download file but nothing Get("DrasatTrader-Trial.exe"); }
but nothing - i make breakpoints and i see all file information in the code full path, size ..... - but i don't know why it's not downloading ?
amd in secound link: https://blogs.msdn.microsoft.com/codefx/2012/02/23/more-about-rest-file-upload-download-service-with-asp-net-web-api-and-windows-phone-background-file-transfer/
i try it nothing too ?
Not i try to download file from MVC action as:
public ActionResult Download() { return File(Server.MapPath("~/TemplateFiles/downloads/DrasatTrader-Trial.exe"), "application/x-msdownload", "DrasatTrader-Trial.exe"); }
i got nothing but got this error ??!!
if you need me upload sample project i can do it to let you help me ?
Friday, April 8, 2016 1:55 PM -
User36583972 posted
Hi a.amin,
Your download file method should have a return type as HttpResponseMessage. You can change your Web API action as the below.
public HttpResponseMessage SaveNewTrial(EnTrialVm trialToAdd) { var newTrial = new TblTrial { FirstName = trialToAdd.FirstName, LastName = trialToAdd.LastName, TrialEmail = trialToAdd.TrialEmail }; _db.tblTrials.Add(newTrial); _db.SaveChanges(); // here i call Get HttpResponseMessage To download file but nothing return Get("DrasatTrader-Trial.exe"); }
You can also try the following method to download file in Web API.
[AllowAnonymous] public HttpResponseMessage GetTestFile() { HttpResponseMessage result = null; var localFilePath = HttpContext.Current.Server.MapPath("~/20160310021806.xls"); if (!File.Exists(localFilePath)) { result = Request.CreateResponse(HttpStatusCode.Gone); } else { // Serve the file to the client result = Request.CreateResponse(HttpStatusCode.OK); result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read)); result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); result.Content.Headers.ContentDisposition.FileName = "20160310021806.xls"; } return result; }
Best Regards,
Yohann Lu
Monday, April 11, 2016 5:32 AM -
User-1846805900 posted
Hi a.amin,
Your download file method should have a return type as HttpResponseMessage. You can change your Web API action as the below.
public HttpResponseMessage SaveNewTrial(EnTrialVm trialToAdd) { var newTrial = new TblTrial { FirstName = trialToAdd.FirstName, LastName = trialToAdd.LastName, TrialEmail = trialToAdd.TrialEmail }; _db.tblTrials.Add(newTrial); _db.SaveChanges(); // here i call Get HttpResponseMessage To download file but nothing return Get("DrasatTrader-Trial.exe"); }
You can also try the following method to download file in Web API.
[AllowAnonymous] public HttpResponseMessage GetTestFile() { HttpResponseMessage result = null; var localFilePath = HttpContext.Current.Server.MapPath("~/20160310021806.xls"); if (!File.Exists(localFilePath)) { result = Request.CreateResponse(HttpStatusCode.Gone); } else { // Serve the file to the client result = Request.CreateResponse(HttpStatusCode.OK); result.Content = new StreamContent(new FileStream(localFilePath, FileMode.Open, FileAccess.Read)); result.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment"); result.Content.Headers.ContentDisposition.FileName = "20160310021806.xls"; } return result; }
Best Regards,
Yohann Lu
i try both and nothing - i work around it as:
1. add "DownloadHttpHandler.ashx" file to my project with code:
public class DownloadHttpHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { var filePath = HttpContext.Current.Server.MapPath("/TemplateFiles/downloads/Trial.exe"); Downloader.DownloadFile(HttpContext.Current, filePath); } public bool IsReusable => false; }
2. in view i add code as:
<form action="~/DownloadHttpHandler.ashx" ng-submit="save(); tri={}" ng-controller="NewTrialController"> @Html.AntiForgeryToken() @Html.ValidationSummary(true, "", new {@class = "text-danger"}) <h1 class="prod-trial-h1 text-center">Subscribe To Our Newsletter</h1> <hr /> @Html.Partial("_EnTrial") </form>
and now the web api action is fired and file is downloaded too
- the thing i try to do now but i can't is how to make it works only if data saved or after data is saved ?
- i hope to get help in this section ?
Wednesday, April 13, 2016 12:26 AM -
User36583972 posted
Hi a.amin,
- the thing i try to do now but i can't is how to make it works only if data saved or after data is saved ?I suggest you use asynchronous methods in your methods. When the data saved or after the data is saved, you will get a state (Ok, or fail), then you can download files.
The following post introduces how to use asynchronous methods fro your reference.
http://forums.asp.net/t/2092556.aspx?Setting+an+explicit+timeout+value+for+action+method+WebApi2
Also, If you have any questions, you can submit a new post in the relevant forums.
Best Regards,
Yohann Lu
Thursday, April 14, 2016 8:12 AM