通过Web服务发送复杂数据的首选方法是什么?
那是2008年,但我仍然对此感到恐惧。因此,我正在开发一个Web方法,该方法需要将复杂的类型传递给它并从中返回。我想用的两个选项是:
- 传递和返回具有数据和行为的实际业务对象。运行wsdl.exe时,它将自动创建仅包含数据部分的代理类,并且这些代理类将自动与服务器端我的真实业务对象进行相互转换。在客户端,他们将只能使用哑代理类型,并且必须将它们映射到一些他们认为合适的真实业务对象中。这里的一个很大的缺点是,如果我同时"拥有"服务器端和客户端,并且我想使用同一组真实的业务对象,那么我会遇到名称冲突等令人头疼的问题。(因为真实对象和代理的名称相同。)
- 忘记尝试传递"真实的"业务对象。相反,只需创建简单的DataTransfer对象,即可将其手动映射到我的真实业务对象。无论如何,它们仍然仍然可以通过wsdl.exe复制到新的代理对象,但是至少我并没有欺骗我自己,以为Web服务可以本机处理带有业务逻辑的对象。
顺便说一句,是否有人知道如何告诉wsdl.exe不复制该对象?我们不应该仅仅告诉它:"嘿,在这里使用这个现有的类型。不要复制它!"
无论如何,我现在已经定居第二,但是我很好奇你们都在想什么。我觉得一般而言,有更好的方法可以做到这一点,而我的观点甚至可能都不是很准确,所以请让我知道经历。
更新:我刚刚发现VS 2008可以在添加"服务引用"时重用现有类型,而不是在代理文件中创建全新的相同类型。甜的。
解决方案
回答
我会做一个混合动力车。我会使用这样的对象
public class TransferObject { public string Type { get; set; } public byte[] Data { get; set; } }
然后我有一个很好的小实用程序,可以序列化对象然后对其进行压缩。
public static class CompressedSerializer { /// <summary> /// Decompresses the specified compressed data. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="compressedData">The compressed data.</param> /// <returns></returns> public static T Decompress<T>(byte[] compressedData) where T : class { T result = null; using (MemoryStream memory = new MemoryStream()) { memory.Write(compressedData, 0, compressedData.Length); memory.Position = 0L; using (GZipStream zip= new GZipStream(memory, CompressionMode.Decompress, true)) { zip.Flush(); var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); result = formatter.Deserialize(zip) as T; } } return result; } /// <summary> /// Compresses the specified data. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="data">The data.</param> /// <returns></returns> public static byte[] Compress<T>(T data) { byte[] result = null; using (MemoryStream memory = new MemoryStream()) { using (GZipStream zip= new GZipStream(memory, CompressionMode.Compress, true)) { var formatter = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); formatter.Serialize(zip, data); } result = memory.ToArray(); } return result; } }
然后,我们只需传递将具有类型名称的传输对象。所以你可以做这样的事情
[WebMethod] public void ReceiveData(TransferObject data) { Type originType = Type.GetType(data.Type); object item = CompressedSerializer.Decompress<object>(data.Data); }
现在,压缩的序列化器使用泛型对其进行强类型化,但是我们可以使用上面的originType轻松地使Type对象接受要反序列化的Type对象,这完全取决于实现。
希望这能给我们一些想法。哦,要回答其他问题,wsdl.exe不支持重用类型,而WCF则支持。
回答
Darren wrote: I'd do a hybrid. I would use an object like this...
有趣的主意...传递对象的序列化版本,而不是(wsdl-ed)对象本身。从某种意义上说,我喜欢它的优雅,但从另一方面讲,它似乎无法达到将Web服务暴露给潜在的第三方或者合作伙伴或者其他目的的目的。他们怎么知道要通过什么?他们是否必须完全依靠文档?由于序列化是.NET特有的,因此它也丢失了一些"异构客户端"方面的内容。我并不是要批评,我只是想知道我们提出的建议是否也适用于这些类型的用例。我在封闭的环境中使用它并没有发现任何问题。
我应该研究WCF ...我一直在避免它,但是也许是时候了。
回答
哦,可以肯定的是,只有在我是Web服务的使用者时,或者如果我们有某种控制器向他们请求对象,然后我们处理序列化并发送,而不是直接使用Web服务,我才这样做。但是实际上,如果他们直接使用Web服务,那么他们将不需要或者不必具有首先要在其中带有类型的程序集,而应使用wsdl生成的对象。
是的,我提出的内容非常特定于.NET,因为我不喜欢使用其他任何东西。我唯一一次使用.net之外的Web服务的时间是在javascript中,但是现在我仅使用json响应而不是xml webservice响应:)
回答
还有一个论点是,分离层具有一组可序列化的对象,这些对象可从Web服务传入和传出,以及一个转换器,用于在该组和业务对象之间映射和转换(这些对象可能具有不适合通过电线传递的属性) )
它是Web服务软件工厂服务工厂偏爱的方法,意味着我们可以更改业务对象而不会破坏Web服务接口/合同