MemoryStream и FileStream: Document Viewer успешно отображает документ из файлового потока, но не из памяти? - PullRequest
2 голосов
/ 03 августа 2011

Я использую элемент управления PDF Viewer от C1 в приложении Silverlight и проверяю ограничения по максимальному размеру PDF.У меня есть PDF размером 35 МБ.

Когда я загружаю просмотрщик PDF через OpenFileDialog, просто отправляя ему поток файлов, который он хорошо отображает.Все 900 страниц.

Однако, когда я пытаюсь загрузить просмотрщик PDF через MemoryStream, созданный из байта [], он ничего не рендерит.Он не выдает ошибку, он просто выводит пустым.

Это точно такой же документ.И процесс MemoryStream успешно работает со значительно меньшими документами PDF.Тем не менее, метод FileStream работает с большими документами, поэтому я знаю, что это не ограничение просмотра PDF, верно?

Метод FileStream:

        OpenFileDialog ofd = new OpenFileDialog();
        bool? res = ofd.ShowDialog();
        if (res == true)
        {
            FileStream stream = ofd.File.OpenRead();
            docViewer.LoadDocument(stream);
        }

Метод MemoryStream:

       imageBytes = File.ReadAllBytes(path);
       MemoryStream stream = new MemoryStream();
       stream.Write(imageBytes, 0, imageBytes.Length);
       stream.Seek(0, SeekOrigin.Begin);
       docViewer.LoadDocument(stream);

Это дало мне те же результаты.Пустой просмотрщик:

using (MemoryStream stream = new MemoryStream(imageBytes))
{
      docViewer.LoadDocument(stream);
}

Снова ... разочарован неудачей.Я реорганизовал вызов для использования «OpenReadAsync», затем я изменил свой вызов API (мы используем MVC в качестве псевдо-API), чтобы вернуть поток, и он по-прежнему отображается пустым.Длина внутреннего результирующего потока тоже правильная.

Вызов клиента:

        string url = App.Server + "Document/RetrievePDFTest";
        try
        {
            WebClient wc = new WebClient();
            wc.OpenReadCompleted += new OpenReadCompletedEventHandler(delegate(object sender, OpenReadCompletedEventArgs e)
            {
                if (e.Result != null)
                {
                    docViewer.LoadDocument(e.Result);
                }
            });
            wc.OpenReadAsync(new Uri(url));
        }
        catch (Exception ex)
        {
            //TODO - handle exception
        }

API сервера:

    public ActionResult RetrievePDFTest()
    {
        return File(System.IO.File.ReadAllBytes("D://temp//repositories//test35mb.PDF"), "application/pdf");
    }

ОБНОВЛЕНИЕ !!!!Я полагаю, что обнаружил, что может быть проблемой.

В моем приложении Silverlight я на самом деле открываю это средство просмотра документов в новом окне, а затем отправляю этому новому окну информацию, с помощью которой можно получитьPDF изображение с сервера.По сути, я говорю, какой документ получить по ключу, который я передаю:

this.windowManager.NavigateToPageInNewWindow("/Views/pdfViewerUserControl.xaml");
                LocalMessageSender s = new LocalMessageSender("receiver", LocalMessageSender.Global);
                s.SendAsync(doc.Barcode);

Теперь, в моем pdfViewerUserControl.xaml, в его конструкторе я создаю и регистрирую слушатель длясообщение:

public pdfViewerUserControl()
    {
        LocalMessageReceiver messageReceiver = new LocalMessageReceiver("receiver", ReceiverNameScope.Global, LocalMessageReceiver.AnyDomain);
        messageReceiver.MessageReceived += messageReceiver_MessageReceived;
        try
        {
            messageReceiver.Listen();
        }
        catch (Exception ex)
        {

        }

        // Required to initialize variables
        InitializeComponent();
    }

В обработчике события «messageReceiver_MessageReceived» я выполняю серверный вызов для получения изображения и загрузки средства просмотра.Этот процесс приводит к пустой программе просмотра PDF, даже если сервер возвращает изображение.(даже БОЛЬШОЙ pdf)

СЕЙЧАС, как инструмент тестирования, у меня также есть кнопка тестирования на странице, эта кнопка запускает событие в коде позади, который делает точно такой же вызов сервера, и загружает результат вточно так же, но это работает !!!Большой 35 МБ PDF-файл успешно отображается в средстве просмотра.

Это наводит меня на мысль, что при использовании объектов LocalMessageSender / LocalMessageReceiver возникает разрыв.

Ответы [ 3 ]

2 голосов
/ 03 августа 2011

Учитывая комментарии, я подозреваю, что проблема в том, что вы загружаете его как строку, а затем конвертируете в байты.Сравните данные в байтовом массиве с данными в файле (например, возьмите хеш MD5).

Чтобы загрузить двоичные данные, вместо этого следует использовать DownloadData.

0 голосов
/ 04 августа 2011

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

Я открываю новое окно, используя HtmlPage.PopupWindow (), указывая другой usercontrol (мой пользовательский элемент управления pdf XAML, который содержит pdfviewer) в качестве URI.

Для того, чтобы передать этому новому окну ключ, какой документ нужно получить / просмотреть, я зарегистрировал слушателя на пользовательском элементе управления этого нового окна. Затем я посылаю этому слушателю ключ.

Что ж, в событии получения сообщения слушателя я делаю вызов, чтобы получить массив байтов и заполнить средство просмотра.

Кажется, это не обновляет интерфейс. Вместо этого я отключил шаблон «слушатель / отправитель» и просто прикрепил ключ к концу URI к «HtmlPage.PopupWindow ()». Затем в конструкторе новой страницы управления пользователями я экстраполирую ключ из URI и «Боб - твой дядя», он работает.

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

0 голосов
/ 03 августа 2011

Одной из возможных причин может быть то, что объект потока памяти должен быть расположен в конце.

using (MemoryStream ms = new MemoryStream())
{
    // Do something with ms..
}

или произнесите это в конце использования объекта потока памяти

stream.Dispose();
stream.Close();
...