Проблема с использованием буфера обмена на стороне сервера в веб-приложении ASPX - PullRequest
1 голос
/ 16 ноября 2010

У меня есть приложение для составления отчетов, которое работает на стороне сервера, которое считывает сохраненный BMP из моей базы данных (в виде байта []), преобразует его обратно в изображение, а затем помещает его в электронную таблицу Excel, которая образует основудля этого отчета (этот отчет в конечном итоге доставляется клиенту для загрузки.) Для этого я пытаюсь использовать буфер обмена на стороне сервера для обработки «вставки» изображения в определенный диапазон на листе.Вот фрагмент кода -

System.Drawing.Image image;
Bitmap bm;
Graphics g;
Excel.Range range;

MemoryStream ms = new MemoryStream(graphRecs.ElementAt(0).Graph, 0, 
   graphRecs.ElementAt(0).Graph.Length);
ms.Write(graphRecs.ElementAt(0).Graph, 0, graphRecs.ElementAt(0).Graph.Length);
image = System.Drawing.Image.FromStream(ms, true);

bm = new Bitmap(413, 130);
g = Graphics.FromImage(bm);
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;
g.DrawImage(image, 0, 1, 413, 130);

Clipboard.SetDataObject(bm, false, 4, 250);
range = ws.get_Range(cBlkPtr[6, 2], cBlkPtr[6, 2]);
ws.Paste(range, bm);
Clipboard.Clear();

Запуск в режиме отладки под VS2008, кажется, работает нормально - изображение преобразуется, добавляется в буфер обмена и вставляется в указанный диапазон без проблем.После публикации веб-приложения на моем сервере IIS происходит сбой в операторе Clipboard.SetDataObject со следующим исключением:

Requested Clipboard operation did not succeed.
at System.Windows.Forms.Clipboard.ThrowIfFailed(Int32 hr)
at System.Windows.Forms.Clipboard.SetDataObject(Object data, Boolean copy, Int32 
       retryTimes, Int32 retryDelay) 
at ReportGenerate.buildPvsClinicSections(Worksheet ws, Object j, patientRecord p, String 
       patientStatus, String programType)

Я предполагаю, что эта ошибка связана с тем, что НЕ находится вSingleThreadApartment.Я добавил директиву AspCompat = true на свою страницу ASPX без изменений (не думал, что это поможет, поскольку AspCompat больше подходит для ASP, чем для ASPX).Поскольку я не могу добавить [STAThread] к своему «основному» (это будет IIS), я не знаю, как действовать дальше.Я также готов изменить подход, который я использую при добавлении изображения в электронную таблицу, при условии, что я могу явно указать (через диапазон), где его разместить.Например, использование Shape.AddPicture не позволяет мне сделать это.

Есть идеи?

Спасибо.

Обновление

Я обновилфрагмент кода для запуска второго потока с правильным ApartmentState -

range = ws.get_Range(cBlkPtr[6, 2], cBlkPtr[6, 2]);

ClipboardModel cbm = new ClipboardModel(bm, range, ws);
System.Threading.Thread cbThread = new System.Threading.Thread(new
     System.Threading.ParameterizedThreadStart(DoClipboardStuff));
cbThread.SetApartmentState(System.Threading.ApartmentState.STA);
cbThread.Start(cbm);
cbThread.Join();

Метод 'DoClipboardStuff' выглядит следующим образом -

[STAThread]
protected void DoClipboardStuff(object o)
{
  try
  {
    ClipboardModel cbm = (ClipboardModel)o;

    Clipboard.SetDataObject(cbm.bm, false, 4, 250);
    cbm.ws.Paste(cbm.range, cbm.bm);
    Clipboard.Clear();
  }
  catch (Exception e)
  {
    StreamWriter sw = new StreamWriter(@"C:\Myopia\Log.txt");
    sw.WriteLine(e.Message);
    sw.WriteLine(e.StackTrace);
    sw.Flush();
    sw.Close();
    throw e;
  }
}

Теперь я получаю точно такую ​​же ошибку, как и раньшеТолько сейчас в этом методе.Я начинаю подозревать, что это не ApartmentState, а скорее отсутствие «пользовательского интерфейса».Я не знаю, будет ли нормальный интерфейс Win32 лучше, но это мой следующий подход (если только у кого-то нет более, .NET'ish решения.)

Update # 2

Хотя мне не удалось решить проблему с IIS 6 и буфером обмена, мне удалось обойти эту проблему, записав восстановленный BMP во временный файл, а затем с помощью Shapes.AddPicture разместил его там, где он мне нуженбыть -

g.DrawImage(image, 0, 1, 400, 75);

bm.Save(@"c:\Myopia\temp.bmp");

Excel.Shape xlShape = ws.Shapes.Item("Rectangle 2");
float left = xlShape.Left;
float top = Convert.ToSingle(ws.get_Range("A1", cBlkPtr[5, 2]).Height);
float width = xlShape.Width;
float height = xlShape.Height;

xlShape = ws.Shapes.AddPicture(@"c:\Myopia\temp.bmp", 
   Microsoft.Office.Core.MsoTriState.msoFalse, Microsoft.Office.Core.MsoTriState.msoCTrue,
        left, top, width, height);

Не идеальное решение, но то, которое работает на данный момент.Единственная проблема с этим подходом заключается в том, что у меня, кажется, есть потеря разрешения между восстановлением BMP из байта [], сохранением его в файл temp.bmp и последующим добавлением его обратно - bmp выглядит «нечетким».Возможно, придется искать менее «потерянный» формат для использования.

1 Ответ

0 голосов
/ 16 ноября 2010

Если STA действительно является проблемой, попробуйте выполнить операцию в новом потоке, для которого вы установили STA, прежде чем запускать его, как показано в ответе Skeet (tm) на этот вопрос:

в .NET, Как мне установить STAThread, когда я запускаю форму в дополнительном потоке?

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

...