C# 当查询结果集末尾有下一页的链接时,为什么ODataFeed.NextPageLink为空?

C# 当查询结果集末尾有下一页的链接时,为什么ODataFeed.NextPageLink为空?,c#,.net,odata,C#,.net,Odata,我在web浏览器中执行了一个查询,每页返回100个结果。这个结果集的末尾有一个,它正确地引导我进入下一页的结果 但是,以下代码使用Microsoft的ODataLib,无法正确填写ODataFeed.NextPageLink,我正在试图理解原因 下面的代码是从我的一个类中提取的单个方法,它只分配一个URI。MyODataHttpRequestMessage类只是HttpWebRequest的包装器,返回响应作为IODataRequestMessage.GetStream的结果,并为其分配Head

我在web浏览器中执行了一个查询,每页返回100个结果。这个结果集的末尾有一个
,它正确地引导我进入下一页的结果

但是,以下代码使用Microsoft的ODataLib,无法正确填写
ODataFeed.NextPageLink
,我正在试图理解原因

下面的代码是从我的一个类中提取的单个方法,它只分配一个URI。My
ODataHttpRequestMessage
类只是
HttpWebRequest
的包装器,返回响应作为
IODataRequestMessage.GetStream的结果,并为其分配
Header
属性

所有其他属性和链接都已正确处理,但未正确处理
ODataFeed.NextPageLink

如何进一步排除故障或解决问题

public void Go()
{
    ODataHttpRequestMessage request = new ODataHttpRequestMessage(this.Url);

    int count = 0;
    using (ODataMessageReader reader = new ODataMessageReader(request))
    {
        ODataReader feedReader = reader.CreateODataFeedReader();

        while (feedReader.Read())
        {
            switch (feedReader.State)
            {
                case ODataReaderState.NavigationLinkEnd:
                    ODataNavigationLink link = feedReader.Item as ODataNavigationLink;
                    break;

                case ODataReaderState.EntryEnd:
                    ODataEntry entry = feedReader.Item as ODataEntry;
                    count++;
                    break;

                case ODataReaderState.FeedEnd:
                    Microsoft.Data.OData.ODataFeed feed = feedReader.Item as Microsoft.Data.OData.ODataFeed;
                    break;
            }
        }
    }
}
以下是ODataHttpRequestMessage的实现:

internal sealed class ODataHttpRequestMessage : IODataRequestMessageAsync
{
    private readonly Uri url;
    private readonly HttpWebRequest request;
    private HttpWebResponse response;

    public Uri Url
    {
        get
        {
            return this.url;
        }

        set
        {
            throw new NotSupportedException("The url may not be changed once the request has been created.");
        }
    }

    public IEnumerable<KeyValuePair<string, string>> Headers
    {
        get
        {
            return this.response.Headers.ToLookup();
        }
    }

    public string Method
    {
        get
        {
            throw new NotImplementedException();
        }

        set
        {
            throw new NotImplementedException();
        }
    }

    public ODataHttpRequestMessage(Uri url)
    {
        this.url = url;
        this.request = HttpWebRequest.CreateHttp(url);
        this.request.Credentials = CredentialCache.DefaultNetworkCredentials;

        this.response = this.request.GetResponse() as HttpWebResponse;
    }

    public string GetHeader(string headerName)
    {
        return this.response.Headers[headerName];
    }

    public void SetHeader(string headerName, string headerValue)
    {
        this.request.Headers[headerName] = headerValue;
    }

    public Stream GetStream()
    {
        Stream stream = response.GetResponseStream();
        return stream;
    }

    public Task<Stream> GetStreamAsync()
    {
        Stream stream = this.GetStream();
        return Task.FromResult<Stream>(stream);
    }
}
内部密封类ODataHttpRequestMessage:IODataRequestMessageAsync
{
私有只读Uri url;
私有只读HttpWebRequest请求;
私有HttpWebResponse;
公共Uri Url
{
得到
{
返回this.url;
}
设置
{
抛出new NotSupportedException(“创建请求后,url可能不会更改。”);
}
}
公共IEnumerable标头
{
得到
{
返回this.response.Headers.ToLookup();
}
}
公共字符串方法
{
得到
{
抛出新的NotImplementedException();
}
设置
{
抛出新的NotImplementedException();
}
}
公共ODataHttpRequestMessage(Uri url)
{
this.url=url;
this.request=HttpWebRequest.CreateHttp(url);
this.request.Credentials=CredentialCache.DefaultNetworkCredentials;
this.response=this.request.GetResponse()作为HttpWebResponse;
}
公共字符串GetHeader(字符串头名称)
{
返回此.response.Headers[headerName];
}
public void SetHeader(字符串headerName、字符串headerValue)
{
this.request.Headers[headerName]=headerValue;
}
公共流GetStream()
{
Stream=response.GetResponseStream();
回流;
}
公共任务GetStreamAsync()
{
Stream=this.GetStream();
返回Task.FromResult(流);
}
}
在有效载荷的末尾,我提到有一个到下一页的链接。 下面是一个最小有效负载,它演示了这一点,也导致了问题:

<?xml version="1.0" encoding="utf-8"?>
<feed xml:base="http://a.b.c.d.e.com/service.svc/" xmlns="http://www.w3.org/2005/Atom" xmlns:d="http://schemas.microsoft.com/ado/2007/08/dataservices" xmlns:m="http://schemas.microsoft.com/ado/2007/08/dataservices/metadata">
    <id>http://a.b.c.d.e.com/Service.svc/Something</id>
    <title type="text">Something</title>
    <updated>2013-11-05T15:55:25Z</updated>
    <link rel="self" title="Something" href="Something" />
    <entry>
        <id>http://a.b.c.d.e.com/service.svc/Something('801b0100-1cee-430c-9767-febc4a4ad1e6')</id>
        <category term="IdentityItem.Something" scheme="http://schemas.microsoft.com/ado/2007/08/dataservices/scheme" />
        <link rel="edit" title="Something" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/MemberOf" type="application/atom+xml;type=feed" title="MemberOf" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/MemberOf" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/UserOwners" type="application/atom+xml;type=feed" title="UserOwners" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/UserOwners" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/ServiceUserOwners" type="application/atom+xml;type=feed" title="ServiceUserOwners" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/ServiceUserOwners" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/MemberUsers" type="application/atom+xml;type=feed" title="MemberUsers" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/MemberUsers" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/MemberServiceUsers" type="application/atom+xml;type=feed" title="MemberServiceUsers" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/MemberServiceUsers" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/MemberTeams" type="application/atom+xml;type=feed" title="MemberTeams" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/MemberTeams" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Children" type="application/atom+xml;type=feed" title="Children" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/Children" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/BusinessRole" type="application/atom+xml;type=entry" title="BusinessRole" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/BusinessRole" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/RoleAssignments" type="application/atom+xml;type=feed" title="RoleAssignments" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/RoleAssignments" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/SuggestedDelegateFor" type="application/atom+xml;type=feed" title="SuggestedDelegateFor" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/SuggestedDelegateFor" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/EscalationSchedules" type="application/atom+xml;type=feed" title="EscalationSchedules" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/EscalationSchedules" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/CommunicationMethods" type="application/atom+xml;type=feed" title="CommunicationMethods" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/CommunicationMethods" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/Parent" type="application/atom+xml;type=entry" title="Parent" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/Parent" />
        <link rel="http://schemas.microsoft.com/ado/2007/08/dataservices/related/PrimaryForUsers" type="application/atom+xml;type=feed" title="PrimaryForUsers" href="Something('801b0100-1cee-430c-9767-febc4a4ad1e6')/PrimaryForUsers" />
        <title />
        <updated>2013-11-05T15:55:25Z</updated>
        <author>
            <name />
        </author>
        <content type="application/xml">
            <m:properties>
                <d:Id>801b0100-1cee-430c-9767-febc4a4ad1e6</d:Id>
                <d:DisplayName>A Great Something</d:DisplayName>
                <d:ParentId>53ec9c58-c882-4a0b-8119-15cc517eee30</d:ParentId>
                <d:ParentNodeType>Something</d:ParentNodeType>
                <d:Tag m:null="true" />
                <d:Name>The name of a something</d:Name>
                <d:Created m:type="Edm.DateTime">2013-03-13T06:14:12Z</d:Created>
                <d:Modified m:type="Edm.DateTime">2013-10-11T03:42:32Z</d:Modified>
                <d:Description m:null="true" />
                <d:Status>Active</d:Status>
                <d:LegacyId m:type="Edm.Int32">2136</d:LegacyId>
                <d:BoundaryNodeType m:null="true" />
                <d:BoundaryNode m:type="IdentityItem.ExternalReference" m:null="true" />
                <d:IsDelegated m:type="Edm.Boolean">false</d:IsDelegated>
                <d:IsAnyRoleAssigned m:type="Edm.Boolean">true</d:IsAnyRoleAssigned>
                <d:Alias>An alias of something</d:Alias>
                <d:Category>Custom</d:Category>
                <d:BoundaryNodeId m:null="true" />
                <d:RelativePath>A relative path to a something</d:RelativePath>
            </m:properties>
        </content>
    </entry>
    <link rel="next" href="http://a.b.c.d.e.com/Service.svc/Something?$top=999900&amp;$skiptoken='19579'" />
</feed>

http://a.b.c.d.e.com/Service.svc/Something
某物
2013-11-05T15:55:25Z
http://a.b.c.d.e.com/service.svc/Something('801b0100-1cee-430c-9767-febc4a4ad1e6')
2013-11-05T15:55:25Z
801b0100-1cee-430c-9767-febc4a4ad1e6
好东西
53ec9c58-c882-4a0b-8119-15cc517eee30
某物
某物的名字
2013-03-13T06:14:12Z
2013-10-11T03:42:32Z
活跃的
2136
假的
真的
某物的别名
习俗
指向某事物的相对路径

您将流视为请求消息而不是响应消息。因为您正在实现一个客户机,所以您将阅读响应和编写请求。请求有效负载不应该有下一个链接(因为请求是从客户端发送到服务器的,服务器永远不会跟随客户端生成的下一个链接),所以ODataLib读取器在读取请求时会忽略它

ODataMessageReader
构造函数可以将
IODataResponseMessage
IODataRequestMessage
的实现作为参数。这决定ODataLib是使用响应还是请求读取规则读取消息

与此相反:

IODataRequestMessageAsync request = new ODataHttpRequestMessage(this.Url);

using (ODataMessageReader reader = new ODataMessageReader(request))
{
   ...
}
您的代码应类似于以下内容:

IODataResponseMessageAsync response = new ODataHttpResponseMessage();

using (ODataMessageReader reader = new ODataMessageReader(response))
{
   ...
}

我没有看到任何明显的错误,但如果这是ODataLib中的一个bug,我会感到惊讶,因为这是一个非常常见的场景。你确定你是在FeedEnd检查而不是FeedStart?为了进一步调试,也许你可以试着简化你的测试负载,使其小而可复制,然后将负载发布到这里?@JenS我继续,并在那里添加了测试负载,它只是一个最初检索到100条记录的查询,但我去掉了下一个99条,保留了链接和提要端,并重写一些属性名称以使其模糊。好的,谢谢。我在下面添加了一个答案。我是黑客,并融合了请求和响应的功能。现在这是有道理的。我会确保它明天早上起作用,并接受解决方案,如果是这样的话,我想它会的。如果我是图书馆的作者,我会做的一件事是,当你访问该财产时抛出一个异常,指示在与请求关联时尝试获取或设置
nextPackageLink
是无效的操作。