【问题标题】:WCF Service Invocation Error - Error while receiving HTTP responseWCF 服务调用错误 - 接收 HTTP 响应时出错
【发布时间】:2013-12-18 17:40:29
【问题描述】:

我几乎完成了我的服务编写工作,并且在过去的几个小时里我一直在测试。但是,无论我如何努力,我都会收到一项特定服务的一种特定方法的错误(code visible here

一切正常,除了 Cinema.Server.ShowController 的 Get() 和 GetAll() 方法。从代码中可以看出,Show是一个复杂的对象,我需要它的转移,架构不能改变。

每当我调用这两个函数时,如果有任何 Show 的数据库条目,它将抛出以下错误消息:

接收到的 HTTP 响应时出错 http://localhost:8090/ShowService。这可能是由于服务 端点绑定不使用 HTTP 协议。这也可能是由于 到被服务器中止的 HTTP 请求上下文(可能是由于 到服务关闭)。有关详细信息,请参阅服务器日志。

(带有可用堆栈跟踪的完整消息here

由于除此之外没有来自 WCF 的错误报告(并且此异常是在客户端引发的),我不知道问题是什么。有人可以请教我吗?

更新

所以在一些 SvcTracing 之后,这里是实际的异常:

尝试序列化参数时出错 http://tempuri.org/:GetAllResult。 InnerException 消息是“类型 'System.Data.Entity.DynamicProxies.Show_B50FB72FE59AC01FA537205B27B30F94605CB1F39BB27C2F1BBB00EF9A720361' 带有数据合同名称 'Show_B50FB72FE59AC01FA537205B27B30F94605CB1F39BB27C2F1BBB00EF9A720361:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' 预计不会。考虑使用 DataContractResolver 或添加任何 已知类型列表中静态未知的类型 - 例如, 通过使用 KnownTypeAttribute 属性或将它们添加到 传递给 DataContractSerializer 的已知类型列表。请参见 InnerException 了解更多详情。

【问题讨论】:

    标签: c# wcf http exception request


    【解决方案1】:

    把它放在客户端的配置文件中:

      <system.diagnostics>
        <sources>
          <source name="System.ServiceModel" switchValue="Information, ActivityTracing" propagateActivity="true">
            <listeners>
              <add name="traceListener" type="System.Diagnostics.XmlWriterTraceListener" initializeData="Logger.xml" />
            </listeners>
          </source>
        </sources>
    
      </system.diagnostics>
    

    运行客户端几次出现错误,确认exe文件夹中有logging.xml文件。

    为您的操作系统下载 Windows SDK,并运行 SvcTraceViewer,将其指向 xml 文件。如果这没有帮助,请将 XML 放入服务器的配置中并重复。

    不保证能给出答案,但能帮上大忙!

    我在 WCF 中遇到复杂结构的一个陷阱是循环引用:一个对象包含一个子项列表;每个子项都包含其父项的引用(序列化为副本)。父级的序列化副本包含子级列表等。

    干杯-

    【讨论】:

    • 我的“客户”是一个网站,使用上面来自共享库的代码。将其添加到库的配置帮助中吗?另外,我仔细检查了一下,没有循环引用:Show 指的是电影、房间、座位列表和预订列表。然后,每个 Booking 引用一张 Ticket,并在此处结束(尽管每张 Ticket 都包含对座位的间接手动引用,通过其行号和列号)。
    • 将其添加到网站的 Web.Config 中。如果 WCF 服务托管在同一个网站上?
    • 没有。正如我所说,WCF 服务(和客户端)都是共享库的一部分,包含上面的代码(所有共享、服务器和客户端 cs 文件都是 Cinema.dll 项目的一部分)。服务器和客户端使用 Server/ClientReference 类的实例,并使用它们进行通信。
    • 好的。将 XML 添加到站点的 Web.Config 文件中,然后查看 SvcTraceViewer 显示的内容。
    • 得到报告,结果发现,服务器端确实抛出了一个错误,它被捕获,但由于某种原因,没有记录。这是一个 SerializationException,但不幸的是日志不包含更多详细信息。我将使用异常消息更新问题。
    【解决方案2】:

    您正在 WCF 服务中使用实体框架,并且您正在返回从数据库中检索到的实体。 EF 动态创建您的类的代理子类。 WCF 不知道如何处理代理子类。

    这篇文章有更多细节: http://msdn.microsoft.com/en-us/library/vstudio/ee705457(v=vs.100).aspx

    POCO代理类型不能被直接序列化或反序列化 Windows 通信基金会 (WCF),因为 DataContractSerializer 序列化引擎只能序列化和 反序列化已知类型。代理类型不是已知类型。更多 信息,请参阅工作中的序列化 POCO 代理部分 与 POCO 实体主题。要将 POCO 代理序列化为 POCO 实体, 使用 ProxyDataContractResolver 类将代理类型映射到 POCO 序列化期间的类型。

    由于某种原因,MS 提供了 ProxyDataContractResolver,但没有提供应用解析器的属性。本文描述了实现 ApplyDataContractResolverAttribute 以及如何将其应用于操作。

    更新:

    在处理循环引用时,直接通过 WCF 返回 EF 对象存在相关问题。假设 A 类与 B 类具有多对一关系。A 具有到 B 的导航属性,B 具有 A 的集合。这可以通过使用属性 [DataContract(IsReference=true)] 标记 DataContract 来处理,但是如果您要传回 EF 对象,您可能不想将 DataContract 和 DataMember 添加到模型中的每个类。相反,DataContractSerializer 可以通过将 preserveObjectReferences 设置为 true 来为您处理此问题。 Sowmy Srinivasan 有一篇很棒的文章描述了如何做到这一点:Preserving Object Reference in WCF

    结合使用 ProxyDataContractResolver 和 preserveObjectReferences = true 的两种方法,我想出了这些类:

    public class ReferencePreservingProxyDataContractSerializerOperationBehavior
        : DataContractSerializerOperationBehavior
    {
        public ReferencePreservingProxyDataContractSerializerOperationBehavior(
          OperationDescription operationDescription)
            : base(operationDescription) { }
        public override XmlObjectSerializer CreateSerializer(
          Type type, string name, string ns, IList<Type> knownTypes)
        {
            return CreateDataContractSerializer(type, name, ns, knownTypes);
        }
    
        private static XmlObjectSerializer CreateDataContractSerializer(
          Type type, string name, string ns, IList<Type> knownTypes)
        {
            return CreateDataContractSerializer(type, name, ns, knownTypes);
        }
    
        public override XmlObjectSerializer CreateSerializer(
          Type type, XmlDictionaryString name, XmlDictionaryString ns,
          IList<Type> knownTypes)
        {
            return new DataContractSerializer(type, name, ns, knownTypes,
                0x7FFF /*maxItemsInObjectGraph*/,
                false/*ignoreExtensionDataObject*/,
                true/*preserveObjectReferences*/,
                null/*dataContractSurrogate*/,
                new ProxyDataContractResolver());
        }
    }
    
    public class ReferencePreservingProxyDataContractFormatAttribute : Attribute, IOperationBehavior
    {
        public void AddBindingParameters(OperationDescription description, BindingParameterCollection parameters)
        {
        }
    
        public void ApplyClientBehavior(OperationDescription description, System.ServiceModel.Dispatcher.ClientOperation proxy)
        {
            IOperationBehavior innerBehavior = new ReferencePreservingProxyDataContractSerializerOperationBehavior(description);
            innerBehavior.ApplyClientBehavior(description, proxy);
        }
    
        public void ApplyDispatchBehavior(OperationDescription description, System.ServiceModel.Dispatcher.DispatchOperation dispatch)
        {
            IOperationBehavior innerBehavior = new ReferencePreservingProxyDataContractSerializerOperationBehavior(description);
            innerBehavior.ApplyDispatchBehavior(description, dispatch);
        }
    
        public void Validate(OperationDescription description)
        {
        }
    }
    

    然后对于每个操作,我只是应用 [ReferencePreservingProxyDataContractFormatAttribute]

    【讨论】:

    • 尝试应用它,它搞砸了我的一些代码。现在所有的List都没有“Except”、“Union”等功能,根本拿不回来。
    • 听起来您缺少 LINQ 的 using 指令。检查文件顶部是否有using System.Linq;
    • 这是我检查的第一件事,虽然它不存在,但添加并没有解决问题,因此我发表了评论。
    • 确切的错误是:错误 23 'System.Collections.Generic.List' 不包含 'Except' 的定义和最佳扩展方法重载 'System.Linq .ParallelEnumerable.Except(System.Linq.ParallelQuery, System.Linq.ParallelQuery, System.Collections.Generic.IEqualityComparer)' 有一些无效参数
    • 用我最近的改动更新了要点。我知道这并不多,因为我不得不恢复许多试验,最终得到了相同的结果。可以看到使用了 Linq,但是它拒绝编译。
    【解决方案3】:

    我认为这部分是你的错误:

    '类型 'System.Data.Entity.DynamicProxies.Show_B50FB72FE59AC01FA537205B27B30F94605CB1F39BB27C2F1BBB00EF9A720361' 带有数据合同名称 'Show_B50FB72FE59AC01FA537205B27B30F94605CB1F39BB27C2F1BBB00EF9A720361:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' 不是预期的。

    可以通过在您的上下文中将 ProxyCreationEnabled 设置为 false 来解决,如下所示:

    cx = new CinemaContext();
    cx.Configuration.ProxyCreationEnabled = false;
    

    当然可能不止这些,但这可能有助于澄清实际问题。

    然后,您可以查看this 帖子,其中讨论了使用 DataContract/DataMember 解决循环引用。我在那里添加了一个答案,向您展示如何在单独的文件中执行此操作。看看能不能帮到你。

    【讨论】:

    • 谢谢,但我已经通过禁用 Show 类的延迟加载解决了这个问题。问题在于,如果启用了延迟加载,则特定对象的基于类的自定义属性在请求之前不会加载,并且 WPF 不喜欢代理。如果没有延迟加载,则具有所有引用的整个对象将从数据库中提取,并在将其发送到客户端之前重新创建。
    • 酷。我可以建议你用这些信息回答你自己的问题吗?这将帮助正在寻找类似问题的解决方案的其他人直接跳到答案。如果您能够显示解决问题的代码行,那将是理想的。
    • 不幸的是,我很久以前就完成了这个项目(学校作业),以至于我不完全记得我是如何做到的,以及我使用了哪些行,并且我还丢弃了源代码。跨度>
    猜你喜欢
    • 2018-03-22
    • 2014-06-03
    • 1970-01-01
    • 2020-07-24
    • 2013-02-26
    • 2023-01-30
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多