I have a webapplication that is set up with a link, and when this link is pressed then a file is downloaded. The file location right now i is on my own HDD. It works when I download the file from Google Chrome, but when i use IE i get a weird scrambled filename. This is my code:
[HttpGet]
public HttpResponseMessage GetFile(string filename, string environment)
{
_requestLogger.LogRequest(Request);
var validateResult = new InputValidator().ValidateInput(filename);
if (!validateResult.IsValid)
{
return new HttpResponseMessage { StatusCode = HttpStatusCode.BadRequest, ReasonPhrase = validateResult.ErrorMessage };
}
filename = SanitizeFileName(filename);
var filePath = _settings.ResolveFilePath(environment, filename);
if (!File.Exists(filePath))
{
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
//Get file
var stream = new FileStream(filePath, FileMode.Open);
//Create result
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
//Add content to result
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
Here is a link to an image of the weird filename
I cant seem to figure out why this is happening. Can anyone help ?
Try to add the filename and content-length headers, something like this:
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") {
FileName = fileName.ToString()
};
response.Content.Headers.ContentLength=stream.Length.ToString();
I figured out what i had to do. I created this method and it solved my problem.
public static void AddProperFileNameHeadersIfIE(HttpContextBase httpContext, string fileName)
{
var browser = httpContext.Request.Browser;
if (browser != null && browser.Browser.Equals("ie", StringComparison.OrdinalIgnoreCase))
{
httpContext.Response.AppendHeader("Content-Disposition", "attachment; filename*=UTF-8''" + HttpUtility.UrlPathEncode(fileName) + "\"");
}
else
{
httpContext.Response.AppendHeader("Content-Disposition", "attachment; filename=\"" + HttpUtility.UrlPathEncode(fileName) + "\"");
}
}
Related
I am trying to use HttpClient with putasync to send file to server. The function looks like:
public async Task SendCsvFile(string path,string apiKey)
{
try
{
string clientKey = "";
LoggerService.Logger.CreateLog("Log");
LoggerService.Logger.Info("Start:SendCsvFile");
FileStream fileStream = null;
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
HttpClient httpClient = new HttpClient(clientHandler);
httpClient.DefaultRequestHeaders.Accept.Clear();
httpClient.DefaultRequestHeaders.Add("x-api-key", clientKey);
string url = "https://test.csv";
var content = new MultipartFormDataContent();
var fileName = Path.GetFileName(path);
fileStream = File.OpenRead(path);
StreamContent streamContent = new StreamContent(fileStream);
content.Add(new StreamContent(fileStream), fileName, fileName);
var response = await httpClient.PutAsync(url, content);
if (response.IsSuccessStatusCode == true)
{
LoggerService.Logger.Info("File sent correctly.");
}
else
{
LoggerService.Logger.Error("Error during sending." + response.StatusCode + ";" + response.ReasonPhrase + ";");
}
fileStream.Close();
LoggerService.Logger.Info("End:SendCsvFile");
}
catch (Exception ex)
{
LoggerService.Logger.Error(ex.ToString());
//return 0;
}
//return 1;
}
File is send fine and it works however Content-disposition header is added to the file to the first line, and client doesn't want that. It's the first time I am doing anything with services and I read through a lot but still I don't know what can i change to not alter the content of csv file.
EDIT.
After I send the file header is added to the content so the file looks like that.
Screenshot from client server
All the data is fine, though the client server processes the data in a way that it should start from column names. So my question really is what can I can change to omit that first line and is it even possible. Maybe thats something obvious but i' m just a newbie in this stuff.
Changing to MultipartContent and Clearing Headers almost work but left me with boundary still visible in a file. Eventually I changed to RestSharp and adding content this way got rid of the problem.
public async Task SendCsvFile(string path, string apiKey)
{
try
{
string clientKey = "";
string url = "";
LoggerService.Logger.CreateLog("CreationAndDispatchStatesWithPrices");
LoggerService.Logger.Info("Start:SendCsvFile");
FileStream fileStream = null;
var fileName = Path.GetFileName(path);
fileStream = File.OpenRead(path);
var client = new RestClient(url);
// client.Timeout = -1;
var request = new RestRequest();
request.AddHeader("x-api-key", clientKey);
request.AddHeader("Content-Type", "text/csv");
request.AddParameter("text/csv", File.ReadAllBytes(path), ParameterType.RequestBody);
RestResponse response = client.Put(request);
if (response.IsSuccessful == true)
{
LoggerService.Logger.Info("File sent correctly.");
}
else
{
LoggerService.Logger.Error("Error sending file." + response.StatusCode + ";" + response.ErrorMessage + ";");
}
fileStream.Close();
LoggerService.Logger.Info("End:SendCsvFile");
}
catch (Exception ex)
{
LoggerService.Logger.Error(ex.ToString());
//return 0;
}
//return 1;
}
I have a Web Api controller, that gets file. (Server)
[HttpGet]
[Route("api/FileDownloading/download")]
public HttpResponseMessage GetDocuments()
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
var fileName = "QRimage2.jpg";
var filePath = HttpContext.Current.Server.MapPath("");
var fileBytes = File.ReadAllBytes(#"c:\\TMP\\QRimage2.jpg");
MemoryStream fileMemStream = new MemoryStream(fileBytes);
result.Content = new StreamContent(fileMemStream);
var headers = result.Content.Headers;
headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
headers.ContentDisposition.FileName = fileName;
headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
headers.ContentLength = fileMemStream.Length;
return result;
}
And Xamarin Android client, that downloading the file using the controller (http://localhost:6100/api/FileDownloading/download)
public void DownloadFile(string url, string folder)
{
string pathToNewFolder = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, folder);
Directory.CreateDirectory(pathToNewFolder);
try
{
WebClient webClient = new WebClient();
webClient.DownloadFileCompleted += new AsyncCompletedEventHandler(Completed);
string pathToNewFile = Path.Combine(pathToNewFolder, Path.GetFileName(url));
webClient.DownloadFileAsync(new Uri(url), null);
}
catch (Exception ex)
{
if (OnFileDownloaded != null)
OnFileDownloaded.Invoke(this, new DownloadEventArgs(false));
}
}
Everithing works fine, but on my Android device in file explorer i have file with "download" file name instead of "QRimage2.jpg". How can I get actual file name using this controller?
You will need use the web response to read the content disposition. So, we can't use DownloadFileAsync directly.
public async Task<string> DownloadFileAsync(string url, string folder)
{
var request = WebRequest.Create(url);
var response = await request.GetResponseAsync().ConfigureAwait(false);
var fileName = string.Empty;
if (response.Headers["Content-Disposition"] != null)
{
var contentDisposition = new System.Net.Mime.ContentDisposition(response.Headers["Content-Disposition"]);
if (contentDisposition.DispositionType == "attachment")
{
fileName = contentDisposition.FileName;
}
}
if (string.IsNullOrEmpty(fileName))
{
throw new ArgumentException("Cannot be null or empty.", nameof(fileName));
}
var filePath = Path.Combine(Android.OS.Environment.ExternalStorageDirectory.AbsolutePath, folder, fileName);
using (var contentStream = response.GetResponseStream())
{
using (var fileStream = File.Create(filePath))
{
await contentStream.CopyToAsync(fileStream).ConfigureAwait(false);
}
}
return filePath;
}
Is this always going to be a jpg? If so I'd change the MediaTypeHeaderValue to image/jpeg - By doing that you are telling the browser the exact type of file, instead of a generic file. I'm thinking this is the issue since you are telling the Android Browser it's just a generic binary file.
Do I need Content-Type: application/octet-stream for file download?
Working o an webapi application with angularJS as UI.
When I download a file to my desktop from my application. The name is changed replacing some characters like 'é','ü' with characters like these é.
The code used to donwload the file is the following.
[HttpGet, Route("{documentid}/raw", Order = 5)]
public IHttpActionResult GetDocumentRaw(string documentid)
{
var service = ResolveService<IDocumentService>();
var raw = service.GetRaw(documentid);
if (raw.Data == null)
{
return NotFound();
}
var fileName = raw.FileName?.GetCleanFileName();
var contentType = raw.ContentType;
if (String.IsNullOrWhiteSpace(fileName))
{
fileName = "rawdata";
}
if (String.IsNullOrWhiteSpace(contentType))
{
contentType = "application/octet-stream";
}
var response = Request.CreateResponse(HttpStatusCode.OK);
Stream stream = new MemoryStream(raw.Data);
response.Content = new StreamContent(stream);
response.Content.Headers.Remove("content-type");
response.Content.Headers.Add("content-type", contentType);
response.Content.Headers.Add("content-disposition", "inline; filename=\"" + fileName + "\"");
response.Content.Headers.Add("content-length", stream.Length.ToString());
response.Content.Headers.Remove("x-filename");
response.Content.Headers.Add("x-filename", fileName);
return ResponseMessage(response);
}
In the UI side, this function is used to download the file.
$download: function(propertyTypeKey) {
$http
.get(this.url + '/raw', {
responseType: 'arraybuffer',
params: {
propertyTypeKey: propertyTypeKey
}
})
.then(function (response) {
DownloadService.downloadFile(
response.data,
response.headers('content-type'),
response.headers('x-filename')
);
});
},
Is this something related to textformat encoding ? Should I add some configuration in the Http Response ? Or may be it is related to the configuration of the IIS Server ?
I firstly suspected my chrome navigator but I'm facing the same issue on IE.
Thank you.
i am trying to download a file (.docx) from asp.net web api.
Since i already have a document in the server i set the path to existing one and then i follow something sugested on stackoverflow and do this:
docDestination is my path.
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(docDestination, FileMode.Open, FileAccess.Read);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
return result;
after that on my client side i try to do this:
.then(response => {
console.log("here lives the response:", response);
var headers = response.headers;
var blob = new Blob([response.body], { type: headers['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] });
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "Filename";
link.click();
}
this is what i get on my response
what i get:
any help?
Just add ContentDisposition to your response header with value of attachment and the browser will interpret it as a file that needs to be download
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(docDestination, FileMode.Open,FileAccess.Read);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "document.docx"
};
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.openxmlformats-officedocument.wordprocessingml.document");
return result;
Take a look in this link for more information in ContentDisposition header
Change return type of your method. You can write method something like this.
public FileResult TestDownload()
{
FileContentResult result = new FileContentResult(System.IO.File.ReadAllBytes("YOUR PATH TO DOC"), "application/msword")
{
FileDownloadName = "myFile.docx"
};
return result;
}
In client side, you just need to have a link button. Once you click on the button, file will be downloaded. Just write this line in cshtml file. replace controller name with your controller name.
#Html.ActionLink("Button 1", "TestDownload", "YourCOntroller")
When you have a stream open, you want to return it's content as a file
[HttpGet]
public async Task<FileStreamResult> Stream()
{
var stream = new MemoryStream(System.IO.File.ReadAllBytes("physical path of file"));
var response = File(stream, "Mime Type of file");
return response;
}
You use it when you have a byte array you would like to return as a file
[HttpGet]
public async Task<FileContentResult> Content()
{
var result = new FileContentResult(System.IO.File.ReadAllBytes("physical path of file"), "Mime Type of file")
{
FileDownloadName = "Your FileName"
};
return result;
}
when you have a file on disk and would like to return it's content (you give a path)-------------only in asp.net core
[HttpGet]
public async Task<IActionResult> PhysicalPath()
{
var result = new PhysicalFileResult("physical path of file", "Mime Type of file")
{
FileDownloadName = "Your FileName",
FileName = "physical path of file"
};
return result;
}
I am using WebAPI for downloading a .pdf file like this:
[HttpGet]
public async Task<HttpResponseMessage> DownloadFile(string id, bool attachment = true)
{
HttpResponseMessage result = null;
try
{
MyService service = new MyService();
var bytes = await service.DownloadFileAsync(id);
if (bytes != null)
{
result = GetBinaryFile(personalDocument, string.Format("{0}.pdf", id), attachment);
}
else
{
result = new HttpResponseMessage(HttpStatusCode.NotFound);
}
}
catch (Exception ex)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest) { ReasonPhrase = "ServerError" });
}
return result;
}
private HttpResponseMessage GetBinaryFile(byte[] bytes, string fileName, bool attachment)
{
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
// result.Content = new ByteArrayContent(bytes);
result.Content = new StreamContent(new System.IO.MemoryStream(bytes));
//result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("inline");
if (attachment)
{
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
}
result.Content.Headers.ContentDisposition.FileName = fileName;
result.Content.Headers.ContentLength = bytes.Length;
return result;
}
The issue is: when I download file for the first time it freezes the browser, and cannot perform anything. But after a refresh of the page, every time the file download is successful.
I tried to use ByteArrayContent or StreamContent but same thing happens. I also tried to use MediaTypeHeaderValue("application/octet-stream") or MediaTypeHeaderValue("application/pdf"), but again - the same issue occurred.
So I find that the problem is
if (attachment)
{
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
}
If I set attachment to be true it set ContentDisposition to be ContentDispositionHeaderValue("attachment") (it is for download only)
If I set attachment to be false it open the file immediately and doesn't freeze the browser..
Any idea? Thanks!