I have an API that offers a file translation service. I have been able to generate a new the new translated file but I have not been able to get it to the client correctly, because the document downloaded it is not readable.
This is my controller code:
[HttpPost]
[Route("TranslateDocument/{inputLanguage}/{outputLanguage}")]
[ProducesResponseType(typeof(FileContentResult), StatusCodes.Status200OK)]
public async Task<ActionResult<FileInfo>> TranslateDocument(string inputLanguage, string outputLanguage, [FromForm] IFormFile file)
{
try
{
FileContentResult result = await _deeplService.TranslateFile(inputLanguage, outputLanguage, file);
return Ok(result);
}
catch (Exception ex)
{
return ManageExceptions(ex);
}
}
In my service I have the following function:
public async Task<FileContentResult> TranslateFile(string inputLang, string outputLang, IFormFile file){
//Code to translate the file into outputLang
...
//Get bytes from Document generated
byte[] bytes = System.IO.File.ReadAllBytes("localpath from doc");
//Send the File to Download.
return new FileContentResult(bytes, "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
}
And this is the response I am getting on the client site:
{
"fileContents": "UEsDBBQAAA...AAyCUAAAAA",
"contentType": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
"fileDownloadName": "",
"lastModified": null,
"entityTag": null,
"enableRangeProcessing": false
}
And when I do the const url = window.URL.createObjectURL(new Blob([response.fileContents], {type: "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}));, the file downloaded is not readable in word
Related
I am trying to create an app where user can upload a text file, and gets the altered text back.
I am using React as FE and ASP.NET Core for BE and Azure storage for the database storage.
This is how my HomeController looks like.
I created a separate "UploadToBlob" method, to post the data
public class HomeController : Controller
{
private readonly IConfiguration _configuration;
public HomeController(IConfiguration Configuration)
{
_configuration = Configuration;
}
public IActionResult Index()
{
return View();
}
[HttpPost("UploadFiles")]
//OPTION B: Uncomment to set a specified upload file limit
[RequestSizeLimit(40000000)]
public async Task<IActionResult> Post(List<IFormFile> files)
{
var uploadSuccess = false;
string uploadedUri = null;
foreach (var formFile in files)
{
if (formFile.Length <= 0)
{
continue;
}
// read directly from stream for blob upload
using (var stream = formFile.OpenReadStream())
{
// Open the file and upload its data
(uploadSuccess, uploadedUri) = await UploadToBlob(formFile.FileName, null, stream);
}
}
if (uploadSuccess)
{
//return the data to the view, which is react display text component.
return View("DisplayText");
}
else
{
//create an error component to show there was some error while uploading
return View("UploadError");
}
}
private async Task<(bool uploadSuccess, string uploadedUri)> UploadToBlob(string fileName, object p, Stream stream)
{
if (stream is null)
{
try
{
string connectionString = Environment.GetEnvironmentVariable("AZURE_STORAGE_CONNECTION_STRING");
// Create a BlobServiceClient object which will be used to create a container client
BlobServiceClient blobServiceClient = new BlobServiceClient(connectionString);
//Create a unique name for the container
string containerName = "textdata" + Guid.NewGuid().ToString();
// Create the container and return a container client object
BlobContainerClient containerClient = await blobServiceClient.CreateBlobContainerAsync(containerName);
string localPath = "./data/";
string textFileName = "textdata" + Guid.NewGuid().ToString() + ".txt";
string localFilePath = Path.Combine(localPath, textFileName);
// Get a reference to a blob
BlobClient blobClient = containerClient.GetBlobClient(textFileName);
Console.WriteLine("Uploading to Blob storage as blob:\n\t {0}\n", blobClient.Uri);
FileStream uploadFileStream = File.OpenRead(localFilePath);
await blobClient.UploadAsync(uploadFileStream, true);
uploadFileStream.Close();
}
catch (StorageException)
{
return (false, null);
}
finally
{
// Clean up resources, e.g. blob container
//if (blobClient != null)
//{
// await blobClient.DeleteIfExistsAsync();
//}
}
}
else
{
return (false, null);
}
}
}
but the console throws errors, saying "'ControllerBase.File(byte[], string)' is a method, which is not valid in the given context (CS0119)"
And because of this error, another error follows "'HomeController.UploadToBlob(string, object, Stream)': not all code paths return a value (CS0161)"
my questions are
Is it a better idea to create a separate method like I did?
how can I resolve the issue regarding the "File" being valid inside of the UploadToBlob method?
If I want to add the file type validation, where should it happen? t.ex. only text file is alid
If I want to read the text string from the uploaded text file, where should I call the
string contents = blob.DownloadTextAsync().Result;
return contents;
How can I pass down the "contents" to my react component? something like this?
useEffect(() => {
fetch('Home')
.then(response => response.json())
.then(data => {
setForcasts(data)
})
}, [])
Thanks for helping this super newbie with ASP.NET Core!
1) It is ok to put uploading into separate method, it could also be put into a separate class for handling blob operations
2) File is the name of one of the controllers methods, if you want to reference the File class from System.IO namespace, you need to fully qualify the name
FileStream uploadFileStream = System.IO.File.OpenRead(localFilePath);
To the other compile error, you need to return something from the UploadToBlob method, now it does not return anything from the try block
3) File type validation can be put into the controller action method
4) it depends on what you plan to do with the text and how are you going to use it. Would it be a new action of the controller (a new API endpoint)?
5) you could create a new API endpoint for downloading files
UPDATE:
For word replacement you could use a similar method:
private Stream FindMostFrequentWordAndReplaceIt(Stream inputStream)
{
using (var sr = new StreamReader(inputStream, Encoding.UTF8)) // what is the encoding of the text?
{
var allText = sr.ReadToEnd(); // read all text into memory
// TODO: Find most frequent word in allText
// replace the word allText.Replace(oldValue, newValue, stringComparison)
var resultText = allText.Replace(...);
var result = new MemoryStream();
using (var sw = new StreamWriter(result))
{
sw.Write(resultText);
}
result.Position = 0;
return result;
}
}
it would be used in your Post method this way:
using (var stream = formFile.OpenReadStream())
{
var streamWithReplacement = FindMostFrequentWordAndReplaceIt(stream);
// Upload the replaced text:
(uploadSuccess, uploadedUri) = await UploadToBlob(formFile.FileName, null, streamWithReplacement);
}
You probably have this method inside MVC controller in which File method exists. Add in your code System.IO.File instead of File
I have requirement to upload xlsx file on server along with some json data(both has to be done in one request). I was able to upload just file using multipart/form-data, but when I tried add JSON data to the same request, request is failing with org.apache.commons.fileupload.FileUploadBase$InvalidContentTypeException: the request doesn't contain a multipart/form-data or multipart/mixed stream
exception. Below is my code.
Client side code
var method = 'POST';
$.ajax({
type: method,
url : "rest/file/upload",
transformRequest: function () {
var formData = new FormData();
formData.append("model", JSON.stringify(jsonData));
formData.append("file",document.getElementById("fileForm"));
return formData;
},
enctype : 'multipart/form-data',
processData : false,
contentType : false,
success: function (data) {},
error: function (data) {}
});
model is the JSON data & file is xlsx file which is to be uploaded.
Server Side Code
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
#Produces(MediaType.TEXT_PLAIN)
public Response uploadResumableISOFile(#Context HttpServletRequest request, #Context UriInfo uri,
#Context HttpHeaders headers, #Context HttpServletResponse response) throws IOException {
ServletFileUpload uploader = null;
try {
DiskFileItemFactory fileFactory = new DiskFileItemFactory();
uploader = new ServletFileUpload(fileFactory);
List<FileItem> fileItemsList = uploader.parseRequest(request);
Iterator<FileItem> fileItemsIterator = fileItemsList.iterator();
while (fileItemsIterator.hasNext()) {
FileItem fileItem = fileItemsIterator.next();
File file = File.createTempFile("TEMP_", ".xlsx");
fileItem.write(file);
System.out.print("File " + fileItem.getName() + " uploaded successfully.");
}
System.out.println("File uploaded to successfully...");
return Response.status(Response.Status.OK).build();
} catch (Exception e) {
System.out.println(e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Failed to upload file.").build();
}
}
Please let me know if something is missing.
This is my write to excel method which returns javax.ws.rs.core.Response
public Response writeToExcel(UserDeatilsVOWrapper listBook) {
XSSFWorkbook workbook = new XSSFWorkbook();
XSSFSheet spreadsheet = workbook.createSheet("Resource Information");
int rowCount = 0;
createHeaderRow(spreadsheet);
for (UserDetailsVO detailsVO : listBook.getUserDetailsList()) {
Row row = spreadsheet.createRow(++rowCount);
writeBook(detailsVO, row);
}
Response response = null;
try (FileOutputStream outputStream = new FileOutputStream(new File("ResourceInformation.xlsx"))) {
workbook.write(outputStream);
// header required to enable download pop-up and set file name
Response.ok().header("Content-Disposition", "attachment; filename=" + "ResourceInformation.xlsx").build();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return response;
}
This is my web service:
#POST
#Path(WebServiceConstants.DOWNLOAD_EXCEL)
#Consumes(MediaType.APPLICATION_JSON)
public Response getFile(UserDeatilsVOWrapper wrapper) {
Response respose=new ExportToExcel().writeToExcel(wrapper);
return respose;}
I get a HTTP204 error. I'm using postman. I know, I'm doing a big mistake in write to excel method and when trying to send file along with response.
Also is there any possible way to write a file object on REST response without saving file on server? I'm doing terrible in here. any help is appreciated.
I do not see where you set your file to the response. Normally you would do something like this
File file = new File("ResourceInformation.xlsx"))
// Do your excel-writing here...
ResponseBuilder response = Response.ok((Object) file);
response.header("Content-Disposition", "attachment; filename=" + "ResourceInformation.xlsx");
return response.build();
I am making a rest API call using Angular. My Rest API look like as below:
#RequestMapping(value = "/getPDF/{projectId}", method = RequestMethod.POST)
public ResponseEntity<byte[]> generateReport(#PathVariable("projectId") long projectId, #RequestBody Object vo, final HttpServletRequest request) {
vo.setProjectId(projectId);
byte[] pdf = blueprintService.generateBluePrint(vo);
LOG.debug(new StringBuilder("Generating Blueprint for VO: ").append(vo).toString());
String fileName = null;
try {
ProjectDetailsVO pdvo = projectSetupService.getProjectDetails(vo.getProjectId());
fileName = new StringBuilder(pdvo.getClientName()).append("_")
.append(pdvo.getProjectName()).append("_")
.append(System.currentTimeMillis()).append(".pdf")
.toString();
} catch (Exception e) {
}
if (fileName == null || fileName.trim().isEmpty())
fileName = new StringBuilder("Project_")
.append(vo.getProjectId()).append("_")
.append(System.currentTimeMillis())
.append(".pdf").toString();
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Type", "application/pdf");
String userAgent = request.getHeader("User-Agent");
if (userAgent != null && !(userAgent.contains("Firefox") && userAgent.contains("Mac"))) {
LOG.debug("Inline BP Content");
headers.add("Content-Disposition", new StringBuilder("inline; filename=\"").append(fileName).append("\"").toString());
} else {
LOG.debug("Attached BP Content");
headers.add("Content-Disposition", new StringBuilder("attachment; filename=\"").append(fileName).append("\"").toString());
}
if (pdf != null)
headers.setContentLength(pdf.length);
return new ResponseEntity<byte[]>(pdf, headers, HttpStatus.OK);
}
}
So server is setting file name for the PDF which I want to be the name of the generated PDF.
I tried below angular code:
success: function (data, status, headers, config) {
$modalInstance.close();
var file = new Blob([data], {type: 'application/pdf'});
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
}
It works fine but it open the pdf of it's own name. Which I think, since Angular is converting the response into PDF. Hence Headers are getting excluded.
Is there any way to make a post request so it will open a PDF in new browser tab some code like as below:
$http.post{
url: myRestURL,
data: postbodyData,
taget: _blank
}
which will open my rest URL in new tab and show the PDF in browser.
Thank you.
I'm trying to give user ability to download a file which is created after database backup.
this is my controller where I try to generate link for that file and than in Javascript I just make tag with the generated link. after clicking the link chrome says "not allowed to load content from local resource: file:///...". can anyone tell me how to allow to load this resource? I'd prefer not to change the directory which is now /tmp
#RequestMapping(value = "/backup-entire-database", method = RequestMethod.POST)
#ResponseBody
public Responce backupEntireDatabase(#RequestBody Map<String, String> databasePasswordMap) throws MalformedURLException {
String databaseUserPassword = databasePasswordMap.get("password");
ShellScript databaseBackupScript = new ShellScript();
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy*MM*dd_HH*mm*ss");
Date now = new Date();
String currentTime = sdfDate.format(now);
try {
databaseBackupScript.exec("database-backup", databaseUserPassword , "databaseBackup_"+currentTime, "", "");
} catch (IOException ex) {
java.util.logging.Logger.getLogger(DatabaseBackupController.class.getName()).log(Level.SEVERE, null, ex);
return new Responce(0, ex.getMessage());
} catch (ShellScriptExecutionExeption ex) {
java.util.logging.Logger.getLogger(DatabaseBackupController.class.getName()).log(Level.SEVERE, null, ex);
return new Responce(0, ex.getMessage());
}
File backupFile=new File("/tmp/PATH_TO_FILE/databaseBackup_"+currentTime);
return new Responce(0, backupFile.toURI().toURL().toString());
}