通过Web服务发送复杂数据的首选方法是什么?

时间:2020-03-05 18:40:02  来源:igfitidea点击:

那是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服务接口/合同