Как инициализировать загрузку файла с внешнего сервера? - PullRequest
5 голосов
/ 21 января 2012

У меня есть метод контроллера MVC, определенный следующим образом:

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

            return pdfDownload;
        }

Если я изменяю первый параметр на URL-адрес сервера, размещенного на отдельном облачном сервере, я получаю сообщение об ошибке:

'MY FILE PATH' не является действительным виртуальным путем.

Я просто хочу, чтобы мой клиент мог загрузить файл.Это кажется намного сложнее, чем нужно.

У меня есть URL, который указывает на PDF.Я хочу, чтобы мой клиент загрузил этот pdf, ничего не нажимая.(Загрузка начнется после успешного ответа службы)

Почему это так сложно и как мне решить эту проблему?

Мне все равно, будет ли решение в JS или MVC ....

Ответы [ 3 ]

8 голосов
/ 21 января 2012

Почему это так сложно и как мне это решить?

На самом деле, это не так сложно:

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");
    }
}

Теперь очевидно, что у этого метода есть серьезный недостаток, поскольку он буферизует файл в памяти. Хотя это может хорошо работать для небольших отчетов, это может быть проблематично для больших файлов и еще более проблематично, если у вас много пользователей, которым не терпится приложить руку к этому великолепному отчету.

Есть также еще один серьезный недостаток первого действия контроллера. Это смешивает обязанности. Он содержит код инфраструктуры, и я призываю вас выполнить его модульное тестирование в отдельности.

Итак, давайте решим эти 2 серьезные проблемы, написав результат пользовательского действия:

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);
        }
    }
}

, который вы будете использовать следующим образом:

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

и по вашему мнению:

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

Или вы можете полностью усомниться в полезности действия вашего контроллера, потому что, по вашему мнению, вместо:

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

вы можете иметь непосредственно:

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

при условии, что клиент, конечно, имеет доступ к этому серверу.

Примечание: будьте очень осторожны с именами файлов, которые вы отправляете в заголовке Content-Disposition. Я вижу в вашем вопросе, что вы использовали что-то вроде Server.UrlEncode("report1.pdf"). Проверьте следующий вопрос на кошмар, в который это может превратиться.

2 голосов
/ 21 января 2012

Вы можете просто перенаправить пользователя в удаленном отчете; если это не вариант, вам нужно прокси:

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

Выше предполагалось, что файл не очень большой; более надежная реализация будет получать и отправлять куски.

0 голосов
/ 06 декабря 2012

Я делаю похожую процедуру. Прямо сейчас у меня есть доступ к изображениям с локального диска

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

Как мне получить доступ к общему ресурсу на нашем SQL Server. У меня есть изображения в папках на SQL Server, которые я хочу получить.

byte [] cimage = new WebClient (). DownLoadData («Общий ресурс сервера» + /Files/koala.jpg");

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...