9

现在是 2008 年,我仍然对这个感到困惑。因此,我正在开发一种需要将复杂类型传递到其中并从中返回的 Web 方法。我正在玩弄的两个选项是:

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

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

顺便说一句 - 有谁知道如何告诉 wsdl.exe不要复制对象?我们不应该直接告诉它,“嘿,在这里使用这个现有的类型。不要复制它!”

无论如何,我现在已经确定了#2,但我很好奇你们的想法。我感觉一般来说有更好的方法可以做到这一点,而且我的所有观点可能都不完全准确,所以请让我知道你的经历。

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

4

4 回答 4

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

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

希望这能给你一些想法。哦,要回答您的其他问题,wsdl.exe 不支持重用类型,但 WCF 支持。

于 2008-08-16T04:31:53.667 回答
1

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

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

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

于 2008-08-16T04:49:33.850 回答
1

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

是的,我提出的内容非常特定于 .NET,因为我不喜欢使用其他任何东西。我唯一一次在.net 之外使用 web 服务是在 javascript 中,但现在我只使用 json 响应而不是 xml webservice 响应:)

于 2008-08-16T05:16:55.213 回答
1

there is also an argument for separating the tiers - have a set of serializable objects that get passed to and from the web service and a translator to map and convert between that set and the business objects (which might have properties not suitable for passing over the wire)

Its the approach favoured by the web service software factory service factory and means that you can change your business objects without breaking the web service interface/contract

于 2008-08-21T12:31:34.190 回答