I'm developing in ASP.NET MVC3 and I have the the code below for saving the file in Sql Server 2008, it works well for IE (I used IE9) but in Firefox I get the error "Index was out of range. Must be non-negative and less than the size of the collection.\r\nParameter name: index", how should i fix this? thanks
[HttpPost]
public ActionResult FileUpload(string qqfile)
{
try
{
HttpPostedFileBase postedFile = Request.Files[0];
var stream = postedFile.InputStream;
App_MessageAttachment NewAttachment = new App_MessageAttachment
{
FileName = postedFile.FileName.ToString().Substring(postedFile.FileName.ToString().LastIndexOf('\\') + 1),
FilteContentType = postedFile.ContentType,
MessageId = 4,
FileData = new byte[postedFile.ContentLength]
};
postedFile.InputStream.Read(NewAttachment.FileData, 0, postedFile.ContentLength);
db.App_MessageAttachments.InsertOnSubmit(NewAttachment);
db.SubmitChanges();
}
catch (Exception ex)
{
return Json(new { success = false, message = ex.Message }, "application/json");
}
return Json(new { success = true }, "text/html");
}
The Valums Ajax upload has 2 modes. If it recognizes that the browser supports HTML5 File API (which undoubtedly is the case with FireFox) it uses this API instead of using an enctype="multipart/form-data" request. So in your controller action you need to account for those differences and in the case of modern browsers that support HTML5 read the Request.InputStream directly:
[HttpPost]
public ActionResult FileUpload(string qqfile)
{
try
{
var stream = Request.InputStream;
var filename = Path.GetFileName(qqfile);
// TODO: not sure about the content type. Check
// with the documentation how is the content type
// for the file transmitted in the case of HTML5 File API
var contentType = Request.ContentType;
if (string.IsNullOrEmpty(qqfile))
{
// IE
var postedFile = Request.Files[0];
stream = postedFile.InputStream;
filename = Path.GetFileName(postedFile.FileName);
contentType = postedFile.ContentType;
}
var contentLength = stream.Length;
var newAttachment = new App_MessageAttachment
{
FileName = filename,
FilteContentType = contentType,
MessageId = 4,
FileData = new byte[contentLength]
};
stream.Read(newAttachment.FileData, 0, contentLength);
db.App_MessageAttachments.InsertOnSubmit(newAttachment);
db.SubmitChanges();
}
catch (Exception ex)
{
return Json(new { success = false, message = ex.Message });
}
return Json(new { success = true }, "text/html");
}
The code might need some tweaking. I don't have time to test it right now but you get the idea: in the case of HTML5 enabled browser the file is written directly to the body of the request whereas for browsers that do not support the File API the file data is transmitted using the standard multipart/form-data encoding.
Related
so both applications are running on https and on local host when i debug the api completes successfully and does return a 201 status and updates the database successfully.
[HttpPost()]
[Route("api/dealers/add")]
public async Task<IActionResult> CreateDealer([FromBody] DealerForCreation dealerForCreation)
{
// get the environments web root path
var webRootPath = _hostingEnvironment.WebRootPath;
var dealer = new Dealer { Name = dealerForCreation.Name };
//create the filename
var filename = Guid.NewGuid().ToString() + ".jpg";
// the full filepath
var filePath = Path.Combine($"{webRootPath}/images/dealers/{filename}");
// write bytes and close stream
await System.IO.File.WriteAllBytesAsync(filePath, dealerForCreation.Bytes);
//add the filename to the dealer
dealer.ImageFileName = filename;
// add and save the dealer
var newDealer = await _dealerService.CreateAsync(dealer).ConfigureAwait(false);
var result = CreatedAtRoute("GetDealer", new { newDealer.Id });
return result;
}
However the client application doesn't seem to recieve the 201 and instead gets a 500. Is there something simple i have missed?
[HttpPost]
[Route("QuestHelper/Dealers/Add")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Add(CreateDealerViewModel createDealerViewModel)
{
if (!ModelState.IsValid)
{
return View("Add", createDealerViewModel);
}
// create a dealerforcreation instance
var dealerForCreation = new DealerForCreation { Name = createDealerViewModel.Name };
//if the file exists read the stream and copy to memory.
if (createDealerViewModel.File != null)
{
using var fileStream = createDealerViewModel.File.OpenReadStream();
using var ms = new MemoryStream();
{
await fileStream.CopyToAsync(ms);
dealerForCreation.Bytes = ms.ToArray();
}
}
// serialize it
var serializedDealerForCreation = JsonConvert.SerializeObject(dealerForCreation);
// get the client and the request
GetClientAndRequest(HttpMethod.Post, route: "/api/dealers/add");
request.Content = new StringContent(serializedDealerForCreation,
Encoding.Unicode, "application/json");
var response = await httpClient.SendAsync(request, HttpCompletionOption.ResponseContentRead).
ConfigureAwait(false);
var status = response.StatusCode; // returns 500 error .. don't know why.. the api returns 201
return RedirectToAction("List");
}
I have tried running it synchronously and also without validating the anti-forgery token and still get the same result.
I am trying to open a new tab and display a downloaded pdf from Core 2.2 web API in angular 9
public GeneratePdf(id: string): Observable<Blob> {
return this.http.get( this.urlPdf + '?id=' + id, { responseType: 'blob' });
}
this.dataProvider.GeneratePdf(id).subscribe({
next: (blob) => {
const blobpart = new Blob([blob], { type: 'application/pdf' });
var fileUrl = URL.createObjectURL(blobpart);
let win: any = this.getWindow();
win.open(fileUrl);
},
error: (err) => this.error.handelHttpError(err),
});
API
[HttpGet]
[Route("PDF")]
public async Task<HttpResponseMessage> PDF(Guid Id) {
_logger.LogInformation("Request:" + Request.GetDisplayUrl());
var endpoint = _appSettings.PdfEndpoint;
try {
var param = await _dal.GetPDFParameters(Id, endpoint);
// Get PDF stream
HttpResponseMessage response = await client.GetAsync(param.EndpontUrl);
if(response.IsSuccessStatusCode) {
using(HttpContent content = response.Content) {
var memStream = new MemoryStream();
Stream sourceStream = await content.ReadAsStreamAsync();
sourceStream.CopyTo(memStream);
var result = new HttpResponseMessage(HttpStatusCode.OK) {
Content = new ByteArrayContent(memStream.ToArray())
};
result.Content.Headers.ContentDisposition =
new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment") {
FileName = Id.ToString() + ".pdf"
};
result.Content.Headers.ContentType =
new MediaTypeHeaderValue("application/octet-stream");
return result;
}
} else {
var result = new HttpResponseMessage(HttpStatusCode.BadRequest);
return result;
}
} catch(Exception ex) {
_logger.LogError(ex, "Exception error");
var result = new HttpResponseMessage(HttpStatusCode.InternalServerError);
return result;
}
}
it doesn't throw an error, it just opens a json object in the new tab, and the size of the object looks too small as the pdf content is over 3k bytes
{"version":{"major":1,"minor":1,"build":-1,"revision":-1,"majorRevision":-1,"minorRevision":-1},"content":{"headers":[{"key":"Content-Disposition","value":["attachment; filename=bd94ee98-65be-4c4f-a001-abecaf1a0644.pdf"]},{"key":"Content-Type","value":["application/octet-stream"]}]},"statusCode":200,"reasonPhrase":"OK","headers":[],"requestMessage":null,"isSuccessStatusCode":true}
update, there was a small error on the Blob, I was not passing in the blobpart to the url.CreateObjecturl Now the app loads the new tab, but states an invalid pdf as there is no content. I know the pdf bytes are going into the content of the api result as i have checked it. and converted it to a string to ensure it's a pdf, which it is.
Thanks for taking the time too look.
I am making API in asp.net Web API framework. I want to read file and convert it into bytes and return it to client.But when reading the file, exception occurs, URL format is not supported?
URL with fileName is send by client.I want to get the file from this URL and convert it into bytes. Tell me about , how i do this?
[Route("api/product/v1/displayimage")]
[AllowAnonymous]
[HttpPost]
//[GZipCompression]
public async Task<byte[]> DisplayImage([FromBody] FilesVM model)
{
try
{
var UrlBase = Url.Content(model.BaseURL);
//var UrlBase = Url.Content("~/Images/Users/5-signs-march14");
// MemoryStream workStream = new MemoryStream();
//string contentType = MimeMapping.GetMimeMapping(fileName);
byte[] byteInfo = System.IO.File.ReadAllBytes(UrlBase);
return await Task.FromResult(byteInfo);
}
catch (Exception ex)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}
Url.Content only returns a string (http://localhost/Image...). If you want the actual content you will have to download it. Here's an example:
using (var client = new WebClient())
{
return await Task.FromResult(client.DownloadData(Url.Content("~/Images/Users/5-signs-march14")));
}
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'm trying to send a 9MB .xls file as a response from web api controller method. The user will click a button on the page and this will trigger the download via the browser.
Here's what I've got so far but it doesn't work however it doesn't throw any exceptions either.
[AcceptVerbs("GET")]
public HttpResponseMessage ExportXls()
{
try
{
byte[] excelData = m_toolsService.ExportToExcelFile();
HttpResponseMessage result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new MemoryStream(excelData);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Data.xls"
};
return result;
}
catch (Exception ex)
{
m_logger.ErrorException("Exception exporting as excel file: ", ex);
return Request.CreateResponse(HttpStatusCode.InternalServerError);
}
}
Here is the coffeescript/javascript jquery ajax call from a button click in the interface.
$.ajax(
url: route
dataType: 'json'
type: 'GET'
success: successCallback
error: errorCallback
)
Now that I think about it perhaps the dataType is wrong and shouldn't be json...
Works also as a HTTP GET method, but don't use $ajax, instead use
window.open(url);
C# code:
[HttpGet]
[Route("report/{scheduleId:int}")]
public HttpResponseMessage DownloadReport(int scheduleId)
{
var reportStream = GenerateExcelReport(scheduleId);
var result = Request.CreateResponse(HttpStatusCode.OK);
result.Content = new StreamContent(reportStream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "Schedule Report.xlsx"
};
return result;
}
JS code:
downloadScheduleReport: function (scheduleId) {
var url = baseUrl + 'api/Tracker/report/' + scheduleId;
window.open(url);
}
I had to make a couple of small changes to get this to work
First: Change the method to a post
[AcceptVerbs("POST")]
Second: Change from using the jQuery ajax lib to use a hidden form, here's my service function for doing the hidden form and submitting it.
exportExcel: (successCallback) =>
if $('#hidden-excel-form').length < 1
$('<form>').attr(
method: 'POST',
id: 'hidden-excel-form',
action: 'api/tools/exportXls'
).appendTo('body');
$('#hidden-excel-form').bind("submit", successCallback)
$('#hidden-excel-form').submit()
Hopefully there's a better way to do this but for the time being it's working and downloading the excel file nicely.
I experienced the same problem.
Problem solved with the following:
window.open(url)
It will store the excel file created in a folder in the system and once its sent to Browser, it will be deleted .
//path to store Excel file temporarily
string tempPathExcelFile = AppDomain.CurrentDomain.BaseDirectory + DateTime.Now.Hour + DateTime.Now.Minute +
DateTime.Now.Second + DateTime.Now.Millisecond +
"_temp";
try
{
//Get Excel using Microsoft.Office.Interop.Excel;
Excel.Workbook workbook = ExportDataSetToExcel();
workbook.SaveAs(tempPathExcelFile, workbook.FileFormat);
tempPathExcelFile = workbook.FullName;
workbook.Close();
byte[] fileBook = File.ReadAllBytes(tempPathExcelFile);
MemoryStream stream = new MemoryStream();
string excelBase64String = Convert.ToBase64String(fileBook);
StreamWriter excelWriter = new StreamWriter(stream);
excelWriter.Write(excelBase64String);
excelWriter.Flush();
stream.Position = 0;
HttpResponseMessage httpResponseMessage = new HttpResponseMessage();
httpResponseMessage.Content = new StreamContent(stream);
httpResponseMessage.Content.Headers.Add("x-filename", "ExcelReport.xlsx");
httpResponseMessage.Content.Headers.ContentType = new MediaTypeHeaderValue("application/vnd.ms-excel");
httpResponseMessage.Content.Headers.ContentDisposition =
new ContentDispositionHeaderValue("attachment");
httpResponseMessage.Content.Headers.ContentDisposition.FileName = "ExcelReport.xlsx";
httpResponseMessage.StatusCode = HttpStatusCode.OK;
return httpResponseMessage;
}
catch (Exception ex)
{
_logger.ErrorException(errorMessage, ex);
return ReturnError(ErrorType.Error, errorMessage);
}
finally
{
if (File.Exists(tempPathExcelFile))
{
File.Delete(tempPathExcelFile);
}
}
//Javascript Code
$.ajax({
url: "/api/exportReport",
type: 'GET',
headers: {
Accept: "application/vnd.ms-excel; base64",
},
success: function (data) {
var uri = 'data:application/vnd.ms-excel;base64,' + data;
var link = document.createElement("a");
link.href = uri;
link.style = "visibility:hidden";
link.download = "ExcelReport.xlsx";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
},
error: function () {
console.log('error Occured while Downloading CSV file.');
},
});
In the end create an empty anchor tag at the end of your html file. <a></a>
For.NetCore you can simply Return type as File.
public IActionResult ExportAsExcel()
{
try
{
using (var ms = new MemoryStream())
{
var data = ExportData(); // Note: This Should be DataTable
data.ConvertAsStream(ms);
ms.Position = 0;
return File(ms.ToArray(), "application/octet-stream", "ExcelReport.xlsx");
}
}
catch (Exception e)
{
_logger.LogError(e.Message, e);
throw;
}
}
This will return a file when you click a particular button
public FileResult ExportXls(){
//the byte stream is the file you want to return
return File(bytes, "application/msexcel")
}