0

My Controller/Action receives some Ids from the view (via Post).

For each of the Ids a file will be fetched. I need to return some generated Excel or PDF files along the the list of IDs that did not fetch any results. Users can download any of the generated files.

I have all the logic in place to build the list of IDs that failed and the Excel and PDF reports, but am not sure how to return this back to the view. Appreciate any help with this.

The flow:

  1. Accept list of IDs from the view (done)
  2. Fetch results for these IDs (done)
  3. Build a list of IDs that did not fetch data (done), a report for the IDs that fetched data in Excel format (done) and a report for the IDs that fetched data in PDF format (done)
  4. Return the artifacts built in step 3 (need help with this)
Rahatur
  • 3,147
  • 3
  • 33
  • 49
Roopak
  • 73
  • 1
  • 7
  • Do you want to view report in report viewwer? – Sohail Shahzad Nov 23 '20 at 13:43
  • @SohailShahzad, I would need to present links for downloading the Excel and PDF files – Roopak Nov 23 '20 at 14:15
  • you can create list of objects and store value into model and return that model. Or you can also use viewbag to store ids of excel and word files and display the name of files in .cshtml view. when user click on file name it send id to server ,get data and download files. – Sohail Shahzad Nov 23 '20 at 14:48
  • @Roopak How are you sending the IDs from the view to the controller? Ajax request or Post? In any case you can send some hyperlinks instead of actual file. The files can be stored in a temporary folder on the server. And then when user user click any of the links the corresponding files would be downloaded. Without knowing what you have implemented so far it would be difficult to give a solution that you are looking for. – Rahatur Nov 23 '20 at 16:04
  • @Rahatur, I'm using post. The files I'm building are in memory. Given a choice, I'd prefer to keep it that way, as I'd otherwise need to run clean-up jobs to clear the saved files. Is there no way to return multiple files to views through models/viewmodels? – Roopak Nov 23 '20 at 20:39
  • @Roopak I have added an answer. Check if that solves the challenge. – Rahatur Nov 24 '20 at 15:03

1 Answers1

0

Post can be both Ajax and non-ajax. I am guessing you are not doing Ajax post.

Sending the files from the controller to the view is easier. However how do you plan to deliver the file based on users choice? View consists of Html, CSS and javascript. So you have to figure out a way to serve the binaray data that you are holding.

Since you are keeping the files in the memory then why don't you send the files as binary data to the view?

Here is a code example how you can send the files to the view:

Models:

public class MyModel
{
    Public List<MyFile> files { get; post; }
    
    Public int TotalFilesProcessed { get; post; }
    Public int TotalFilesFailed { get; post; }
}

public class MyFile
{
    Public string FileName { get; post; }
    Public string FileExtension { get; post; }
    Public byte[] FileContent { get; post; }
    Public double FileLength { get; post; }
    Public double ContentType { get; post; } 
}

Controller/Action:

MyModel model = new MyModel();
MyModel.files = new List<MyFile>();

MyFile file1 = new MyFile();
file1.FileExtension = "pdf"
file1.FileContent = null; //Assign file byte from the memory
file1.FileLength = file1.FileContent.Length;
file1.ContentType = "application/octet-stream";
MyModel.files.Add(file1);

MyFile file2 = new MyFile();
file2.FileExtension = "png"
file2.FileContent = null; //Assign file byte from the memory
file2.FileLength = file2.FileContent.Length;
file2.ContentType = "application/octet-stream";
MyModel.files.Add(file2);

MyModel.TotalFilesProcessed = 5;
MyModel.TotalFilesFailed = 2;

return View(model);

On the razor view you can write C# codes to get the data from the model. Loop through the List<MyFile> and render the file names as Html buttons or hyperlinks so that user can click one and download the file.

As per your question that is how you can have the files sent to the view. But the actual question should be how do you transmit the byte to the user when user clicks a button.

Following is a piece of code that will help you to put the bytes within the javascript code. Read the details of the code here:

var bytes = new Uint8Array(resultByte); // pass your byte response to this constructor

var blob=new Blob([bytes], {type: "application/pdf"});// change resultByte to bytes

var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="myFileName.pdf";
link.click();

The concept here is to transmit the byte from the html page so that the browser triggers a file download for the content. You will need to tweak the js as per your needs.

Note:

I think preparing the files in advance and holding in the memory is not a good idea.

Instead why don't you prepare a partial action which can be called from the page (javascript) with parameters. Then this partial action will prepare a file based on your input and send the byte/status to the view.

Based on status you can decide if the file can be allowed to download or a status message will be displayed instead.

Here is a recomended flow:

  • Have a partial action which takes one Id and process the file for that. If no data is found then send a 404 json result.
  • For all the Ids call the partial action in a loop and gather all the response in your jabascript
  • Once you have all the results (or even as each of the ajax response comes in) you can add a button/hyperlink for that in the UI.
  • Display a loader on the UI so that user know files are being processed. You can choose to block the UI till all the files are processed on allow the user to download as soon as a file becomes available

Doing the above will not need any cleanup job or hold larger number of files in the memory.

Rahatur
  • 3,147
  • 3
  • 33
  • 49