代码之家  ›  专栏  ›  技术社区  ›  Steve Elmer

在wcf中,如何返回包含System.Drawing.Image属性的类?

  •  2
  • Steve Elmer  · 技术社区  · 16 年前

    我有一个wcf服务,它公开了一个方法,该方法返回包含image属性的对象数组(请参见下面的代码)。在同一个解决方案中,我有一个类库项目,它具有对我的WCF项目的服务引用。在类库中,当我尝试“更新服务引用”时,代理类将不可用。当我从我的类中删除“graphic”属性时,更新类库中的服务引用没有困难,我的代码编译并运行良好。我将“graphic”属性放回,代理类再次变得不可用。更奇怪的是,服务引用所公开的唯一类是“image”。

    我在这里能俯瞰到什么?

    [Serializable]
    public class PhotoDTO
    {
        public Guid Id { get; set; }
        public Image Graphic { get; set; }
    }
    
    
    [ServiceContract]
    public interface IGeneralService
    {
        [OperationContract]
        PhotoDTO[] GetPhotos(Guid subsectionId);
    }
    
    4 回复  |  直到 16 年前
        1
  •  5
  •   nitzmahone    16 年前

    编辑:正如Alexdej正确指出的那样,映像将正确地使用dcs进行序列化/反序列化,但是您必须将DataContract类型更改为位图,或者在运行时使用config为system.drawing.image指定位图的已知类型(您不能将其属性化,因为您不拥有image类)。

    Image类不适合由DataContractSerializer进行序列化-它与GDI缓冲区和封面下的内容有各种各样的联系。dcs用于表示控制类的整个结构的数据对象。这是因为在3.5sp1中,他们增加了dcs序列化没有用datacontractattribute标记的对象的能力(主要是为了方便那些懒惰的人将其线类属性化)。不幸的副作用是,序列化程序很乐意尝试序列化任何旧对象,但在许多情况下(如您的)都无法生成有用的结果。

    不管怎样,您需要将它转换成一个字节[]或一个流,以使其通过线路,并将其作为图像重新水化。如果在两侧使用WCF和相同的DataContract类型(例如,不是生成的类型),则可以将图形保留为属性,但不使用DataMember标记它。通过调用image为另一个proprity imagebytes(标记为datamember)创建图形填充存储集。保存到memoryStream,然后转储字节[]。使set on image byte s从以相同方式传入的byte[]加载图形属性的内部图像存储。当对象在另一端进行反序列化(例如,反序列化程序调用ImageBytes setter)时,poof-图形属性的存储被填充,它全部正常工作。全自动序列化/反序列化行为-ImageBytes属性只是一个实现细节。

        2
  •  1
  •   Simon Fox    16 年前

    尝试显式指定数据合同

    [DataContract()]
    public class PhotoDTO
    {
        [DataMember()] 
        public Guid Id { get; set; }
    
        [DataMember()] 
        public Image Graphic { get; set; }
    }
    

    更新

    下面是一些测试序列化问题的代码。如果在已知类型列表中没有位图类型(它继承自图像,并且我正在使用image.from file()加载PNG文件),则会中断此操作。在此上下文中引发的异常表示需要位图为已知类型。然后序列化就可以工作了。

     public static void LogDTO<T>(T dto)
     {
            DataContractSerializer ser =
                new DataContractSerializer(typeof(T),
                     new []{typeof(System.Drawing.Image),
                            typeof(System.Drawing.Bitmap)});
    
            FileStream writer = new FileStream("C:\\temp\\" + dto.ToString() + ".xml",
                                                                 FileMode.Create);
            ser.WriteObject(writer, dto);
            writer.Close();
        }
    
        3
  •  1
  •   alexdej    16 年前

    image类与dcserializer兼容——image实现了ISerializable,并且仅对映像的原始字节[]数据进行序列化时“做了正确的事情”。

    您应该从更新服务引用过程中获得一些警告(在错误列表窗口中查找这些警告)。可能发生的情况是更新服务引用找不到System.Drawing.Image类型,因为您的客户端项目没有对System.Drawing.dll的引用。尝试向System.Drawing.dll添加程序集引用,然后再次更新服务引用。

    顺便说一句,您应该将[datacontract]和[datamember]属性放在您的类型上,而不是像其他海报中提到的那样[可序列化]。或者,如果您使用的是3.5sp1,则可以完全取消这些属性。

        4
  •  0
  •   Steve Elmer    16 年前

    谢谢,尼茨玛宏。不过,这正是我害怕的。我希望避免将第二个属性与看起来有点“臭”的同一字段关联,但这可能是最简单的解决方案:

    [DataContract]
    public class PhotoDTO
    {
        private Guid _id = Guid.Empty;
        private Image _graphic;
    
    
        [DataMember]
        public Guid Id
        {
            get { return _id; }
            set { _id = value; }
        }
    
        [DataMember]
        public byte[] GraphicBytes
        {
            get 
            {
                if (_graphic == null) return new byte[0];
    
                using (MemoryStream ms = new MemoryStream())
                {
                    _graphic.Save(ms, ImageFormat.Png);
                    return ms.ToArray();
                }
            }
    
            set 
            {
                if (value.Length > 0)
                {
                    using (MemoryStream ms = new MemoryStream(value))
                    {
                        _graphic = Image.FromStream(ms);
                    }
                }
                else
                {
                    _graphic = null;
                }
            }
        }
    
        public Image Graphic
        {
            get { return _graphic; }
            set { _graphic = value; }
        }
    
    
        public PhotoDTO()
            : this(Guid.Empty, null)
        { }
    
        public PhotoDTO(Guid id, Image graphic)
        {
            _id = id;
            _graphic = graphic;
        }
    }
    

    }

    推荐文章