Skip to content

Commit

Permalink
- Reduced allocations on the RestierControllers and RestierOperationE…
Browse files Browse the repository at this point in the history
…xecutor

- Improved consistency between the different RestierController versions.
- Improved unit tests.
  • Loading branch information
robertmclaws committed Oct 30, 2023
1 parent 4f1d3c8 commit 3ccea9e
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 195 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public async Task<IQueryable> ExecuteOperationAsync(OperationContext context, Ca
{
Ensure.NotNull(context, nameof(context));

if (!(context is RestierOperationContext restierOperationContext))
if (context is not RestierOperationContext restierOperationContext)
{
throw new NotImplementedException(string.Format(CultureInfo.InvariantCulture, AspNetResources.NoSupportedOperationContext, context.GetType()));
}
Expand Down Expand Up @@ -109,13 +109,13 @@ public async Task<IQueryable> ExecuteOperationAsync(OperationContext context, Ca
var parameter = parameterArray[paraIndex];
var currentParameterValue = restierOperationContext.GetParameterValueFunc(parameter.Name);

object convertedValue = null;
object convertedValue;
if (restierOperationContext.IsFunction)
{
var parameterTypeRef = parameter.ParameterType.GetTypeReference(model);

// Change to right CLR class for collection/Enum/Complex/Entity
// JWS: As long as OData requires the ServiceProvder, we have to provide it. DI abuse smell.
// JWS: As long as OData requires the ServiceProvider, we have to provide it. DI abuse smell.
convertedValue = DeserializationHelpers.ConvertValue(
currentParameterValue,
parameter.Name,
Expand All @@ -136,12 +136,13 @@ public async Task<IQueryable> ExecuteOperationAsync(OperationContext context, Ca

restierOperationContext.ParameterValues = parameters;

// Invoke preprocessing on the operation execution
// RWM: Invoke pre-operation processing.
await PerformPreEvent(restierOperationContext, cancellationToken).ConfigureAwait(false);

// RWM: Invoke the operation.
var result = await InvokeOperation(restierOperationContext.Api, method, parameters, model).ConfigureAwait(false);

// Invoke preprocessing on the operation execution
// Invoke post-operation processing.
await PerformPostEvent(restierOperationContext, cancellationToken).ConfigureAwait(false);
return result;
}
Expand All @@ -153,13 +154,8 @@ private static object PrepareBindingParameter(Type bindingType, IEnumerable bind
// This means binding to a single entity
if (enumerableType is null)
{
var entity = bindingParameterValue.SingleOrDefault();
if (entity is null)
{
throw new StatusCodeException(HttpStatusCode.NotFound, Resources.ResourceNotFound);
}

return entity;
return bindingParameterValue.SingleOrDefault() ??
throw new StatusCodeException(HttpStatusCode.NotFound, AspNetResources.ResourceNotFound);
}

// This means function is bound to an entity set.
Expand All @@ -171,16 +167,14 @@ private static object PrepareBindingParameter(Type bindingType, IEnumerable bind
{
var toArrayMethodInfo = ExpressionHelperMethods.EnumerableToArrayGeneric
.MakeGenericMethod(elementClrType);
var arrayResult = toArrayMethodInfo.Invoke(null, new object[] { bindingParameterValue });
return arrayResult;
return toArrayMethodInfo.Invoke(null, new object[] { bindingParameterValue });
}

if (bindingType.FindGenericType(typeof(ICollection<>)) is not null)
{
var toListMethodInfo = ExpressionHelperMethods.EnumerableToListGeneric
.MakeGenericMethod(elementClrType);
var listResult = toListMethodInfo.Invoke(null, new object[] { bindingParameterValue });
return listResult;
return toListMethodInfo.Invoke(null, new object[] { bindingParameterValue });
}

return bindingParameterValue;
Expand All @@ -199,16 +193,14 @@ private static async Task<IQueryable> InvokeOperation(
if (result is Task task)
{
await task.ConfigureAwait(false);
if (returnType.GenericTypeArguments.Any())
{
returnType = returnType.GenericTypeArguments.First();
var resultProperty = typeof(Task<>).MakeGenericType(returnType).GetProperty("Result");
result = resultProperty.GetValue(task);
}
else

if (!returnType.GenericTypeArguments.Any())
{
return null;
}

returnType = returnType.GenericTypeArguments.First();
result = typeof(Task<>).MakeGenericType(returnType).GetProperty("Result").GetValue(task);
}

var edmReturnType = returnType.GetReturnTypeReference(model);
Expand All @@ -220,8 +212,7 @@ private static async Task<IQueryable> InvokeOperation(
return ExpressionHelpers.CreateEmptyQueryable(elementClrType);
}

var enumerableType = result.GetType().FindGenericType(typeof(IEnumerable<>));
if (enumerableType is not null)
if (result.GetType().FindGenericType(typeof(IEnumerable<>)) is not null)
{
return ((IEnumerable)result).AsQueryable();
}
Expand All @@ -235,9 +226,8 @@ private static async Task<IQueryable> InvokeOperation(
var objectQueryable = new[] { result }.AsQueryable();
var castMethodInfo = typeof(Enumerable).GetMethod("Cast").MakeGenericMethod(returnType);
var castedResult = castMethodInfo.Invoke(null, new object[] { objectQueryable });
var typedQueryable = ExpressionHelperMethods.QueryableAsQueryable.Invoke(null, new object[] { castedResult }) as IQueryable;

return typedQueryable;
return ExpressionHelperMethods.QueryableAsQueryable.Invoke(null, new object[] { castedResult }) as IQueryable;
}

private async Task InvokeAuthorizers(OperationContext context, CancellationToken cancellationToken)
Expand Down
Loading

0 comments on commit 3ccea9e

Please sign in to comment.