/// <inheritdoc /> public async Task <QueryResult> ApplyAndExecuteAsync(IQueryable queryable, string queryString, CancellationToken cancellationToken = default(CancellationToken)) { cancellationToken.ThrowIfCancellationRequested(); var entityQuery = new EntityQuery(queryString); var elementType = TypeFns.GetElementType(queryable.GetType()); entityQuery.Validate(elementType, _entityMetadataProvider); int?inlineCount = null; queryable = entityQuery.ApplyWhere(queryable, elementType); if (entityQuery.IsInlineCountEnabled) { inlineCount = (int)Queryable.Count((dynamic)queryable); } queryable = EntityQuery.ApplyCustomLogic?.Invoke(entityQuery, queryable, elementType) ?? queryable; queryable = entityQuery.ApplyOrderBy(queryable, elementType); queryable = entityQuery.ApplySkip(queryable, elementType); queryable = entityQuery.ApplyTake(queryable, elementType); queryable = entityQuery.ApplySelect(queryable, elementType); queryable = ApplyExpand(queryable, entityQuery, elementType, out var postExecuteExpandPaths); var listResult = await(ToListAsync((dynamic)queryable, cancellationToken)).ConfigureAwait(false); if (postExecuteExpandPaths?.Count > 0) { _proxyInitializer.Initialize(listResult, postExecuteExpandPaths); } listResult = EntityQuery.AfterExecution?.Invoke(entityQuery, queryable, listResult) ?? listResult; return(new QueryResult(listResult, inlineCount)); }
/// <inheritdoc /> public QueryResult ApplyAndExecute(IQueryable queryable, string queryString) { var entityQuery = new EntityQuery(queryString); var elementType = TypeFns.GetElementType(queryable.GetType()); entityQuery.Validate(elementType, _entityMetadataProvider); int?inlineCount = null; queryable = entityQuery.ApplyWhere(queryable, elementType); if (entityQuery.IsInlineCountEnabled) { inlineCount = (int)Queryable.Count((dynamic)queryable); } queryable = EntityQuery.ApplyCustomLogic?.Invoke(entityQuery, queryable, elementType) ?? queryable; queryable = entityQuery.ApplyOrderBy(queryable, elementType); queryable = entityQuery.ApplySkip(queryable, elementType); queryable = entityQuery.ApplyTake(queryable, elementType); queryable = entityQuery.ApplySelect(queryable, elementType); queryable = ApplyExpand(queryable, entityQuery, elementType, out var postExecuteExpandPaths); var listResult = ToList((dynamic)queryable); if (postExecuteExpandPaths?.Count > 0) { _proxyInitializer.Initialize(listResult, postExecuteExpandPaths); } listResult = EntityQuery.AfterExecution?.Invoke(entityQuery, queryable, listResult) ?? listResult; return(new QueryResult(listResult, inlineCount)); }
/// <summary> /// Apply the select clause to the queryable /// </summary> /// <param name="queryable"></param> /// <param name="selectQueryString"></param> /// <returns></returns> public virtual IQueryable ApplySelect(IQueryable queryable, string selectQueryString) { var selectClauses = selectQueryString.Split(',').Select(sc => sc.Replace('/', '.')).ToList(); var elementType = TypeFns.GetElementType(queryable.GetType()); var func = QueryBuilder.BuildSelectFunc(elementType, selectClauses); return(func(queryable)); }
public override void OnActionExecuted(ActionExecutedContext context) { var qs = QueryFns.ExtractAndDecodeQueryString(context); if (qs == null) { base.OnActionExecuted(context); return; } var queryable = QueryFns.ExtractQueryable(context); if (queryable == null) { base.OnActionExecuted(context); } var eq = new EntityQuery(qs); var eleType = TypeFns.GetElementType(queryable.GetType()); eq.Validate(eleType); int?inlineCount = null; var originalQueryable = queryable; queryable = eq.ApplyWhere(queryable, eleType); if (eq.IsInlineCountEnabled) { inlineCount = (int)Queryable.Count((dynamic)queryable); } queryable = eq.ApplyOrderBy(queryable, eleType); queryable = eq.ApplySkip(queryable, eleType); queryable = eq.ApplyTake(queryable, eleType); queryable = eq.ApplySelect(queryable, eleType); queryable = eq.ApplyExpand(queryable, eleType); if (queryable != originalQueryable) { // if a select or expand was encountered we need to // execute the DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. var listResult = Enumerable.ToList((dynamic)queryable); var qr = new QueryResult(listResult, inlineCount); context.Result = new ObjectResult(qr); } base.OnActionExecuted(context); }
private IQueryable ApplyNestedOrderBy(IQueryable queryable, ODataQueryOptions queryOptions) { var elementType = TypeFns.GetElementType(queryable.GetType()); var result = queryable; string inlinecountString = queryOptions.RawValues.InlineCount; if (!string.IsNullOrWhiteSpace(inlinecountString)) { if (inlinecountString == "allpages") { if (result is IQueryable) { var inlineCount = (Int64)Queryable.Count((dynamic)result); queryOptions.Request.SetInlineCount(inlineCount); } } } var orderByClauses = queryOptions.RawValues.OrderBy.Split(',').ToList(); var isThenBy = false; orderByClauses.ForEach(obc => { var func = QueryBuilder.BuildOrderByFunc(isThenBy, elementType, obc); result = func(result); isThenBy = true; }); var skipQueryString = queryOptions.RawValues.Skip; if (!string.IsNullOrWhiteSpace(skipQueryString)) { var count = int.Parse(skipQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } var topQueryString = queryOptions.RawValues.Top; if (!string.IsNullOrWhiteSpace(topQueryString)) { var count = int.Parse(topQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } return(result); }
/// <summary> /// Apply the select clause to the queryable /// </summary> /// <param name="queryable"></param> /// <param name="selectQueryString"></param> /// <returns></returns> public virtual IQueryable ApplySelect(IQueryable queryable, ODataQueryOptions queryOptions) { var selectQueryString = queryOptions.RawValues.Select; if (string.IsNullOrEmpty(selectQueryString)) { return(queryable); } var selectClauses = selectQueryString.Split(',').Select(sc => sc.Replace('/', '.')).ToList(); var elementType = TypeFns.GetElementType(queryable.GetType()); var func = QueryBuilder.BuildSelectFunc(elementType, selectClauses); return(func(queryable)); }
public virtual IQueryable ApplyOrderBy(IQueryable queryable, ODataQueryOptions queryOptions) { var elementType = TypeFns.GetElementType(queryable.GetType()); var result = queryable; var orderByString = queryOptions.RawValues.OrderBy; if (!string.IsNullOrEmpty(orderByString)) { var orderByClauses = orderByString.Split(',').ToList(); var isThenBy = false; orderByClauses.ForEach(obc => { var parts = obc.Trim().Replace(" ", " ").Split(' '); var propertyPath = parts[0]; bool isDesc = parts.Length > 1 && parts[1] == "desc"; var odi = new OrderByClause.OrderByItem(parts[0], isDesc); var func = QueryBuilder.BuildOrderByFunc(isThenBy, elementType, odi); result = func(result); isThenBy = true; }); } var skipQueryString = queryOptions.RawValues.Skip; if (!string.IsNullOrWhiteSpace(skipQueryString)) { var count = int.Parse(skipQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } var topQueryString = queryOptions.RawValues.Top; if (!string.IsNullOrWhiteSpace(topQueryString)) { var count = int.Parse(topQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } return(result); }
public virtual IQueryable ApplyOrderBy(IQueryable queryable, ODataQueryOptions queryOptions) { var elementType = TypeFns.GetElementType(queryable.GetType()); var result = queryable; var orderByString = queryOptions.RawValues.OrderBy; if (!string.IsNullOrEmpty(orderByString)) { // apply the new order var orderByClauses = orderByString.Split(',').ToList(); var isThenBy = false; orderByClauses.ForEach(obc => { var func = QueryBuilder.BuildOrderByFunc(isThenBy, elementType, obc); result = func(result); isThenBy = true; }); } var skipQueryString = queryOptions.RawValues.Skip; if (!string.IsNullOrWhiteSpace(skipQueryString)) { var count = int.Parse(skipQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Skip <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } var topQueryString = queryOptions.RawValues.Top; if (!string.IsNullOrWhiteSpace(topQueryString)) { var count = int.Parse(topQueryString); var method = TypeFns.GetMethodByExample((IQueryable <String> q) => Queryable.Take <String>(q, 999), elementType); var func = BuildIQueryableFunc(elementType, method, count); result = func(result); } return(result); }
private static MethodCallExpression GenerateMethodCall(Expression queryableExpr, string methodName, String propertyName, Type forceEntityType = null) { var baseEntityType = TypeFns.GetElementType(queryableExpr.Type); var entityType = forceEntityType != null ? forceEntityType : baseEntityType; Type selectorResultType; LambdaExpression selector = GeneratePropertySelector(entityType, propertyName, out selectorResultType); var parmTypes = new List <Type> { baseEntityType }; if (forceEntityType != null) { parmTypes.Add(forceEntityType); } parmTypes.Add(selectorResultType); var methodMI = typeof(EntityFrameworkQueryableExtensions).GetMethods().Where(me => me.Name == methodName).FirstOrDefault(); MethodCallExpression resultExp = Expression.Call(methodMI.DeclaringType, methodName, parmTypes.ToArray(), queryableExpr, Expression.Quote(selector)); return(resultExp); }
public IQueryable IncludeByString(IQueryable queryable, String expandQueryString) { var result = queryable.Expression; if (string.IsNullOrEmpty(expandQueryString)) { return(queryable); } var baseElementType = TypeFns.GetElementType(queryable.GetType()); expandQueryString = expandQueryString.Replace('/', '.'); var expandEntities = expandQueryString.Split('.').ToList(); var isThenInclude = false; expandEntities.ForEach(propertyName => { var parmElementType = isThenInclude ? GetIncludeableElementType(result.Type) : TypeFns.GetElementType(result.Type); var propertyInfo = parmElementType.GetProperty(propertyName); if (propertyInfo == null) { throw new Exception("Unable to locate property: " + propertyName + " on type: " + parmElementType.ToString()); } if (isThenInclude) { result = ThenIncludeString(result, propertyName, parmElementType); } else { result = IncludeString(result, propertyName); } isThenInclude = true; }); return(queryable.Provider.CreateQuery(result) as IQueryable); }
/// <summary> /// Apply to expands clause to the queryable /// </summary> /// <param name="queryable"></param> /// <param name="expandsQueryString"></param> /// <returns></returns> public virtual IQueryable ApplyExpand(IQueryable queryable, ODataQueryOptions queryOptions) { return(queryable); var queryable2 = queryable as IQueryable <object>; var expandQueryString = queryOptions.RawValues.Expand; if (string.IsNullOrEmpty(expandQueryString)) { return(queryable); } var eleType = TypeFns.GetElementType(queryable2.GetType()); expandQueryString.Split(',').Select(s => s.Trim().Replace('/', '.')).ToList().ForEach(expand => { //queryable = ((dynamic)queryable).Include(expand.Replace('/', '.')); queryable2 = queryable2.Include(expand); //var method = TypeFns.GetMethodByExample((IQueryable<String> q) => EntityFrameworkQueryableExtensions.Include<String>(q, "dummyPath"), eleType); //var func = QueryBuilder.BuildIQueryableFunc(eleType, method, expand); //queryable2 = func(queryable2 as IQueryable) as IQueryable<object>; }); return(queryable2 as IQueryable); }
/// <summary> /// Apply the queryOptions to the query. /// This method handles nested order-by statements the the current ASP.NET web api does not yet support. /// </summary> /// <param name="queryable"></param> /// <param name="queryOptions"></param> /// <param name="querySettings"></param> /// <returns></returns> public IQueryable ApplyQuery(IQueryable queryable, ODataQueryOptions queryOptions, ODataQuerySettings querySettings) { // HACK: this is a hack because on a bug in querySettings.EnsureStableOrdering = true that overrides // any existing order by clauses, instead of appending to them. querySettings.EnsureStableOrdering = false; // Basic idea here is the current WebApi OData cannot support the following operations // 1) "orderby" with nested properties // 2) "select" with complex types // 3) "selects" of "nested" properties unless accompanied by the appropriate "expand". // i.e. can't do Customers.select("orders") unless we also add expand("orders") // The workaround here is to bypass "select" and "orderBy" processing under these conditions // This involves removing the "offending" queryOptions before asking the WebApi2 OData processing to do its thing // and then post processing the resulting IQueryable. // We actually do this with all selects because it's easier than trying to determine if they are actually problematic. // Another approach that DOESN'T work is to let WebApi2 OData try to do it stuff and then only handle the cases where it throws an exception. // This doesn't work because WebApi2 OData will actually just skip the portions of the query that it can't process and return what it can ( under some conditions). var expandQueryString = queryOptions.RawValues.Expand; var orderByQueryString = queryOptions.RawValues.OrderBy; var selectQueryString = queryOptions.RawValues.Select; var filterQueryString = queryOptions.RawValues.Filter; ODataQueryOptions newQueryOptions = queryOptions; if (!string.IsNullOrWhiteSpace(selectQueryString)) { newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions); } else if ((!string.IsNullOrWhiteSpace(orderByQueryString)) && orderByQueryString.IndexOf('/') >= 0) { newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions); } //else if (ManuallyExpand && !string.IsNullOrWhiteSpace(expandQueryString)) else if (!string.IsNullOrWhiteSpace(expandQueryString)) { newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions); } else if (!string.IsNullOrWhiteSpace(filterQueryString)) { newQueryOptions = QueryHelper.RemoveSelectExpandOrderBy(newQueryOptions); } if (newQueryOptions == queryOptions) { return(queryOptions.ApplyTo(queryable, querySettings)); } else { // remove inlinecount or it will be executed two times if (newQueryOptions.InlineCount != null) { newQueryOptions = QueryHelper.RemoveInlineCount(newQueryOptions); } // apply default processing first with "unsupported" stuff removed. var q = newQueryOptions.ApplyTo(queryable, querySettings); // then apply unsupported stuff. // remove any ordering q = RemoveOrderBy(q); // apply any filtering q = ApplyFilter(q, queryOptions); string inlinecountString = queryOptions.RawValues.InlineCount; if (!string.IsNullOrWhiteSpace(inlinecountString)) { if (inlinecountString == "allpages") { // TODO: make this asynch //var inlineCount = (Int64)Queryable.LongCount((dynamic)q); //queryOptions.Request.SetInlineCount(inlineCount); // create new query for count var countQ = q.Provider.CreateQuery(q.Expression) as IQueryable; if (_LongCountAsynchMI == null) { _LongCountAsynchMI = typeof(EntityFrameworkQueryableExtensions).GetMethods().Where(me => me.Name == "LongCountAsync" && me.GetParameters().Count() == 2).FirstOrDefault(); } var countQEntityType = TypeFns.GetElementType(q.Expression.Type); var methodMI = _LongCountAsynchMI.MakeGenericMethod(countQEntityType); try { this._inlineCountT = methodMI.Invoke(countQ, new Object[] { countQ, new System.Threading.CancellationToken() }) as Task <long>; } catch (Exception ex) { } } } q = ApplyOrderBy(q, queryOptions); var q2 = ApplySelect(q, queryOptions); if (q2 == q) { q2 = ApplyExpand(q, queryOptions); } return(q2); } }
/// <summary> /// Replaces the response.Content with the query results, wrapped in a QueryResult object if necessary. /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <param name="responseObject"></param> /// <param name="queryable"></param> public virtual async Task <bool> WrapResult(HttpRequestMessage request, HttpResponseMessage response, IQueryable queryResult) { //Object tmp; //request.Properties.TryGetValue("MS_InlineCount", out tmp); //var inlineCount = (Int64?)tmp; // if a select or expand was encountered we need to // execute the DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. dynamic listQueryResult = null; try { // try entity core method first if (_toListAsynchMI == null) { _toListAsynchMI = typeof(EntityFrameworkQueryableExtensions).GetMethods().Where(me => me.Name == "ToListAsync" && me.GetParameters().Count() == 2).FirstOrDefault(); } var countQEntityType = TypeFns.GetElementType(queryResult.Expression.Type); var methodMI = _toListAsynchMI.MakeGenericMethod(countQEntityType); var resultT = methodMI.Invoke(queryResult, new Object[] { queryResult, new System.Threading.CancellationToken() }) as Task; await resultT; listQueryResult = (resultT as dynamic).Result; } catch (Exception ex) { try { // try old method on EF core failure as not every query will be an EF core query listQueryResult = Enumerable.ToList((dynamic)queryResult); } catch (Exception ex2) { throw ex2; } } var elementType = queryResult.ElementType; if (elementType.Name.StartsWith("SelectAllAndExpand")) { var prop = elementType.GetProperties().FirstOrDefault(pi => pi.Name == "Instance"); var mi = prop.GetGetMethod(); var lqr = (List <Object>)listQueryResult; listQueryResult = (dynamic)lqr.Select(item => { var instance = mi.Invoke(item, null); return((Object)instance); }).ToList(); } // HierarchyNodeExpressionVisitor listQueryResult = PostExecuteQuery((IEnumerable)listQueryResult); if (listQueryResult != null || this._inlineCountT != null) { Object result = listQueryResult; if (this._inlineCountT != null) { var inlineCount = await this._inlineCountT; result = new QueryResult() { Results = listQueryResult, InlineCount = inlineCount }; } var formatter = ((dynamic)response.Content).Formatter; var oc = new ObjectContent(result.GetType(), result, formatter); response.Content = oc; } return(true); }
public override void OnActionExecuted(ActionExecutedContext context) { var qs = QueryFns.ExtractAndDecodeQueryString(context); if (qs == null) { base.OnActionExecuted(context); return; } var queryable = QueryFns.ExtractQueryable(context); if (queryable == null) { base.OnActionExecuted(context); return; } var eq = new EntityQuery(qs); var eleType = TypeFns.GetElementType(queryable.GetType()); eq.Validate(eleType); int?inlineCount = null; queryable = eq.ApplyWhere(queryable, eleType); if (eq.IsInlineCountEnabled) { inlineCount = (int)Queryable.Count((dynamic)queryable); } queryable = eq.ApplyOrderBy(queryable, eleType); queryable = eq.ApplySkip(queryable, eleType); queryable = eq.ApplyTake(queryable, eleType); queryable = eq.ApplySelect(queryable, eleType); queryable = eq.ApplyExpand(queryable, eleType); // if a select or expand was encountered we need to // execute the DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. var listResult = Enumerable.ToList((dynamic)queryable); var qr = new QueryResult(listResult, inlineCount); var breezeConfig = context.HttpContext.RequestServices.GetService <IBreezeConfig>(); context.Result = new ObjectResult(qr) { Formatters = new FormatterCollection <IOutputFormatter> { #if NETCOREAPP3_1 || NETCOREAPP3_0 new NewtonsoftJsonOutputFormatter(breezeConfig.GetJsonSerializerSettings(), context.HttpContext.RequestServices.GetRequiredService <ArrayPool <char> >(), context.HttpContext.RequestServices.GetRequiredService <MvcOptions>()) #else new JsonOutputFormatter(breezeConfig.GetJsonSerializerSettings(), context.HttpContext.RequestServices.GetRequiredService <ArrayPool <char> >()) #endif } }; var session = GetSession(queryable); if (session != null) { Close(session); } base.OnActionExecuted(context); }
public override void OnActionExecuted(ActionExecutedContext context) { var objResult = context.Result as ObjectResult; if (objResult == null) { base.OnActionExecuted(context); return; } var qs = context.HttpContext.Request.QueryString; var q = WebUtility.UrlDecode(qs.Value); if (q.Length == 0) { base.OnActionExecuted(context); return; } q = q.Substring(1, q.Length - 2); var eq = new EntityQuery(q); var eleType = TypeFns.GetElementType(objResult.Value.GetType()); eq.Validate(eleType); // TODO: handle IEnumerable as well. var result = (IQueryable)objResult.Value; int?inlineCount = null; if (eq.WherePredicate != null) { result = QueryBuilder.ApplyWhere(result, eleType, eq.WherePredicate); } if (eq.IsInlineCountEnabled) { inlineCount = (int)Queryable.Count((dynamic)result); } if (eq.OrderByClause != null) { result = QueryBuilder.ApplyOrderBy(result, eleType, eq.OrderByClause); } if (eq.SkipCount.HasValue) { result = QueryBuilder.ApplySkip(result, eleType, eq.SkipCount.Value); } if (eq.TakeCount.HasValue) { result = QueryBuilder.ApplyTake(result, eleType, eq.TakeCount.Value); } if (eq.SelectClause != null) { result = QueryBuilder.ApplySelect(result, eleType, eq.SelectClause); } if (eq.ExpandClause != null) { eq.ExpandClause.PropertyPaths.ToList().ForEach(expand => { result = ((dynamic)result).Include(expand.Replace('/', '.')); }); } if (objResult.Value != result) { // if a select or expand was encountered we need to // execute the DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. var listResult = Enumerable.ToList((dynamic)result); var qr = new QueryResult(listResult, inlineCount); context.Result = new ObjectResult(qr); } base.OnActionExecuted(context); }
public override void OnActionExecuted(HttpActionExecutedContext context) { var qs = QueryFns.ExtractAndDecodeQueryString(context); if (qs == null) { base.OnActionExecuted(context); return; } var queryable = QueryFns.ExtractQueryable(context); if (queryable == null) { base.OnActionExecuted(context); return; } var eq = new EntityQuery(qs); var eleType = TypeFns.GetElementType(queryable.GetType()); eq.Validate(eleType); int?inlineCount = null; var originalQueryable = queryable; queryable = eq.ApplyWhere(queryable, eleType); IFutureValue <int> inlineCountFuture = null; if (eq.IsInlineCountEnabled) { if (UseFuture) { var countExpr = GetCountExpressionMethod.MakeGenericMethod(eleType).Invoke(this, new object[0]); inlineCountFuture = (IFutureValue <int>)ToFutureValueMethod.MakeGenericMethod(eleType, typeof(int)) .Invoke(null, new[] { queryable, countExpr }); } else { inlineCount = (int)Queryable.Count((dynamic)queryable); } } queryable = eq.ApplyOrderBy(queryable, eleType); queryable = eq.ApplySkip(queryable, eleType); queryable = eq.ApplyTake(queryable, eleType); queryable = eq.ApplySelect(queryable, eleType); queryable = eq.ApplyExpand(queryable, eleType); if (queryable != originalQueryable) { // if a select or expand was encountered we need to // execute the DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. dynamic listResult; if (UseFuture) { var future = ToFutureMethod.MakeGenericMethod(eleType).Invoke(null, new object[] { queryable }); listResult = Enumerable.ToList((dynamic)future.GetType().GetMethod("GetEnumerable").Invoke(future, new object[0])); } else { listResult = Enumerable.ToList((dynamic)queryable); } var qr = new QueryResult(listResult, inlineCountFuture?.Value ?? inlineCount); if (CloseSession) { var session = GetSession(queryable); if (session != null) { Close(session); } } context.Response = context.Request.CreateResponse(HttpStatusCode.OK, qr); } base.OnActionExecuted(context); }