不支持批处理负载中的嵌套更改集:Odata-asp.net web api 2



我在配置中启用了批处理路由,请参阅下面的代码。

namespace WebAPI {
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services
            // Web API routes
            config.MapHttpAttributeRoutes();
            config.Services.Replace(typeof(IExceptionHandler), new CustomExceptionHandler());
            config.MapODataServiceRoute(routeName: "OData",
                routePrefix: "",
                model: APIConfiguration.GetModel(),
                batchHandler: new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
        }
} } 

我正在使用下面的代码使用http客户端来发布一个批。

Dim batchContent As New MultipartContent("mixed", "--testDataBoundary---")
'Parent
Dim RqP As New HttpRequestMessage(HttpMethod.Put, String.Format("{0}Projects({1})/", APIURI, projectRequest.project.ProjectID))
RqP.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(projectRequest.project, microsoftDateFormatSettings))
Dim ProjectContent As New HttpMessageContent(RqP)
If ProjectContent.Headers.Contains("Content-Type") Then ProjectContent.Headers.Remove("Content-Type")
ProjectContent.Headers.Add("Content-Type", "multipart/mixed; boundary=--testPTDataBoundary---")
'ProjectContent.Headers.Add("Content-Type", "application/http")
ProjectContent.Headers.Add("Content-Transfer-Encoding", "binary")
If ProjectContent.Headers.Contains("contentTypeMime-Part") Then ProjectContent.Headers.Remove("contentTypeMime-Part")
'ProjectContent.Headers.Add("contentTypeMime-Part", "Content-Type:application/http;")
ProjectContent.Headers.Add("contentTypeMime-Part", "Content-Type:multipart/mixed;")
batchContent.Add(ProjectContent)
'Child1
Dim report As Report = projectRequest.project.Reports.Take(1).First()
Dim RqR As New HttpRequestMessage(HttpMethod.Put, String.Format("{0}Reports({1})/", APIURI, report.ReportID))
RqR.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(report, microsoftDateFormatSettings))
Dim ReportContent As New HttpMessageContent(RqR)
If ReportContent.Headers.Contains("Content-Type") Then ReportContent.Headers.Remove("Content-Type")
ReportContent.Headers.Add("Content-Type", "multipart/mixed; boundary=--testPTDataBoundary---")
'ReportContent.Headers.Add("Content-Type", "application/http")
ReportContent.Headers.Add("Content-Transfer-Encoding", "binary")
If ReportContent.Headers.Contains("contentTypeMime-Part") Then ReportContent.Headers.Remove("contentTypeMime-Part")
'ReportContent.Headers.Add("contentTypeMime-Part", "Content-Type:application/http;")
ReportContent.Headers.Add("contentTypeMime-Part", "Content-Type:multipart/mixed;")
batchContent.Add(ReportContent)

Dim batchRequest As HttpRequestMessage = New HttpRequestMessage(HttpMethod.Post, APIURI& "/$batch/")
batchRequest.Content = batchContent
Dim APIResponseBatch = Await Client.SendAsync(batchRequest)
Dim streamProvider = APIResponseBatch.Content.ReadAsMultipartAsync().Result()
For Each cnt As HttpContent In streamProvider.Contents
  lblErrorMsg.Text &= cnt.ReadAsStringAsync().Result
Next

最初,我得到了以下异常,然后我将contentTypeMimePart添加到批处理的每个请求中。

找到丢失或无效的"内容传输编码"标头。必须为每个批处理操作指定"内容传输编码"标头,其值必须为"二进制"

我能够在一个批次中加入多个GET,并且正在为所有请求提取数据。但对于帖子(在我的情况下是父母和孩子),我得到了以下的解释;

不支持批处理负载中的嵌套更改集

这是对使用asp.net web API2的oData的限制,还是我在这里遗漏了什么?

我终于解决了这个问题。

下面给出的序列中有以下错误,我继续添加标头,最终我能够在Batch中发出两个PUT请求。

错误1

"内容类型"头值应用程序http;msgtype=request'无效。当这是更改集的开始时,值必须是"multipart/mixed";否则必须是"application/http"。

错误2

内容类型"multipart/mixed"指定了一个批处理负载;但是,该负载不包括批处理边界或包括多个边界。在OData中,批处理负载内容类型必须在内容类型的"boundary"参数中仅指定一个批处边界。

错误3

不支持批处理负载中的嵌套更改集。

错误3花了大部分时间从MSDN中找到这个URL,这说明添加了以下标题内容类型

客户端请求id

返回客户端请求id

内容ID

DataServiceVersion

在将以上四种类型添加到标题后,错误#3消失了,我的批次正在工作。

MSDN的URL上写着:;

在批处理服务中添加任务请求支持以下概念:

每个请求都必须包含一个唯一的Content-ID MIME部分标头。此标头与响应中的操作结果一起返回,可用于将单个请求与其响应进行匹配。

如果任何请求包含无效的标头集或包含批处理中不支持的操作,则批处理服务将返回HTTP状态代码400(错误请求)。

批处理服务为有效的添加任务请求返回HTTP状态代码202(已接受)。然后,服务器将对各个操作的结果进行流式传输。

批处理服务可以重新排序这些"添加任务"请求的响应。客户端需要使用Content-Id-MIME部分标头来匹配与响应对应的请求。响应包含每个操作的结果和错误信息。如果在"添加任务"请求期间服务器超时或连接关闭,则该请求可能已被部分或全部处理,或者根本没有处理。在这种情况下,用户应该重新发出请求。请注意,在重新发出请求时,正确处理故障取决于用户。例如,用户在重试过程中应使用相同的任务名称,这样,如果上一次操作成功,则重试不会意外创建额外的任务。

添加任务请求最多可包含100个操作

添加任务请求中的所有任务必须属于同一工作项和

代码

Private Async Function SaveProjectAsBatch() As Threading.Tasks.Task
        Using Client As New HttpClient()
            Dim APIhostUri As String = "http://localhost:2025/"
            Dim APIResponse As HttpResponseMessage
            Client.BaseAddress = New Uri(APIhostUri)
            Dim content As HttpContent
            'If date serialization is required              
            Dim microsoftDateFormatSettings As JsonSerializerSettings = New JsonSerializerSettings With {
                                .DateFormatHandling = DateFormatHandling.IsoDateFormat,
                                .DateParseHandling = DateParseHandling.DateTimeOffset, .DateTimeZoneHandling = DateTimeZoneHandling.Utc
                                }
            ' Batch Process
            Dim boundary As String = "--changeset_ProjectData"
            Dim batchContent As New MultipartContent("mixed", "--batch" & boundary)
            'request 1
            Dim RqP As New HttpRequestMessage(HttpMethod.Put, "Url1(key)/")
            RqP.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(RequestContent, microsoftDateFormatSettings))
            If RqP.Content.Headers.Contains("Content-Type") Then RqP.Content.Headers.Remove("Content-Type")
            RqP.Content.Headers.Add("Content-Type", "application/json")
            Dim Request1 As New HttpMessageContent(RqP)
            If Request1.Headers.Contains("Content-Type") Then Request1.Headers.Remove("Content-Type")
            Request1.Headers.Add("Content-Type", "application/http")
            Request1.Headers.Add("Content-Transfer-Encoding", "binary")
            Request1.Headers.Add("client-request-id", "12345678")
            Request1.Headers.Add("return-client-request-id", "True")
            Request1.Headers.Add("Content-ID", "1")
            Request1.Headers.Add("DataServiceVersion", "3.0")
            If Request1.Headers.Contains("contentTypeMime-Part") Then Request1.Headers.Remove("contentTypeMime-Part")
            Request1.Headers.Add("contentTypeMime-Part", "Content-Type:application/http;")
            batchContent.Add(Request1)
            'request 2
            Dim RqR As New HttpRequestMessage(HttpMethod.Put, "Url2(Key)/")
            RqP.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(Request1Content, microsoftDateFormatSettings))
            If RqR.Content.Headers.Contains("Content-Type") Then RqR.Content.Headers.Remove("Content-Type")
            RqR.Content.Headers.Add("Content-Type", "application/json")
            Dim Request2 As New HttpMessageContent(RqR)
            If Request2.Headers.Contains("Content-Type") Then Request2.Headers.Remove("Content-Type")
            Request2.Headers.Add("Content-Type", "application/http")
            Request2.Headers.Add("Content-Transfer-Encoding", "binary")
            Request2.Headers.Add("client-request-id", "99999")
            Request2.Headers.Add("return-client-request-id", "True")
            Request2.Headers.Add("Content-ID", "2")
            Request2.Headers.Add("DataServiceVersion", "3.0")
            If Request2.Headers.Contains("contentTypeMime-Part") Then Request2.Headers.Remove("contentTypeMime-Part")
            Request2.Headers.Add("contentTypeMime-Part", "Content-Type:application/http;")
            batchContent.Add(Request2)

            Dim batchRequest As HttpRequestMessage = New HttpRequestMessage(HttpMethod.Post, APIhostUri & "/$batch/")
            batchRequest.Content = batchContent

            Dim APIResponseBatch = Await Client.SendAsync(batchRequest)
            Dim streamProvider = APIResponseBatch.Content.ReadAsMultipartAsync().Result()
            For Each cnt As HttpContent In streamProvider.Contents
                Console.WriteLine(cnt.ReadAsStringAsync().Result)
            Next
        End Using
    End Function

最新更新