我在配置中启用了批处理路由,请参阅下面的代码。
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