How to initialize downloading files from an external server?

I have an MVC controller method defined as follows:

public ActionResult GetPdf(string filename) { var pdfDownload = File("~/Content/GeneratedReports/report1.pdf", "application/pdf", Server.UrlEncode("report1.pdf")); return pdfDownload; } 

If I change the first parameter to the URL of a server hosted on a separate cloud server, then I get an error:

"MY FILE PATH" is not a valid virtual path.

I just want my client to be able to upload the file. This seems a lot more complicated than necessary.

I have a url that points to a pdf file. I want my client to download this pdf file without clicking anything. (Download will be initiated after a successful service response)

Why is it so complicated and how do I solve it?

I don't care if the solution is in JS or MVC ....

+4
source share
3 answers

Why is it so complicated and how do I solve it?

Actually, this is not so difficult:

 public ActionResult GetPdf(string filename) { using (var client = new WebClient()) { var buffer = client.DownloadData("http://foo.com/bar.pdf"); return File(buffer, "application/pdf", "report1.pdf"); } } 

Now, obviously, there is a serious flaw in this method, since it loads the file into memory. Although this may work fine for small reports, it can be problematic with large files and even more problematic if you have many users eager to put their hand in this excellent report.

There is also another serious flaw with the first controller action. He mixes duties. It contains infrastructure code, and I suggest you unit test isolate it.

So, let me solve these two serious problems by writing the result of a custom action:

 public class ReportResult : ActionResult { private readonly string _filename; public ReportResult(string filename) { _filename = filename; } public override void ExecuteResult(ControllerContext context) { var cd = new ContentDisposition { FileName = _filename, Inline = false }; var response = context.HttpContext.Response; response.ContentType = "application/pdf"; response.Headers["Content-Disposition"] = cd.ToString(); using (var client = new WebClient()) using (var stream = client.OpenRead("http://foo.com/" + _filename)) { // in .NET 4.0 implementation this will process in chunks // of 4KB stream.CopyTo(response.OutputStream); } } } 

what you will use like this:

 public ActionResult GetPdf(string filename) { return new ReportResult(filename); } 

and in your opinion:

 @Html.ActionLink("Download report", "GetPdf", new { filename = "report.pdf" }) 

Or you can completely ask about the usefulness of the actions of your controller, because in your view, instead of:

 @Html.ActionLink("Download report", "GetPdf") 

you could directly:

 <a href="http://foo.com/bar.pdf">Download report</a> 

assuming the client has access to this server, of course.

Note: be very careful with the file names that you send in the Content-Disposition header. I see in your question that you used something like Server.UrlEncode("report1.pdf") . Draw up the following question for a nightmare that might turn into.

+7
source

You can simply redirect the user to a remote report; if this is not an option, you need to proxy it:

 byte[] blob; using(var client = new WebClient()) { blob = client.DownloadData(remoteUrl); } return File(blob, "application/pdf", "report1.pdf"); 

it was assumed above that the file is not very large; a more robust implementation will retrieve and send pieces.

+2
source

I am doing a similar procedure. Right now I have access to images from a local drive.

byte [] cimage = new WebClient (). DownLoadData (System.Web.HttpContent.Server.MapPath ("~ / Content / koala.jpg"));

How to access a resource on our SQL Server. I have images in folders on SQL Server that I want to retrieve.

byte [] cimage = new WebClient (). DownLoadData ("Server Share" + / Files / koala.jpg);

0
source

Source: https://habr.com/ru/post/1392144/


All Articles