Last active
December 15, 2015 23:18
-
-
Save raghuramn/5338853 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public class AsyncQueryableAttribute : ActionFilterAttribute | |
{ | |
private static readonly MethodInfo _bufferAsync = typeof(AsyncQueryableAttribute).GetMethod("BufferAsyncCore", BindingFlags.NonPublic | BindingFlags.Static); | |
private readonly QueryableAttribute _innerFilter = new QueryableAttribute(); | |
// this method is copied from ActionFilterAttribute | |
public async Task<HttpResponseMessage> ExecuteActionFilterAsync( | |
HttpActionContext actionContext, | |
CancellationToken cancellationToken, | |
Func<Task<HttpResponseMessage>> continuation) | |
{ | |
cancellationToken.ThrowIfCancellationRequested(); | |
HttpResponseMessage response = null; | |
Exception exception = null; | |
try | |
{ | |
response = await continuation(); | |
} | |
catch (Exception e) | |
{ | |
exception = e; | |
} | |
try | |
{ | |
HttpActionExecutedContext executedContext = new HttpActionExecutedContext(actionContext, exception) { Response = response }; | |
_innerFilter.OnActionExecuted(executedContext); | |
if (executedContext.Response != null) | |
{ | |
return await BufferAsyncQueryable(executedContext.Response); | |
} | |
if (executedContext.Exception != null) | |
{ | |
throw executedContext.Exception; | |
} | |
} | |
catch | |
{ | |
// Catch is running because OnActionExecuted threw an exception, so we just want to re-throw the exception. | |
// We also need to reset the response to forget about it since a filter threw an exception. | |
actionContext.Response = null; | |
throw; | |
} | |
throw new NotSupportedException("InnerFilter must set either Response or Exception. Both are null."); | |
} | |
// Executes the queryable eagerly and asynchronously if it implements IDbAsyncEnumerable. | |
// Note that this would call ToListAsync and would load the entire result set into memory. | |
private async Task<HttpResponseMessage> BufferAsyncQueryable(HttpResponseMessage response) | |
{ | |
ObjectContent objectContent = response.Content as ObjectContent; | |
if (response.IsSuccessStatusCode && objectContent != null) | |
{ | |
IQueryable queryable = objectContent.Value as IQueryable; | |
if (queryable != null && queryable is IDbAsyncEnumerable) | |
{ | |
objectContent.Value = await BufferAsync(queryable); | |
} | |
} | |
return response; | |
} | |
private static Task<IQueryable> BufferAsync(IQueryable input) | |
{ | |
MethodInfo bufferAsync = _bufferAsync.MakeGenericMethod(input.ElementType); | |
return bufferAsync.Invoke(null, new[] { input }) as Task<IQueryable>; | |
} | |
// called using reflection. | |
private static async Task<IQueryable> BufferAsyncCore<T>(IQueryable<T> input) | |
{ | |
var list = await input.ToListAsync(); | |
return list.AsQueryable(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment