Потоковый файл SharePoint для предварительного просмотра - PullRequest
2 голосов
/ 09 сентября 2008

Я хочу передать файл, размещенный в библиотеке документов SharePoint 2003, в браузер. По сути, идея состоит в том, чтобы открыть файл как поток и затем «записать» поток файлов в ответ, указав тип контента и заголовки расположения контента. Расположение содержимого используется, чтобы сохранить имя файла, тип содержимого, конечно, чтобы подсказывать браузеру, какое приложение открыть для просмотра файла.

Это хорошо работает в среде разработки и среде UAT. Однако в производственной среде все не всегда работает должным образом, однако только с IE6 / IE7. FF отлично работает во всех средах.

Обратите внимание, что в производственной среде SSL включен и обычно используется. (Когда SSL не используется в производственной среде, потоки файлов именуются, как и ожидалось, и отображаются правильно.)

Вот фрагмент кода:

System.IO.FileStream fs = new System.IO.FileStream(Server.MapPath(".") + "\\" + "test.doc", System.IO.FileMode.Open);
long byteNum = fs.Length;
byte[] pdfBytes = new byte[byteNum];
fs.Read(pdfBytes, 0, (int)byteNum);

Response.AppendHeader("Content-disposition", "filename=Testme.doc");
Response.CacheControl = "no-cache";
Response.ContentType = "application/msword; charset=utf-8";
Response.Expires = -1;
Response.OutputStream.Write(pdfBytes, 0, pdfBytes.Length);
Response.Flush();
Response.Close();
fs.Close();

Как я уже сказал, этот фрагмент кода отлично работает на компьютере разработчика и в среде UAT. Откроется диалоговое окно с просьбой сохранить, просмотреть или отменить Testme.doc. Но в производстве только при использовании SSL IE 6 и IE7 не используют имя вложения. Вместо этого он использует имя страницы, которая отправляет поток, testheader.apx, а затем выдается ошибка.

IE предоставляет расширенную настройку «Не сохранять зашифрованные страницы на диск».

Я подозреваю, что это является частью проблемы, сервер сообщает браузеру не кэшировать файл, в то время как в IE включена функция "Не сохранять зашифрованные страницы на диск".

Да. Я знаю, что для больших файлов приведенный выше фрагмент кода будет серьезным затягиванием памяти, и это будет проблематично. Таким образом, настоящее окончательное решение не откроет весь файл в одном байтовом массиве, а откроет файл в виде потока, а затем отправит файл клиенту кусками размера кусочка (например, размером примерно 10 КБ).

У кого-нибудь еще есть подобный опыт потоковой передачи двоичных файлов через ssl? Есть предложения или рекомендации?

Ответы [ 2 ]

4 голосов
/ 10 сентября 2008

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


Response.AddHeader("Content-Disposition", "attachment;filename=myfile.doc");

не удалось, что я включил свой код ниже, поскольку я знаю, что работает над https://


private void ReadFile(string URL)
{
  try
  {
                string uristring = URL;
                WebRequest myReq = WebRequest.Create(uristring);
                NetworkCredential netCredential = new NetworkCredential(ConfigurationManager.AppSettings["Username"].ToString(), 
                                                                        ConfigurationManager.AppSettings["Password"].ToString(), 
                                                                        ConfigurationManager.AppSettings["Domain"].ToString());
                myReq.Credentials = netCredential;
                StringBuilder strSource = new StringBuilder("");

                //get the stream of data 
                string contentType = "";
                MemoryStream ms;
                // Send a request to download the pdf document and then get the response
                using (HttpWebResponse response = (HttpWebResponse)myReq.GetResponse())
                {
                    contentType = response.ContentType;
                    // Get the stream from the server
                    using (Stream stream = response.GetResponseStream())
                    {
                        // Use the ReadFully method from the link above:
                        byte[] data = ReadFully(stream, response.ContentLength);
                        // Return the memory stream.
                        ms = new MemoryStream(data);
                    }
                }

                Response.Clear();
                Response.ContentType = contentType;
                Response.AddHeader("Content-Disposition", "attachment;");

                // Write the memory stream containing the pdf file directly to the Response object that gets sent to the client
                ms.WriteTo(Response.OutputStream);
  }
  catch (Exception ex)
  {
    throw new Exception("Error in ReadFile", ex);
  }
}

3 голосов
/ 17 сентября 2008

Хорошо, я решил проблему, здесь действуют несколько факторов.

Во-первых, эта статья поддержки Microsoft была полезной: Internet Explorer не может открыть документы Office с веб-сайта SSL .

Чтобы Internet Explorer мог открыть документы в Office (или на любом внешнем сервере ActiveX), Internet Explorer должен сохранить файл в каталоге локального кэша и попросить соответствующее приложение загрузить файл. с помощью IPersistFile :: Load. Если файл не сохранен на диске, эта операция завершится неудачей.

Когда Internet Explorer связывается с защищенным веб-сайтом через SSL, Internet Explorer принудительно выполняет любой запрос без кэширования. Если заголовок или заголовки присутствуют, Internet Explorer не кэширует файл. Следовательно, Office не может открыть файл.

Во-вторых, что-то ранее при обработке страницы вызывало запись заголовка «no-cache». Поэтому необходимо добавить Response.ClearHeaders, это очистит заголовок no-cache, а вывод страницы должен разрешить кэширование.

В-третьих, для хорошей меры, также добавлено в Response.End, чтобы никакая другая обработка, выполняемая в течение времени жизни запроса, не пыталась очистить установленные мной заголовки и повторно добавить заголовок no-cache.

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

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

System.IO.FileStream fs = new System.IO.FileStream(Server.MapPath(".") + "\\" + "TestMe.doc", System.IO.FileMode.Open);
long byteNum = fs.Length;
byte[] fileBytes = new byte[byteNum];
fs.Read(fileBytes, 0, (int)byteNum);

Response.ClearContent();
Response.ClearHeaders();
Response.AppendHeader("Content-disposition", "attachment; filename=Testme.doc");
Response.Cache.SetCacheability(HttpCacheability.Public);
Response.ContentType = "application/octet-stream";
Response.OutputStream.Write(fileBytes, 0, fileBytes.Length);
Response.Flush();
Response.Close();
fs.Close();
Response.End();

Имейте в виду тоже, это только для иллюстрации. Реальный производственный код будет включать обработку исключений и, вероятно, читать файл по частям за раз (возможно, 10 КБ).

Мауро, спасибо за то, что уловил детали, которые также отсутствовали в коде.

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