Только часть потока записывается в компонент конвейера
Я создаю компонент конвейера, который может преобразовать формат изображения в другой формат (например, с jpg в png):
using (System.Drawing.Bitmap bmpSource = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(msgReceived.BodyPart.Data))
{
VirtualStream strConvertedImage = new VirtualStream();
bmpSource.Save(strConvertedImage, System.Drawing.Imaging.ImageFormat.Png);
strConvertedImage.Flush();
strConvertedImage.Position = 0;
ctxPipeline.ResourceTracker.AddResource(strConvertedImage);
}
msgReceived.BodyPart.Data = strConvertedImage;
Я использую этот компонент в приемном конвейере с файловым адаптером, и он работает нормально, но когда я подписываюсь на сквозной порт отправки и файловый адаптер, записанный файл является лишь частью реального изображения.
Замечания:
Я могу использовать этот же код (за исключением загрузки исходного растрового изображения из потока файлов вместо потока сообщений BizTalk) в консольном приложении Windows, и он работает нормально, так что это похоже на BizTalk.
Я думаю, что это как-то связано с исходным потоком.
Это кажется странным поведением, но если я проверяю свойства длины и позиции msgReceived.BodyPart.Data, длина равна 904678. Позиция равна 0. Позиция остается равной 0 и никогда не меняется, даже когда битовая карта загружается и сохраняется. Я ожидал бы, что при загрузке растрового изображения положение изменится, если только метод BitMap.FromStream не начнет поиск потока после завершения загрузки.
Кроме того, когда я сохраняю растровое изображение в своем новом потоке в виде png, длина нового потока всегда равна 54789, представляя только первую сторону изображения. Теперь, если я немедленно сохраню тот же объект растрового изображения в новом потоке, его размер будет 1400868, представляющий все изображение, а msgReceived.BodyPart.Data.Position теперь равен 904678, что означает, что весь исходный поток был прочитан.
Вот пример:
using (System.Drawing.Bitmap bmpSource = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(msgReceived.BodyPart.Data))
{
VirtualStream strConvertedImage = new VirtualStream();
bmpSource.Save(strConvertedImage, System.Drawing.Imaging.ImageFormat.Png);
strConvertedImage.Flush();
strConvertedImage.Position = 0;
//msgReceived.BodyPart.Data.Position is 0
//msgReceived.BodyPart.Data.Length is 904678
//strConvertedImage.Position is 54789 (Only part of image was saved)
strConvertedImage = new VirtualStream();
bmpSource.Save(strConvertedImage, System.Drawing.Imaging.ImageFormat.Png);
//msgReceived.BodyPart.Data.Position is 904678
//msgReceived.BodyPart.Data.Length is 904678
//strConvertedImage.Position is 1400868 (full image was saved)
msgReceived.BodyPart.Data = strConvertedImage;
ctxPipeline.ResourceTracker.AddResource(strConvertedImage);
}
Почему позиция msgReceived.BodyPart.Data продвигается только во втором сохранении? И почему бы при первой попытке сохранения сохранить только часть преобразованного изображения. Я сбит с толку!
1 ответ
Я бы не использовал Data
свойство кроме того, чтобы установить поток в конце; на MSDN он клонирует поток данных и иногда дает неожиданное поведение (я видел Data
свойство быть нулевым в некоторых адаптерах, даже если GetOriginalDataStream()
успешно вернул поток). использование GetOriginalDataStream()
вместо. Я бы также избегал использования using
блоки в конвейере - хотя я не могу понять, почему ваш пример будет проблемой, очень легко ошибочно избавиться от потока, который в итоге удаляет исходный поток данных.
Например,
Stream originalStream = msgReceived.BodyPart.GetOriginalDataStream();
originalStream.Seek(0, SeekOrigin.Begin);
VirtualStream vtsConvertedImage = new VirtualStream()
System.Drawing.Bitmap bmpSource = (System.Drawing.Bitmap)System.Drawing.Bitmap.FromStream(originalStream);
bmpSource.Save(vtsConvertedImage, System.Drawing.Imaging.ImageFormat.Png);
vtsConvertedImage.Flush();
vts.ConvertedImage.Seek(0, SeekOrigin.Begin);
msgReceived.BodyPart.Data = vtsConvertedImage;
ctxPipeline.ResourceTracker.AddResource(vtsConvertedImage);
ctxPipeline.ResourceTracker.AddResource(bmpSource);