Skip to content

Commit 142f4ff

Browse files
author
fenzhao
committed
Issue 1594: DefaultODataBatchHandler doesn't handle urls relative to the
batch endpoint properly. The root cause is that the base uri of ODataMessageReaderSettings doesn't end with slash. The fix is only for v3 and v4 works well for all kinds of urls because ODL v4 will append a slash in the end of the base uri if there isn't one.
1 parent 6c5cc2c commit 142f4ff

File tree

4 files changed

+82
-2
lines changed

4 files changed

+82
-2
lines changed

src/System.Web.Http.OData/OData/Batch/DefaultODataBatchHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public virtual async Task<IList<ODataBatchRequestItem>> ParseBatchRequestsAsync(
110110
{
111111
DisableMessageStreamDisposal = true,
112112
MessageQuotas = MessageQuotas,
113-
BaseUri = GetBaseUri(request)
113+
BaseUri = EnsureTrailingSlash(GetBaseUri(request))
114114
};
115115

116116
ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(oDataReaderSettings, cancellationToken);

src/System.Web.Http.OData/OData/Batch/ODataBatchHandler.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
22

3+
using System.Diagnostics.Contracts;
34
using System.Web.Http.Batch;
45
using Microsoft.Data.OData;
56

@@ -34,5 +35,17 @@ public ODataMessageQuotas MessageQuotas
3435
/// Gets or sets the name of the OData route associated with this batch handler.
3536
/// </summary>
3637
public string ODataRouteName { get; set; }
38+
39+
internal static Uri EnsureTrailingSlash(Uri uri)
40+
{
41+
Contract.Assert(uri != null);
42+
43+
if (!uri.OriginalString.EndsWith("/", StringComparison.Ordinal))
44+
{
45+
return new Uri(uri.OriginalString + "/");
46+
}
47+
48+
return uri;
49+
}
3750
}
3851
}

src/System.Web.Http.OData/OData/Batch/UnbufferedODataBatchHandler.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public override async Task<HttpResponseMessage> ProcessBatchAsync(HttpRequestMes
3838
{
3939
DisableMessageStreamDisposal = true,
4040
MessageQuotas = MessageQuotas,
41-
BaseUri = GetBaseUri(request)
41+
BaseUri = EnsureTrailingSlash(GetBaseUri(request))
4242
};
4343

4444
ODataMessageReader reader = await request.Content.GetODataMessageReaderAsync(oDataReaderSettings, cancellationToken);

test/System.Web.Http.OData.Test/OData/Batch/DefaultODataBatchHandlerTest.cs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,12 @@
66
using System.Net.Http;
77
using System.Net.Http.Headers;
88
using System.Threading;
9+
using System.Web.Http.OData;
910
using System.Web.Http.OData.Batch;
11+
using System.Web.Http.OData.Builder;
12+
using System.Web.Http.OData.Extensions;
1013
using System.Web.Http.Routing;
14+
using Microsoft.Data.Edm;
1115
using Microsoft.TestCommon;
1216

1317
namespace System.Web.Http
@@ -324,5 +328,68 @@ public void ValidateRequest_Throws_IfRequestContentTypeDoesNotHaveBoundary()
324328
Assert.Equal("The batch request must have a boundary specification in the \"Content-Type\" header.",
325329
errorResponse.Response.Content.ReadAsAsync<HttpError>().Result.Message);
326330
}
331+
332+
[Fact]
333+
public void BatchRequest_Works_AbsoluteAndRelativeUri()
334+
{
335+
// Arrange
336+
ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
337+
builder.EntitySet<BatchCustomer>("BatchCustomers");
338+
IEdmModel model = builder.GetEdmModel();
339+
340+
HttpConfiguration configuration = new HttpConfiguration();
341+
HttpServer server = new HttpServer(configuration);
342+
HttpClient client = new HttpClient(server);
343+
configuration.Routes.MapODataServiceRoute("odata", "odata", model, new DefaultODataBatchHandler(server));
344+
345+
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, "http://localhost/odata/$batch");
346+
request.Content = new StringContent(
347+
@"--batch_36522ad7-fc75-4b56-8c71-56071383e77b
348+
Content-Type: application/http
349+
Content-Transfer-Encoding:binary
350+
351+
GET http://localhost/odata/BatchCustomers(5) HTTP/1.1
352+
353+
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
354+
Content-Type: application/http
355+
Content-Transfer-Encoding:binary
356+
357+
GET /odata/BatchCustomers(6) HTTP/1.1
358+
Host: localhost
359+
360+
--batch_36522ad7-fc75-4b56-8c71-56071383e77b
361+
Content-Type: application/http
362+
Content-Transfer-Encoding:binary
363+
364+
GET BatchCustomers(7) HTTP/1.1
365+
366+
--batch_36522ad7-fc75-4b56-8c71-56071383e77b--
367+
");
368+
request.Content.Headers.ContentType =
369+
MediaTypeHeaderValue.Parse("multipart/mixed;boundary=batch_36522ad7-fc75-4b56-8c71-56071383e77b");
370+
371+
// Act
372+
HttpResponseMessage response = client.SendAsync(request).Result;
373+
string responseString = response.Content.ReadAsStringAsync().Result;
374+
375+
// Assert
376+
Assert.Equal(HttpStatusCode.Accepted, response.StatusCode);
377+
Assert.Contains("\"odata.metadata\":\"http://localhost/odata/$metadata#BatchCustomers/@Element\",\"ID\":5", responseString);
378+
Assert.Contains("\"odata.metadata\":\"http://localhost/odata/$metadata#BatchCustomers/@Element\",\"ID\":6", responseString);
379+
Assert.Contains("\"odata.metadata\":\"http://localhost/odata/$metadata#BatchCustomers/@Element\",\"ID\":7", responseString);
380+
}
381+
382+
public class BatchCustomersController : ODataController
383+
{
384+
public IHttpActionResult Get(int key)
385+
{
386+
return Ok(new BatchCustomer { ID = key });
387+
}
388+
}
389+
390+
public class BatchCustomer
391+
{
392+
public int ID { get; set; }
393+
}
327394
}
328395
}

0 commit comments

Comments
 (0)