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

时间:2008-08-16 03:58:25

标签: .net web-services soap wsdl

这是2008年,我仍然对这个问题感到厌烦。所以我正在开发一个Web方法,需要传递一个复杂类型并从中返回。我正在考虑的两个选项是:

  1. 传递并返回包含数据和行为的实际业务对象。运行wsdl.exe时,它将自动创建仅包含数据部分的代理类,这些代理类将自动转换为服务器端的实际业务对象。在客户端,他们只会使用哑代理类型,他们必须将它们映射到一些他们认为合适的真实业务对象。这里的一个很大的缺点是,如果我“拥有”服务器端和客户端端,并且我想使用相同的一组真实业务对象,我可能遇到一些带有名称冲突的头疼等等。(因为真实的对象和代理名称相同。)

  2. 忘记尝试传递“真正的”业务对象。相反,只需创建简单的DataTransfer对象,我将手动来回映射到我的实际业务对象。无论如何,它们仍然被wsdl.exe复制到新的代理对象,但至少我并不是在试图让自己认为Web服务本身可以处理具有业务逻辑的对象。

  3. 顺便说一下 - 有谁知道如何告诉wsdl.exe 制作对象的副本?我们不应该只是告诉它,“嘿,在这里使用现有类型。不要复制它!”

    无论如何,我现在已经确定了#2,但我很好奇你们都在想什么。我觉得有一些方式更好的方法可以做到这一点,我可能在所有方面都不完全准确,所以请让我知道你的经历是什么。

    更新:我刚刚发现VS 2008在添加“服务参考”时可以选择重用现有类型,而不是在代理文件中创建全新的相同类型。甜。

4 个答案:

答案 0 :(得分:4)

我会做一个混合动力车。我会使用像这样的对象

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);
}

现在压缩序列化程序使用泛型使其强类型化,但您可以轻松地使用一个方法来接受一个Type对象以使用上面的originType进行反序列化,这一切都取决于您的实现。

希望这会给你一些想法。哦,并回答你的另一个问题,wsdl.exe不支持重用类型,但WCF确实如此。

答案 1 :(得分:1)

还有一个用于分隔层的参数 - 具有一组可序列化的对象,这些对象可以传递到Web服务和从Web服务传递,以及一个转换器,用于映射和转换该集合和业务对象(可能具有不适合的属性)越过电线)

它是Web服务软件工厂service factory所青睐的方法,这意味着您可以在不破坏Web服务接口/合同的情况下更改业务对象

答案 2 :(得分:1)

  

Darren 写道:我会做混合动力。我会使用这样的对象......

有趣的想法......传递对象的序列化版本而不是(wsdl-ed)对象本身。在某种程度上,我喜欢它的优雅,但另一方面,它似乎打败了将您的Web服务暴露给潜在的第三方或合作伙伴或其他任何东西的目的。他们怎么知道要通过什么?他们是否必须完全依赖文档?它也失去了一些“异构客户端”方面,因为序列化非常.Net特定。我并不是说要批评,我只是想知道你提出的内容是否也适用于这些类型的用例。我认为在封闭环境中使用它没有任何问题。

我应该调查WCF ......我一直在避免它,但也许是时候了。

答案 3 :(得分:1)

哦,当然,我只是在我是网络服务的消费者时,或者如果你有某种控制器,他们从中请求一个对象,然后你处理序列化和发送,而不是直接消费网络服务。但实际上,如果他们直接使用web服务,那么他们就不需要或者必须首先拥有其中包含类型的程序集,并且应该使用wsdl生成的对象。

是的,我提出的是非常具体的.NET,因为我不喜欢使用其他任何东西。我在.net之外使用webservices的唯一另一次是在javascript中,但现在我只使用json响应而不是xml webservice响应:)