【问题标题】:Why does the proxy generated code create a new class when a MessageContract is in my WCF Service?当 MessageContract 在我的 WCF 服务中时,为什么代理生成的代码会创建一个新类?
【发布时间】:2010-05-24 19:49:02
【问题描述】:

我创建了两个 WCF 服务(运输和 PDFGenerator)。它们和我的 ClientApp 共享一个名为 Kyle.Common.Contracts 的程序集。在这个程序集中,我有三个类:

namespace Kyle.Common.Contracts
{
    [MessageContract]
    public class PDFResponse
    {
        [MessageHeader]
        public string fileName { get; set; }
        [MessageBodyMember]
        public System.IO.Stream fileStream { get; set; }
    }

    [MessageContract]
    public class PDFRequest
    {
        [MessageHeader]
        public Enums.PDFDocumentNameEnum docType { get; set; }
        [MessageHeader]
        public int? pk { get; set; }
        [MessageHeader]
        public string[] emailAddress { get; set; }
        [MessageBodyMember]
        public Kyle.Common.Contracts.TrackItResult[] trackItResults { get; set; }
    }

    [DataContract(Name = "TrackResult", Namespace = "http://kyle")]
    public class TrackResult
    {
        [DataMember]
        public int SeqNum { get; set; }
        [DataMember]
        public int ShipmentID { get; set; }
        [DataMember]
        public string StoreNum { get; set; }
    }
}

我的 PDFGenerator ServiceContract 看起来像:

namespace Kyle.WCF.PDFDocs
{
    [ServiceContract(Namespace="http://kyle")]
    public interface IPDFDocsService
    {
        [OperationContract]
        PDFResponse GeneratePDF(PDFRequest request);

        [OperationContract]
        void GeneratePDFAsync(Kyle.Common.Contracts.Enums.PDFDocumentNameEnum docType, int? pk, string[] emailAddress);

        [OperationContract]
        Kyle.Common.Contracts.TrackResult[] Test();
    }
}

如果我注释掉 GeneratePDF 存根,VS2010 生成的代理会意识到 Test 返回的是 Kyle.Common.Contracts.TrackResult 数组。但是,如果我将 GeneratePDF 留在那里,代理将拒绝使用 Kyle.Common.Contracts.TrackResult,而是创建一个新类 ClientApp.PDFDocServices.TrackResult,并将其用作 Test 的返回类型。

有没有办法在我使用 MessageContract 时强制代理生成器使用 Kyle.Common.Contracts.TrackResult?也许有更好的方法来使用流和文件名作为返回类型?

我只是不想创建一个 Copy 方法来从 ClientApp.PDFDocServices.TrackResult 复制到 Kyle.Common.Contracts.TrackResult,因为它们应该是完全相同的类。

【问题讨论】:

    标签: c# wcf


    【解决方案1】:

    经过大量额外的挖掘,我意识到实际上是 Enum “破坏”了它。它与 DataContractSerializer 与 XmlSerializer 的工作方式有关。长话短说,解决方案是将 Enum 变成可空的。

    [MessageContract]
    public class PDFRequest
    {
        [MessageHeader]
        public Enums.PDFDocumentNameEnum? docType { get; set; }
        [MessageHeader]
        public int? pk { get; set; }
        [MessageHeader]
        public string[] emailAddress { get; set; }
        [MessageBodyMember]
        public Kyle.Common.Contracts.TrackItResult[] trackItResults { get; set; }
    }
    

    【讨论】:

      【解决方案2】:

      我遇到了同样的问题 (MessageContract+enums),你的帖子帮助了我。实际上,如果您将枚举字段显式设置为可为空,则它可以工作。问题是当使用枚举时,WCF 使用 XML 序列化程序,它不能从空字符串中分辨出 null。

      WCF 团队的一位实际成员对此行为 here 进行了详细解释。

      在使用裸消息时的文档/文字的情况下,WCF 在处理枚举类型时回退到 XmlSerializer。 ... XmlSerializer 默认将 null 视为缺失 ... 我们遇到没有 nillable="true" 的架构 ... 值类型的检测逻辑目前仅处理原始值类型,它不检查枚举。

      换句话说,WCF 不喜欢枚举...但是,嘿,它有效,您只需要注意它!

      【讨论】:

        【解决方案3】:

        您可以指示 Visual Studio 重用引用程序集中的类。因此,如果您的测试项目有一个对 Kyle.Common.Contracts 程序集的程序集引用,它应该重用其中定义的那些类型,而不是添加新的客户端代理类。

        启用此功能的开关位于Add Service Reference 对话窗口中的Advanced 页面上 - 默认情况下应该打开:

        确保您的项目

        • 具有对通用数据协定程序集的程序集引用
        • 当您添加服务引用时,此设置确实处于启用状态

        【讨论】:

        • 马克,感谢您的及时回复。我已经仔细检查了这一点,并且肯定已经检查过了。如果我注释掉使用 MessageContracts 的 OperationContract,并在我的客户端更新我的引用,客户端将使用正确的程序集。但是,一旦我取消注释 OperationContract 并再次更新我的引用,客户端就会创建新类。这让我觉得这与 MessageContracts 的工作方式有关。
        • @DaleyKD:好的,听上去很有趣——我自己从不使用 MessageContracts,所以我无法从我自己的经验中真正判断出是什么导致了这种行为。不过好像有点奇怪....
        猜你喜欢
        • 1970-01-01
        • 2011-04-03
        • 1970-01-01
        • 2011-02-15
        • 1970-01-01
        • 1970-01-01
        • 2011-08-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多