Web Api Return File with additional data - c#

I'm returning a file as follows:
public async Task<IActionResult> GetFile(string id)
{
try
{
GetFileDataResponse retrieveResponse = new GetFileDataResponse();
retrieveResponse = GetFileData(Int32.Parse(id));
var folderName = Path.Combine("Resources", "Images");
var pathToSave = Path.Combine(Directory.GetCurrentDirectory(), folderName);
pathToSave = Path.Combine(pathToSave, retrieveResponse.FileUrl);
var fileName = Path.GetFileName(pathToSave);
var content = await System.IO.File.ReadAllBytesAsync(pathToSave);
new FileExtensionContentTypeProvider()
.TryGetContentType(fileName, out string contentType);
return File(content, contentType, fileName);
}
catch(Exception ex)
{
response.Success = false;
response.Message = ex.ToString();
return BadRequest() ;
}
}
Is there a way to send some data additional besides the file?
I want to send some data like "uploadedBy:1", but I don't know if this is possible, I read about some parameter in the content disposition but I'm not sure how to implement it.
Thanks in advance.

Related

ASP.NET Core Web API - Error CS1955 Non-invocable member 'File' cannot be used like a method

In my ASP.NET Core-6 Web API, I want to download file based on parameter id.
So, I have this repository that will eventually be called in the controller:
Repository:
public async Task<string> GetLeaveDocumentByIdAsync(Guid id)
{
var leaveAttachment = _dbContext.LeaveApplications
.Include(la => la.LeaveApproval)
.ThenInclude(la => la.LeaveApprovalAttachments)
.Where(la => (bool)la.IsApproved)
.SelectMany(la => la.LeaveApproval.LeaveApprovalAttachments)
.FirstOrDefault(laa => laa.Id == id);
var filePath = Path.Combine(Directory.GetCurrentDirectory(), leaveAttachment.FilePath);
var memory = new MemoryStream();
using (var stream = new FileStream(filePath, FileMode.Open))
{
await stream.CopyToAsync(memory);
}
memory.Position = 0;
var contentType = "APPLICATION/octet-stream";
var fileName = Path.GetFileName(filePath);
return File(memory, contentType, fileName);
}
Service:
public async Task<Response<string>> GetLeaveDocumentServiceByIdAsync(Guid id)
{
var response = new Response<string>();
var leave = await _unitOfWork.Leaves.GetLeaveDocumentByIdAsync(id);
if (leave != null)
{
response.Message = "File Downloaded Successfully";
response.StatusCode = (int)HttpStatusCode.OK;
response.Successful = true;
}
else
{
response.StatusCode = (int)HttpStatusCode.BadRequest;
response.Successful = false;
response.Message = $"File Download Failed. Please try again";
return response;
}
return response;
}
Controller:
public async Task<ActionResult<Response<string>>> DownloadLeaveDocumentAsync(Guid id)
{
var result = await _leaveApprovalsService.GetLeaveDocumentServiceByIdAsync(id);
return StatusCode(result.StatusCode, result);
}
This is the flow:
Repository -> Service -> Controller
I want to download the selected file by id, but I got this error in the Repository:
Error CS1955 Non-invocable member 'File' cannot be used like a method.
File is highlighted in
return File(memory, contentType, fileName)
How do I resolve this?
Thanks

How to give a file name to uploadFile EF C#

I am uploading a file and wish to name it with one of the input fields which I wille be typing in my view. For ex: I type "Test" in my "Designation Commerciale" field. However, it gives me the NullReferenceException as it does not find any. Would appreciate your help. Thanks.
Controller:
public async Task<string> UploadFile(IFormFile file)
{
//bool iscopied;
string resp = String.Empty;
try
{
if (file.Length > 0)
{
var model = new IdentificationProduitViewModel();
string x = model.DesignationCommerciale;
string filename = x + Path.GetExtension(file.FileName);
string path = Path.GetFullPath(Path.Combine(Directory.GetCurrentDirectory(), "UploadFds"));
using (var filestream = new FileStream(Path.Combine(path, filename), FileMode.Create))
{
await file.CopyToAsync(filestream);
}
//iscopied = true;
resp = filename;
}
else
{
// iscopied = false;
resp = String.Empty;
}
}
catch(Exception)
{
throw;
}
return resp;
}
HTTPPOST:
string tryupload = await UploadFile(file_fds);
if (!String.IsNullOrEmpty(tryupload))
{
TempData["uploadok"] = "Fichier chargé avec success !";
model.Fds_Filepath = tryupload;
}

ActionResult not returning a PDF file

so I'm in process of migrating of my app from .NET Framework 4.8 to .NET6. Due to some .NET classes being obsolete in newer version I am experiencing some problems.
I have a controller in which one of endpoints is supposed to return a PDF file. But instead of this what it returns right now is just a JSON file containing only a few values.
Endpoint method:
[HttpPost]
public ActionResult DownloadFile([FromForm] string data, [FromForm] string fileType)
{
try
{
if (!string.IsNullOrWhiteSpace(data))
{
return GenerateReportDocument(data, fileType);
}
}
catch (Exception ex)
{
logger.LogError(ex, $"Unexpected error occured in {nameof(DownloadFile)}.");
return StatusCode(500);
}
return NoContent();
}
Then data is taken into GenerateReportDocument method:
private ActionResult GenerateReportDocument(string data, string fileType)
{
var specificationString = specificationGeneratorService.GenerateSpecificationString(JObject.Parse(data));
logger.LogWarning($"Check images in specificationString: '{specificationString}'");
if (string.IsNullOrWhiteSpace(specificationString))
{
specificationString = "<p></p>";
}
var reportGenerator = generateReportDocuments.SingleOrDefault(r => r.FileType.ToLower().Equals(fileType.ToLower()));
if (reportGenerator is not null)
{
return Ok(reportGenerator.GenerateReportDocument(SpecificationFileName, specificationString));
}
return NoContent();
}
Which then is supposed to be taken into third method:
public HttpContent GenerateReportDocument(string fileName, string specificationString)
{
var requestContent = new StringContent(JsonConvert.SerializeObject(new { Html = specificationString }));
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var httpResponse = Flurl.Url.Combine(_abcPdfOptions.PdfConverterUrl, "pdf/convertfromhtmltopdf")
.PostAsync(requestContent).GetAwaiter().GetResult();
HttpContent httpContent = httpResponse.Content;
httpContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"{fileName}.{FileExt}",
};
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return httpContent;
}
This is how those methods looked like in .NET Framework 4.8 (when they were working correctly, presented in same order as their equivalent methods in .NET6 project):
[HttpPost]
public HttpResponseMessage DownloadFile(HttpRequestMessage requestMessage)
{
try
{
var specification = requestMessage.Content.ReadAsFormDataAsync().Result;
string data = specification.Get("Data");
string fileType = specification.Get("FileType");
if (!string.IsNullOrWhiteSpace(data))
{
return GenerateReportDocument(data, fileType);
}
}
catch (Exception ex)
{
logger.LogError(ex, $"Unexpected error occured in {nameof(DownloadFile)}.");
return new HttpResponseMessage(HttpStatusCode.InternalServerError);
}
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
private HttpResponseMessage GenerateReportDocument(string data, string fileType)
{
var specificationString = specificationGeneratorService.GenerateSpecificationString(JObject.Parse(data));
logger.LogWarning($"Check images in specificationString: '{specificationString}'");
if (string.IsNullOrWhiteSpace(specificationString))
{
specificationString = "<p></p>";
}
var reportGenerator = generateReportDocuments.SingleOrDefault(r => r.FileType.ToLower().Equals(fileType.ToLower()));
if (reportGenerator != null)
{
return new HttpResponseMessage(HttpStatusCode.OK)
{
Content = reportGenerator.GenerateReportDocument(SpecificationFileName, specificationString),
};
}
return new HttpResponseMessage(HttpStatusCode.NoContent);
}
public HttpContent GenerateReportDocument(string fileName, string specificationString)
{
var requestContent = new StringContent(JsonConvert.SerializeObject(new { Html = specificationString }));
requestContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var httpResponse = Flurl.Url.Combine(_abcPdfOptions.PdfConverterUrl, "pdf/convertfromhtmltopdf")
.PostAsync(requestContent).GetAwaiter().GetResult();
HttpContent httpContent = httpResponse.Content;
httpContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = $"{fileName}.{FileExt}",
};
httpContent.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
return httpContent;
}
I have tried editing my code and changing the methods into IActionResult or HttpResponse, also altering the return types and their arguments. What am I doing wrong? Is ActionResult a good choice for what I'm trying to do?
Did you try returning FileStreamResult/File ?
var fileStream = new FileStream(#"file_path", FileMode.Open);
return new FileStreamResult(fileStream, "application/pdf");
Or
var fileStream = new FileStream(#"file_path", FileMode.Open);
return File(fileStream , "application/pdf", "FileDownloadName.ext");
if you are doing an ajax call to the controller, then no file will be downloaded, you will receive some json data.you need to make a non ajax call so that server will download the file

How can I download file in my folder c# ASP.NET Web API?

I need a download file in my C:\fileName.
I am send to fileName this class but it does not working ? Where is my error?
This is my code:
// POST: api/Calendar/DownloadFile
[HttpPost]
public HttpResponseMessage DownloadFile(DownloadInput fileName)
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
var filePath = HttpContext.Current.Server.MapPath(#"C:\" + fileName);
var fileBytes = File.ReadAllBytes(filePath);
var 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;
}
This is my error:
ExceptionType: "System.NotImplementedException"
Message: "An error has occurred."
The below is for MVC:
public ActionResult DownloadFile(string fileWithFullPath)
{
var fileBytes = System.IO.File.ReadAllBytes(fileWithFullPath);
return File(fileBytes, MediaTypeNames.Application.Octet, fileName);
}
The below is for API:
public ActionResult DownloadFile()
{
var result = new HttpResponseMessage(HttpStatusCode.OK);
var stream = new FileStream(fullyQualifiedFileName, FileMode.Open);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
result.Content.Headers.ContentLength = stream.Length;
string input = $"filename=test.pdf";
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse(input, out contentDisposition))
{
result.Content.Headers.ContentDisposition = contentDisposition;
}
return this.ResponseMessage(result);
}
Based on what you are showing here, the parameter DosyaAdi is a string and it is not clear what DownloadInput is. I would suggest changing the input parameter to a string and also changing the Method to HttpGet. The second suggestion is for convention and probably not the issue.
// GET: api/Calendar/DownloadFile
[HttpGet]
public HttpResponseMessage DownloadFile(string DosyaAdi)...
good luck

How to pass the File Data from C# Console application to WebApi?

I am trying to call the Web api method for saving the File Data.When I debug Webapi method I found that ContentLength is not coming as correct, because of this when i am retrieving the file it is showing error as corrupted file.
My Class method is :-
using (var formData = new MultipartFormDataContent())
{
HttpContent stringContent = new StringContent(file);
formData.Add(stringContent, "file", file);
formData.Add(new StringContent(JsonConvert.SerializeObject(file.Length)), "ContentLength ");
HttpResponseMessage responseFile = client.PostAsync("Report/SaveFile?docId=" + docId, formData).Result;
}
My Web api method is :-
[HttpPost]
public HttpResponseMessage SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var httpRequest = HttpContext.Current.Request;
bool IsSuccess = true;
if (httpRequest.Files.Count > 0)
{
var docfiles = new List<string>();
foreach (string file in httpRequest.Files)
{
HttpPostedFile postedFile = httpRequest.Files[file];
// Initialize the stream.
Stream myStream = postedFile.InputStream;
myStream.Position = 0;
myStream.Seek(0, SeekOrigin.Begin);
var _item = CorrectedReportLibrary.Services.ReportService.SaveFile(myStream,docId);
response = Request.CreateResponse<bool>((IsSuccess)
? HttpStatusCode.OK
: HttpStatusCode.NoContent,
IsSuccess);
}
}
}
catch (Exception ex)
{
Theranos.Common.Library.Util.LogManager.AddLog(ex, "Error in CorrectedReportAPI.Controllers.SaveDocument()", null);
return Request.CreateResponse<ReportDocumentResult>(HttpStatusCode.InternalServerError, null);
}
return response;
}
How can I set the ContentLength from C# class method?
It looks a bit strange that you use ContentLength as the second parameter on the StringContent class. It is suppose to be which encoding you want to use, for example
new StringContent(content, Encoding.UTF8). I don't think it is the content length that is the issue here.
StringContent class
I guess since it is a file you want to upload, you already have the file read as a stream, so I usually do something like this:
Client:
private async Task UploadFile(MemoryStream file)
{
var client = new HttpClient();
var content = new MultipartFormDataContent();
content.Add(new StreamContent(file));
var result = await client.PostAsync("Report/SaveFile?docId=" + docId, content);
}
Edit. Since it's a multipartform it's easier to let the framework handle the details. Try something like this:
Server:
[HttpPost]
public async Task<HttpResponseMessage> SaveFile(long docId)
{
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.Unauthorized);
try
{
var filedata = await Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider());
foreach(var file in filedata.Contents)
{
var fileStream = await file.ReadAsStreamAsync();
}
response = Request.CreateResponse<bool>(HttpStatusCode.OK, true);
}
catch (Exception ex)
{
response = Request.CreateResponse<bool>(HttpStatusCode.InternalServerError, false);
}
return response;
}
At Last I found the solution no need to change the web api service,
issue was from client where I was directly passing the file data, Now the modified
working code is like this:-
using (var formData = new MultipartFormDataContent())
{
var bytes = File.ReadAllBytes(file);
formData.Add(new StreamContent(new MemoryStream(bytes)), "file", file);
HttpResponseMessage responseFile = client.PostAsync("ReportInfo/SaveFile?docId=" + docId, formData).Result;
}

Categories

Resources