Skip to content

Commit ec3166d

Browse files
committed
Fix behaviour on status code requests.
1 parent 13938e8 commit ec3166d

File tree

2 files changed

+113
-40
lines changed

2 files changed

+113
-40
lines changed

src/Microsoft.AspNetCore.OData/EnableQueryAttribute.cs

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ public override void OnActionExecuting(ActionExecutingContext context)
140140
{
141141
elementType = TypeHelper.GetImplementedIEnumerableType(returnType);
142142
}
143-
else if(TypeHelper.IsGenericType(returnType) && returnType.GetGenericTypeDefinition() == typeof(Task<>))
143+
else if (TypeHelper.IsGenericType(returnType) && returnType.GetGenericTypeDefinition() == typeof(Task<>))
144144
{
145145
elementType = returnType.GetGenericArguments().First();
146146
}
@@ -228,46 +228,44 @@ public override void OnActionExecuted(ActionExecutedContext actionExecutedContex
228228
{
229229
// actionExecutedContext.Result might also indicate a status code that has not yet
230230
// been applied to the result; make sure it's also successful.
231-
StatusCodeResult statusCodeResult = actionExecutedContext.Result as StatusCodeResult;
232-
if (statusCodeResult == null || IsSuccessStatusCode(statusCodeResult.StatusCode))
231+
ObjectResult responseContent = actionExecutedContext.Result as ObjectResult;
232+
233+
if (responseContent != null && (responseContent.StatusCode == null || IsSuccessStatusCode(responseContent.StatusCode.Value)))
233234
{
234-
ObjectResult responseContent = actionExecutedContext.Result as ObjectResult;
235-
if (responseContent != null)
235+
236+
//throw Error.Argument("actionExecutedContext", SRResources.QueryingRequiresObjectContent,
237+
// actionExecutedContext.Result.GetType().FullName);
238+
239+
// Get collection from SingleResult.
240+
IQueryable singleResultCollection = null;
241+
SingleResult singleResult = responseContent.Value as SingleResult;
242+
if (singleResult != null)
243+
{
244+
// This could be a SingleResult, which has the property Queryable.
245+
// But it could be a SingleResult() or SingleResult<T>. Sort by number of parameters
246+
// on the property and get the one with the most parameters.
247+
PropertyInfo propInfo = responseContent.Value.GetType().GetProperties()
248+
.OrderBy(p => p.GetIndexParameters().Count())
249+
.Where(p => p.Name.Equals("Queryable"))
250+
.LastOrDefault();
251+
252+
singleResultCollection = propInfo.GetValue(singleResult) as IQueryable;
253+
}
254+
255+
// Execution the action.
256+
object queryResult = OnActionExecuted(
257+
responseContent.Value,
258+
singleResultCollection,
259+
new WebApiActionDescriptor(actionDescriptor as ControllerActionDescriptor),
260+
new WebApiRequestMessage(request),
261+
(elementClrType) => GetModel(elementClrType, request, actionDescriptor),
262+
(queryContext) => CreateAndValidateQueryOptions(request, queryContext),
263+
(statusCode) => actionExecutedContext.Result = new StatusCodeResult((int)statusCode),
264+
(statusCode, message, exception) => actionExecutedContext.Result = CreateBadRequestResult(message, exception));
265+
266+
if (queryResult != null)
236267
{
237-
//throw Error.Argument("actionExecutedContext", SRResources.QueryingRequiresObjectContent,
238-
// actionExecutedContext.Result.GetType().FullName);
239-
240-
// Get collection from SingleResult.
241-
IQueryable singleResultCollection = null;
242-
SingleResult singleResult = responseContent.Value as SingleResult;
243-
if (singleResult != null)
244-
{
245-
// This could be a SingleResult, which has the property Queryable.
246-
// But it could be a SingleResult() or SingleResult<T>. Sort by number of parameters
247-
// on the property and get the one with the most parameters.
248-
PropertyInfo propInfo = responseContent.Value.GetType().GetProperties()
249-
.OrderBy(p => p.GetIndexParameters().Count())
250-
.Where(p => p.Name.Equals("Queryable"))
251-
.LastOrDefault();
252-
253-
singleResultCollection = propInfo.GetValue(singleResult) as IQueryable;
254-
}
255-
256-
// Execution the action.
257-
object queryResult = OnActionExecuted(
258-
responseContent.Value,
259-
singleResultCollection,
260-
new WebApiActionDescriptor(actionDescriptor as ControllerActionDescriptor),
261-
new WebApiRequestMessage(request),
262-
(elementClrType) => GetModel(elementClrType, request, actionDescriptor),
263-
(queryContext) => CreateAndValidateQueryOptions(request, queryContext),
264-
(statusCode) => actionExecutedContext.Result = new StatusCodeResult((int)statusCode),
265-
(statusCode, message, exception) => actionExecutedContext.Result = CreateBadRequestResult(message, exception));
266-
267-
if (queryResult != null)
268-
{
269-
responseContent.Value = queryResult;
270-
}
268+
responseContent.Value = queryResult;
271269
}
272270
}
273271
}

test/UnitTest/Microsoft.AspNet.OData.Test.Shared/Query/EnableQueryAttributeTest.cs

Lines changed: 76 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,25 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
#if NETCORE
5+
using System;
56
using System.Collections.Generic;
67
using System.Collections.ObjectModel;
8+
using System.Linq;
9+
using Microsoft.AspNet.OData.Extensions;
710
using Microsoft.AspNet.OData.Query;
11+
using Microsoft.AspNet.OData.Routing;
12+
using Microsoft.AspNet.OData.Test.Abstraction;
813
using Microsoft.AspNet.OData.Test.Common;
914
using Microsoft.AspNet.OData.Test.Common.Models;
1015
using Microsoft.AspNet.OData.Test.Query.Controllers;
16+
using Microsoft.AspNetCore.Http;
17+
using Microsoft.AspNetCore.Mvc;
18+
using Microsoft.AspNetCore.Mvc.Abstractions;
19+
using Microsoft.AspNetCore.Mvc.Filters;
20+
using Microsoft.AspNetCore.Routing;
21+
using Microsoft.Extensions.DependencyInjection;
22+
using Microsoft.OData;
23+
using Microsoft.OData.Edm;
1124
using Xunit;
1225
#else
1326
using System;
@@ -254,8 +267,70 @@ public void OnActionExecuted_Throws_Null_Context()
254267
{
255268
ExceptionAssert.ThrowsArgumentNull(() => new EnableQueryAttribute().OnActionExecuted(null), "actionExecutedContext");
256269
}
257-
258270
#if NETCORE // Following functionality is only supported in NetCore.
271+
[Fact]
272+
public void OnActionExecuted_HandlesStatusCodesCorrectly()
273+
{
274+
// Arrange
275+
HttpContext httpContext = new DefaultHttpContext();
276+
httpContext.Request.Method = "Get";
277+
ActionDescriptor actionDescriptor = new ActionDescriptor();
278+
ActionContext actionContext = new ActionContext(httpContext, new RouteData(), actionDescriptor);
279+
280+
ActionExecutedContext context = new ActionExecutedContext(actionContext, new List<IFilterMetadata>(), "someController");
281+
context.Result = new ObjectResult(new { Error = "Error", Message = "Message" }) { StatusCode = 500 };
282+
283+
EnableQueryAttribute attribute = new EnableQueryAttribute();
284+
285+
// Act and Assert
286+
ExceptionAssert.DoesNotThrow(() => attribute.OnActionExecuted(context));
287+
}
288+
289+
[Fact]
290+
public void OnActionExecuted_HandlesRequestsNormally()
291+
{
292+
// Arrange
293+
var routeName = "odata";
294+
IEdmModel model = new CustomersModelWithInheritance().Model;
295+
var configuration = RoutingConfigurationFactory.Create();
296+
297+
configuration.Filter();
298+
299+
var request = RequestFactory.CreateFromModel(model, "http://localhost/odata/Customers?$filter=Id eq 1", routeName, new ODataPath());
300+
301+
IServiceProvider serviceProvider = GetServiceProvider(configuration, model, routeName);
302+
request.ODataFeature().RequestContainer = serviceProvider;
303+
HttpContext httpContext = request.HttpContext;
304+
httpContext.RequestServices = serviceProvider;
305+
306+
ActionDescriptor actionDescriptor = ControllerDescriptorFactory
307+
.Create(configuration, "CustomersController", typeof(CustomersController))
308+
.First(descriptor => descriptor.ActionName.StartsWith("Get", StringComparison.OrdinalIgnoreCase));
309+
ActionContext actionContext = new ActionContext(httpContext, new RouteData(), actionDescriptor);
310+
311+
ActionExecutedContext context = new ActionExecutedContext(actionContext, new List<IFilterMetadata>(), new CustomersController());
312+
context.Result = new ObjectResult(new List<Customer>()) { StatusCode = 200 };
313+
314+
EnableQueryAttribute attribute = new EnableQueryAttribute();
315+
316+
// Act and Assert
317+
ExceptionAssert.DoesNotThrow(() => attribute.OnActionExecuted(context));
318+
319+
Assert.NotNull(context.Result as ObjectResult);
320+
}
321+
322+
private IServiceProvider GetServiceProvider(IRouteBuilder builder, IEdmModel model, string routeName)
323+
{
324+
IPerRouteContainer perRouteContainer = builder.ServiceProvider.GetRequiredService<IPerRouteContainer>();
325+
326+
// Create an service provider for this route. Add the default services to the custom configuration actions.
327+
Action<IContainerBuilder> builderAction = ODataRouteBuilderExtensions.ConfigureDefaultServices(builder, b =>
328+
{
329+
b.AddService(Microsoft.OData.ServiceLifetime.Singleton, sp => model);
330+
});
331+
return perRouteContainer.CreateODataRootContainer(routeName, builderAction);
332+
}
333+
259334
[Fact]
260335
public void OnActionExecuting_Throws_Null_Context()
261336
{

0 commit comments

Comments
 (0)