Calling an oData Batch using .net HttpClient class

You have full code here, no theory!

Private Async Function SaveEntityAsBatch() 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

‘Required if you need dates serialization

Dim microsoftDateFormatSettings As JsonSerializerSettings = New JsonSerializerSettings With {
.DateFormatHandling = DateFormatHandling.IsoDateFormat,
.DateParseHandling = DateParseHandling.DateTimeOffset, .DateTimeZoneHandling = DateTimeZoneHandling.Utc

‘ Batch Process
Dim boundary As String = “–changeset_Data—”
Dim batchContent As New MultipartContent(“mixed”, “–batch” & boundary)

Dim RqP As New HttpRequestMessage(HttpMethod.Put, “URL(id)/”)
RqP.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(projectRequest, microsoftDateFormatSettings))
If RqP.Content.Headers.Contains(“Content-Type”) Then RqP.Content.Headers.Remove(“Content-Type”)
RqP.Content.Headers.Add(“Content-Type”, “application/json”)
Dim ReqContent As New HttpMessageContent(RqP)
If ReqContent.Headers.Contains(“Content-Type”) Then ProjectContent.Headers.Remove(“Content-Type”)
ReqContent.Headers.Add(“Content-Type”, “application/http”)
ReqContent.Headers.Add(“Content-Transfer-Encoding”, “binary”)
ReqContent.Headers.Add(“client-request-id”, “12345678”)
ReqContent.Headers.Add(“return-client-request-id”, “True”)
ReqContent.Headers.Add(“Content-ID”, “1”)
ReqContent.Headers.Add(“DataServiceVersion”, “3.0”)
If ReqContent.Headers.Contains(“contentTypeMime-Part”) Then ReqContent.Headers.Remove(“contentTypeMime-Part”)
ReqContent.Headers.Add(“contentTypeMime-Part”, “Content-Type:application/http;”)



Dim RqR As New HttpRequestMessage(HttpMethod.Put, “URL2/”, PtsAPIhostUri)
RqR.Content = New StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(report, microsoftDateFormatSettings))
If RqR.Content.Headers.Contains(“Content-Type”) Then RqR.Content.Headers.Remove(“Content-Type”)
RqR.Content.Headers.Add(“Content-Type”, “application/json”)
Dim ReqContent2 As New HttpMessageContent(RqR)

If ReqContent2.Headers.Contains(“Content-Type”) Then ReportContent.Headers.Remove(“Content-Type”)
ReqContent2.Headers.Add(“Content-Type”, “application/http”)
ReqContent2.Headers.Add(“Content-Transfer-Encoding”, “binary”)
ReqContent2.Headers.Add(“client-request-id”, “99999”)
ReqContent2.Headers.Add(“return-client-request-id”, “True”)
ReqContent2.Headers.Add(“Content-ID”, “2”)
ReqContent2.Headers.Add(“DataServiceVersion”, “3.0”)

If ReqContent2.Headers.Contains(“contentTypeMime-Part”) Then ReqContent2.Headers.Remove(“contentTypeMime-Part”)
ReqContent2.Headers.Add(“contentTypeMime-Part”, “Content-Type:application/http;”)
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

End Using
End Function

I got following errors in given sequences and I continued to add the header and finally I was able to two PUT request in Batch.

Error #1

The ‘Content-Type’ header value ‘application/http; msgtype=request’ is invalid. When this is the start of the change set, the value must be ‘multipart/mixed’; otherwise it must be ‘application/http’.

Error #2

The content type ‘multipart/mixed’ specifies a batch payload; however, the payload either does not include a batch boundary or includes more than one boundary. In OData, batch payload content types must specify exactly one batch boundary in the ‘boundary’ parameter of the content type.

Error #3

Nested change sets in a batch payload are not supported.

Error #3 took most of the time to find out this URL from MSDN, which speaks about adding following Header Content Types

ReqContent2.Headers.Add(“client-request-id”, “99999”)
ReqContent2.Headers.Add(“return-client-request-id”, “True”)
ReqContent2.Headers.Add(“Content-ID”, “2”)
ReqContent2.Headers.Add(“DataServiceVersion”, “3.0”)

After adding above four types to header Error #3 was gone and my Batch was working.

The URL from MSDN says;

Add Tasks requests in Batch service support the following concepts:

  • Each request must contain a unique Content-ID MIME part header. This header is returned with the result of the operation in the response, and can be used to match an individual request with its response.
  • The Batch service returns a HTTP Status Code 400 (Bad Request) if any request contains an invalid set of headers or contains operations which are not supported in the batch.
  • The Batch service returns a HTTP Status Code 202 (Accepted) for a valid Add Tasks request. The server will then stream the results of individual operations.
  • The Batch service can re-order the responses of these Add Task requests. The Content-Id MIME part header needs to be used by the Client to match the request corresponding to the response. The response contains the results and error information for each operation.If the server times out or the connection is closed during an Add Tasks request, the request may have been partially or fully processed, or not at all. In such cases, the user should re-issue the request. Note that it is up to the users to correctly deal with failures when re-issuing a request. For example, the users should use the same task names during retry, so that if the prior operation succeeded, the retry will not create extra tasks unexpectedly.
  • An Add Tasks request can include at most 100 operations.
  • All the tasks in an Add Tasks request must belong to the same workitem and job.

One thought on “Calling an oData Batch using .net HttpClient class

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s