自定义 wcf 数据提供者和调试关系错误

Posted

技术标签:

【中文标题】自定义 wcf 数据提供者和调试关系错误【英文标题】:Custom wcf data provider and debugging a relationship error 【发布时间】:2011-12-01 06:53:11 【问题描述】:

我正在实现一个自定义数据提供者,我已经让它返回数据并且可以被过滤,但是在让关系正常工作时遇到了一些麻烦。

查询元数据时,关系看起来正确,查询表时出现相关属性链接,但尝试访问 ResourceReference 属性时出现以下异常:

    Object reference not set to an instance of an object.
        System.NullReferenceException
        stacktrace at System.Data.Services.Providers.DataServiceProviderWrapper.GetResourceAssociationSet(ResourceSetWrapper resourceSet, ResourceType resourceType, ResourceProperty resourceProperty)
   at System.Data.Services.Providers.DataServiceProviderWrapper.GetContainer(ResourceSetWrapper sourceContainer, ResourceType sourceResourceType, ResourceProperty navigationProperty)
   at System.Data.Services.Providers.DataServiceProviderWrapper.GetResourceProperties(ResourceSetWrapper resourceSet, ResourceType resourceType)
   at System.Data.Services.Serializers.SyndicationSerializer.WriteObjectProperties(IExpandedResult expanded, Object customObject, ResourceType resourceType, Uri absoluteUri, String relativeUri, SyndicationItem item, DictionaryContent content, EpmSourcePathSegment currentSourceRoot)
   at System.Data.Services.Serializers.SyndicationSerializer.WriteEntryElement(IExpandedResult expanded, Object element, ResourceType expectedType, Uri absoluteUri, String relativeUri, SyndicationItem target)
   at System.Data.Services.Serializers.SyndicationSerializer.WriteTopLevelElement(IExpandedResult expanded, Object element)
   at System.Data.Services.Serializers.Serializer.WriteRequest(IEnumerator queryResults, Boolean hasMoved)
   at System.Data.Services.ResponseBodyWriter.Write(Stream stream)

这是我如何创建关系的示例:

var sourceReference = new ResourceProperty(
                relatedType.ResourceTypeName,
                ResourcePropertyKind.ResourceReference,
                relatedType.ResourceType);
            sourceReference.CanReflectOnInstanceTypeProperty = false;
            compoundType.ResourceType.AddProperty(sourceReference);

var destinationReference = new ResourceProperty(
                compoundType.ResourceSetName,
                ResourcePropertyKind.ResourceSetReference,
                compoundType.ResourceType);
            destinationReference.CanReflectOnInstanceTypeProperty = false;
            source.ResourceType.AddProperty(destinationReference);

var sourceAssociation = new ResourceAssociationSet(
                        "source",
                        new ResourceAssociationSetEnd(compoundType.ResourceSet, compoundType.ResourceType, sourceReference),
                        new ResourceAssociationSetEnd(relatedType.ResourceSet, relatedType.ResourceType, null));

var destinationAssociation = new ResourceAssociationSet(
                             "destination",
                             new ResourceAssociationSetEnd(relatedType.ResourceSet, relatedType.ResourceType, destinationReference),
                             new ResourceAssociationSetEnd(compoundType.ResourceSet, compoundType.ResourceType, null));

通过查看 OData 网站上的示例代码,我认为我已正确完成所有操作,但无法确定我的错误。有任何想法吗?或调试自定义 WCF 数据服务的提示?

更新: 这是在 null 异常之前发生的情况。

有一个与 Projects 有关系的资源集 Collars,所以我执行以下查询: blah.svc/Collars(1)/项目

我在 IDataServiceMetadataProvider 中对 GetResourceAssociationSet 的覆盖使用参数 ResourceSet = Collars、ResourceType = Collar、Property = Project 进行调用,然后我返回上面指定的关联集。 然后使用 ResourceSet = Projects、ResourceType = Collar、Property = Project 再次调用 GetResourceAssociationSet,我返回相同的关联集。

那么在System.Data.Services.Providers.GetResourceAssociationSetEnd中传入的变量是resourceSet = Projects,resourceType = Collar,resourceProperty = Project,这个函数返回null。

这使得 System.Data.Services.Providers.DataServiceProviderWrapper.GetResourceAssociationSet 中的 thisEnd 等于 null。 然后使用相同的变量调用 GetRelatedResourceAssociationSetEnd,也返回 null。

所以它会随着调用而崩溃

ResourceSetWrapper relatedSet = this.ValidateResourceSet(relatedEnd.ResourceSet); 

因为relatedEnd 为空。

【问题讨论】:

在双向关系的情况下,您可以只创建一个 ResourceAssociationSet 并为两个导航属性返回它。但这只是一个优化,上面的应该也可以。 很遗憾,我找不到问题所在。您能否尝试启用 .NET 框架的源代码,以便准确查看失败的位置。或者,如果这不可能,调试器应该在抛出异常时至少向您显示一些局部变量,您能否也发布这些(以及它们的值)? 感谢 Vitek,我在上面添加了更多细节,但我很难让源代码调试正常工作:( 是的,删除我缓存的符号并重新下载它们,源代码调试再次工作,添加了更多细节。 无论如何,如果您可以转储代表每个方向的导航属性的 ResourceProperty 会有所帮助。 GetResourceAssociationSet 调用源自一个 ResourceType,它采用了基本 ResourceType 并且我们使用了它的 ResourceProperties 之一(用于所讨论的导航属性)。然后将这三个传递给 GetResourceAssociationSet 调用。因此,您在上面描述的值会让我相信您的元数据设置不正确,但很难从上面确认。 【参考方案1】:

好吧,在我的调试中,我注意到在发生错误之前最后一次调用 GetResourceAssociationSet 是针对 resourceSet 和 resourceType 参数具有不同值的情况(在派生类型的情况下)。

所以,我查看并找到了这个

WCF data services (OData), query with inheritance limitation?

...你瞧,这个无意义的空引用异常(至少在我的情况下)是由同样的问题引起的。我删除了有问题的属性(然后将其移至基础资源集,即使它在实践中不存在),问题已解决。

有趣的附注(如果这有助于原始海报):ResourceType.Properties 包括来自基本类型的属性。不得不更改一些代码来使用 PropertiesDeclaredOnThisType...

【讨论】:

杰夫,您能详细说明您的问题和解决方案吗?我遇到了类似的继承问题(***.com/questions/9182999/…)。另一个类似问题的链接是针对 EF 提供程序的,自定义提供程序是否存在相同的继承限制(仍然)? 是的,即使对于自定义提供程序(如我的)也确实存在。最终,我们放弃了 WCF 数据服务,转而采用更标准的 Web 服务方法。以我的拙见,这是一项很酷的技术,但没有经过深思熟虑或实施。如果您真的希望通过 Web 服务支持 IQueryable,我建议您研究表达式树序列化或通过 rest 传递和解析 LINQ 查询字符串。 感谢 Jeff,我正在为此直接使用 REST Web 服务。【参考方案2】:

我的解决方案是我在 IDataServiceQueryProvider 中实现 GetResourceType 时犯了一个错误。

查询作为 ResourceSetReference 的资源属性时,我返回的是父资源的 ResourceType,而不是相关资源的类型。

【讨论】:

以上是关于自定义 wcf 数据提供者和调试关系错误的主要内容,如果未能解决你的问题,请参考以下文章

哪个更容易,编写自定义 OData uri 解析器或自定义 IQueryable 提供程序?

自托管 WCF 服务和 basicHttpBinding:绑定不提供表示调用者的 Windows 标识

如何在 WCF 服务中实现自定义身份验证

502 badgateway wcf 没有响应

WCF - WCF基本概念和简单WCF服务端创建

C# WCF -- 通过自定义 AuthorizationManager 自定义错误授权失败