0

从六月到今天,我一直在使用夜间构建。我写了一个批处理程序来解析我的请求,它正在工作。更新后,对于 $batch 端点的原始 POST 调用 myParseBatchRequestsAsync一次,然后收到一条消息“批处理请求必须具有 'multipart/mixed' 作为媒体类型。”

然后,当我在处理程序中为该方法添加一个覆盖ProcessBatchAsync,并在我的原始项目中使用 June nightly 构建设置中断时,我看到这个方法只调用了一次,然后调用了解析例程,一切都成功了。

当我在 7 月版本中执行此操作时,我看到ProcessBatchAsync调用了一次原始 POST 到 $batch,然后是解析,返回子请求。当子请求被执行时,我看到另一个调用ProcessBatchAsync,它命中验证例程并失败,因为子请求不是批处理,而是对实体端点的创建/更改请求。

到目前为止,我可以提供以下内容:

我的批处理程序看起来像:

Imports System.Web.Http
Imports System.Web.Http.OData
Imports System.Web.Http.OData.Batch
Imports System.Net.Http
Imports Microsoft.Data.OData

Imports System.Collections.Generic
Imports System.Diagnostics.CodeAnalysis
Imports System.Threading
Imports System.Threading.Tasks
Imports System.Web.Http.Batch


Public Class CustomODataBatchHandler
    Inherits DefaultODataBatchHandler


    Public Sub New(ByVal server As HttpServer)
        MyBase.New(server)
    End Sub


Public Overrides Async Function ParseBatchRequestsAsync(request As HttpRequestMessage, ByVal cancel As CancellationToken) As Threading.Tasks.Task(Of IList(Of ODataBatchRequestItem))


    If request Is Nothing Then Throw New HttpException(400, "Bad Request")

    Dim oDataReaderSettings As ODataMessageReaderSettings = New ODataMessageReaderSettings With {.DisableMessageStreamDisposal = True, .MessageQuotas = MessageQuotas, .BaseUri = GetBaseUri(request)}
    Dim reader As ODataMessageReader = Await request.Content.GetODataMessageReaderAsync(oDataReaderSettings)
    request.RegisterForDispose(reader)

    Dim requests As List(Of ODataBatchRequestItem) = New List(Of ODataBatchRequestItem)
    Dim batchReader As ODataBatchReader = reader.CreateODataBatchReader()
    Dim batchId As Guid = Guid.NewGuid()
    Do While (batchReader.Read())

        If batchReader.State = ODataBatchReaderState.ChangesetStart Then
            Dim changeSetRequests As IList(Of HttpRequestMessage) = Await batchReader.ReadChangeSetRequestAsync(batchId)
            For Each changeSetRequest As HttpRequestMessage In changeSetRequests
                changeSetRequest.CopyBatchRequestProperties(request)
                Dim originalURI As Uri = changeSetRequest.RequestUri
                Dim reg As New System.Text.RegularExpressions.Regex("\/\$[0-9]+\/")
                If originalURI.IsAbsoluteUri And reg.IsMatch(originalURI.ToString) Then
                    'original URI has a content id in it. replce base uri.
                    Dim newURI As New Uri(originalURI.ToString.Replace(Me.GetBaseUri(request).ToString, ""), UriKind.Relative)
                    changeSetRequest.RequestUri = newURI
                End If

            Next

            requests.Add(New ChangeSetRequestItem(changeSetRequests))

        ElseIf batchReader.State = ODataBatchReaderState.Operation Then

            Dim operationRequest As HttpRequestMessage = Await batchReader.ReadOperationRequestAsync(batchId, bufferContentStream:=True)
            operationRequest.CopyBatchRequestProperties(request)
            requests.Add(New OperationRequestItem(operationRequest))
        End If
    Loop

    Return requests
End Function



End Class

这基本上是将源转换为 vb.net,并添加了内容 id 处理的替换,这似乎解决了我遇到的相对 uri 的问题。

此处理程序在我的 webapiconfig.vb 中实现如下: config.Routes.MapODataRoute("odata", "odata", nm.GetEdmModel, New DefaultODataPathHandler, routingConventions, New CustomODataBatchHandler(GlobalConfiguration.DefaultServer))

如果我更改请求只是一次提交一个请求,则会调用控制器并完成处理,因此它必须是批处理中的某些内容,可能是我做错了。

更新2013 年 7 月 16 日 更改为 DefaultODataBatchHandler 并观察客户端的异常情况,我看到请求被拒绝:“批处理请求必须具有 'multipart/mixed' 作为媒体类型。”

当我观察 WCF 数据服务客户端构建请求时,$batch 的 POST 具有以下标头:

DataServiceVersion: 1.0;NetFx
MaxDataServiceVersion: 3.0;NetFx
Content-Type: multipart/mixed; boundary=batch_7b1d426d-dc36-4a6d-9d3d-be2b64b90d38
Accept: multipart/mixed
Accept-Charset: UTF-8
User-Agent: Microsoft ADO.NET Data Services

我尝试将其设置回我的处理程序,并且可以看到请求已被解析并作为更改集返回。然后在调用我的控制器之前,在处理程序中的某处将相同的媒体类型错误返回给我的客户端。

更新 2 我获取了源代码DefaultODataBatchHandler并将其用作自定义批处理处理程序,而无需更改代码。逐步进行,我看到 $batch 的第一个 POST 解析很好,并通过了验证。当子请求的更改集传递给ExecuteRequestMessagesAsync然后responses.Add(await request.SendRequestAsync(Invoker, cancellationToken));被调用时,ProcessBatchRequest再次触发并尝试处理子请求而不是允许它由控制器处理。这再次进入验证和解析例程,但由于这不再是批处理请求而失败,并且内容类型现在是 XML,因为它是实际实体。

为了使用 Nightly 构建,我删除了所有我能找到的为 MVC、WebAPI、OData 等安装的东西,然后安装了所有的 nightly 包。我想包括这个,以防它是其他原因造成的。

更新 3 我在原始项目的原始自定义批处理处理程序中覆盖了 ProcessBatchAsync 方法,并且可以确认 ProcessBatchAsync ws 仅在工作时调用一次。在当前的夜间构建中,似乎为原始请求和子请求调用了 ProcessBatchAsync。我无法确认这是否仅发生在这个项目中,或者还发生在一个新项目中。

UPDATE 4 Repro here:批量问题 Repro

谢谢!

史蒂夫

4

0 回答 0