У меня есть набор файлов pdf, хранящихся в месте, доступном только для приложения, поэтому к этим файлам нельзя получить доступ напрямую через http.

Пути к файлам хранятся в базе данных, и когда пользователю предоставляется возможность загрузить файл, выполняется следующий код:

 Response.ContentType = "Application/pdf"
 Response.AppendHeader("Content-Disposition", "attachment; filename=<some file name>")
 Response.TransmitFile(Server.MapPath("<the file path>"))
 Response.End()

Все работает нормально, если я имею дело с одним файлом

Проблема:

У меня есть хранимая процедура, которая возвращает список всех файлов, доступных пользователю для загрузки, и может возвращать любое количество файлов от 1 до 20.

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

Что-то типа

File name 1, some description 1, download (button, link?)
File name 2, some description 2, download (button, link?)

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

Какое элегантное решение для достижения этой цели с использованием .net2.0?

2
kristof 10 Фев 2009 в 16:44

2 ответа

Лучший ответ

В обычном ASP.NET (2.0) вам нужно создать «обработчик». Самый простой вариант - добавить шаблон «общий обработчик» (ashx), а затем разместить на странице обычную ссылку (например) на «download.ashx? Id = 2».

Внутри обработчика проанализируйте строку запроса и передайте файл пользователю:

    public void ProcessRequest(HttpContext context)
    {
        // set headers...
        string filePath = FindPath(context.Request.QueryString("id"));
        context.Response.WriteFile(filePath);
    }

Где FindPath разрешает физический файл из ссылки строки запроса.

Если бы это был ASP.NET MVC, вы могли бы просто использовать результат действия File(path).

8
Marc Gravell 10 Фев 2009 в 16:54
+1 - Очень хороший ответ. Очень немногие люди знают, как использовать файлы ASHX, несмотря на их полезность.
 – 
Mark Brittingham
10 Фев 2009 в 16:58
+1. Спасибо, Марк, это указывает мне правильное направление. Я полагаю, что результат функции FindPath должен быть специфичным для пользователя / сеанса, чтобы гарантировать, что кто-то не вызовет страницу напрямую с идентификатором, для которого у него нет разрешений.
 – 
kristof
10 Фев 2009 в 17:09
Лично я бы установил идентификаторы и просто проверил разрешения внутри метода (возможно, используя идентификаторы базы данных). Таким образом, ссылки работают между сеансами / браузерами, пока у вас есть доступ.
 – 
Marc Gravell
10 Фев 2009 в 17:37
Это было более или менее то, что я имел в виду, говоря о сеансе / пользователе. Я считал, что список путей к файлам - это сеанс, а идентификатор будет идентификатором в списке, или, в качестве альтернативы, получить его из базы данных с использованием переданного идентификатора, но тогда мне нужно также проверить, есть ли у пользователя разрешения для файла
 – 
kristof
10 Фев 2009 в 18:43
Чтобы проверить, что мне также нужно будет передать userId, я считаю, что в сеансе в противном случае вы можете напрямую вызвать Download.ashx? Id = 2? User = 5. Я понимаю, что для использования данных сеанса обработчику необходимо реализовать System.Web.SessionState.IRequiresSessionState.
 – 
kristof
10 Фев 2009 в 18:48

URL-адреса в списке файлов, которые вы возвращаете пользователю, могут указывать на страницу ASPX, с которой они могут быть загружены, как и в приведенном вами примере кода.

0
Assaf Lavie 10 Фев 2009 в 16:48