public MyFieldResolver( FillDataExtensions fillDataExtensions, IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; _fillDataExtensions = fillDataExtensions; _logger = _httpContextAccessor.HttpContext.RequestServices.GetService <ILogger <MyFieldResolver <TUser, TRole, TUserRole> > >(); }
public async Task InvokeAsync(HttpContext context, ISchema schema, FillDataExtensions fillDataExtensions) { if (context.WebSockets.IsWebSocketRequest || !context.Request.Path.StartsWithSegments(_path)) { await _next(context); return; } _fillDataExtensions = fillDataExtensions; // Handle requests as per recommendation at http://graphql.org/learn/serving-over-http/ // Inspiration: https://github.com/graphql/express-graphql/blob/master/src/index.js var httpRequest = context.Request; var httpResponse = context.Response; //var writer = context.RequestServices.GetRequiredService<IDocumentWriter>(); var cancellationToken = GetCancellationToken(context); // GraphQL HTTP only supports GET and POST methods bool isGet = HttpMethods.IsGet(httpRequest.Method); bool isPost = HttpMethods.IsPost(httpRequest.Method); if (!isGet && !isPost) { httpResponse.Headers["Allow"] = "GET, POST"; await WriteErrorResponseAsync(context, $"Invalid HTTP method. Only GET and POST are supported. {DOCS_URL}", httpStatusCode : 405 // Method Not Allowed ); return; } // Parse POST body GraphQLRequest bodyGQLRequest = null; GraphQLRequest[] bodyGQLBatchRequest = null; if (isPost) { if (!MediaTypeHeaderValue.TryParse(httpRequest.ContentType, out var mediaTypeHeader)) { await WriteErrorResponseAsync(context, $"Invalid 'Content-Type' header: value '{httpRequest.ContentType}' could not be parsed."); return; } switch (mediaTypeHeader.MediaType) { case MediaType.JSON: var deserializationResult = await _deserializer.DeserializeFromJsonBodyAsync(httpRequest, cancellationToken); if (!deserializationResult.IsSuccessful) { await WriteErrorResponseAsync(context, "Body text could not be parsed. Body text should start with '{' for normal graphql query or with '[' for batched query."); return; } bodyGQLRequest = deserializationResult.Single; bodyGQLBatchRequest = deserializationResult.Batch; break; case MediaType.GRAPH_QL: bodyGQLRequest = await DeserializeFromGraphBodyAsync(httpRequest.Body); break; case MediaType.FORM: var formCollection = await httpRequest.ReadFormAsync(); bodyGQLRequest = DeserializeFromFormBody(formCollection); break; default: await WriteErrorResponseAsync(context, $"Invalid 'Content-Type' header: non-supported media type. " + $"Must be of '{MediaType.JSON}', '{MediaType.GRAPH_QL}' or '{MediaType.FORM}'. {DOCS_URL}"); return; } } // If we don't have a batch request, parse the URL too to determine the actual request to run // Querystring params take priority GraphQLRequest gqlRequest = null; if (bodyGQLBatchRequest == null) { // Parse URL var urlGQLRequest = DeserializeFromQueryString(httpRequest.Query); gqlRequest = new GraphQLRequest { Query = urlGQLRequest.Query ?? bodyGQLRequest?.Query, Inputs = urlGQLRequest.Inputs ?? bodyGQLRequest?.Inputs, OperationName = urlGQLRequest.OperationName ?? bodyGQLRequest?.OperationName }; } // Prepare context and execute var userContextBuilder = context.RequestServices.GetService <IUserContextBuilder>(); var userContext = userContextBuilder == null ? new Dictionary <string, object>() // in order to allow resolvers to exchange their state through this object : await userContextBuilder.BuildUserContext(context); var executer = context.RequestServices.GetRequiredService <IGraphQLExecuter <TSchema> >(); // var executer = context.RequestServices.GetRequiredService<IDocumentExecuter>(); // Normal execution with single graphql request if (bodyGQLBatchRequest == null) { var stopwatch = ValueStopwatch.StartNew(); // var result = await ExecuteRequestAsync(schema, gqlRequest, context, executer, cancellationToken); var result = await ExecuteRequestAsync(gqlRequest, userContext, executer, context.RequestServices, cancellationToken); await RequestExecutedAsync(new GraphQLRequestExecutionResult(gqlRequest, result, stopwatch.Elapsed)); if (result.Errors?.Count > 0) { await WriteErrorResponseAsync(context, result); } else { await WriteResponseAsync(context, result); } } // Execute multiple graphql requests in one batch else { var error = false; ExecutionResult executionResult = null; var executionResults = new ExecutionResult[bodyGQLBatchRequest.Length]; for (int i = 0; i < bodyGQLBatchRequest.Length; ++i) { var gqlRequestInBatch = bodyGQLBatchRequest[i]; var stopwatch = ValueStopwatch.StartNew(); // var result = await ExecuteRequestAsync(schema, gqlRequestInBatch, context, executer, cancellationToken); var result = await ExecuteRequestAsync(gqlRequestInBatch, userContext, executer, context.RequestServices, cancellationToken); await RequestExecutedAsync(new GraphQLRequestExecutionResult(gqlRequestInBatch, result, stopwatch.Elapsed, i)); if (result.Errors?.Count > 0) { error = true; executionResult = result; } executionResults[i] = result; } if (error) { await WriteErrorResponseAsync(context, executionResult); } else { // await WriteResponseAsync(context, executionResults); } } }
public static async Task <IEnumerable <T> > GetPagedAsync <T>(this IQueryable <T> source, IHttpContextAccessor _httpContextAccessor, FillDataExtensions _fillDataExtensions) where T : class { bool allowCache = true; // Filter By if (_httpContextAccessor.HttpContext.Request.Query.Any(x => x.Key.Equals("filter_by"))) { var properties = new Dictionary <string, Type>(); foreach (var propertyInfo in typeof(T).GetProperties()) { //Console.WriteLine($"_________________TRACEEEEEEEEEEEEEEEEE____________: key: {propertyInfo.Name} value: {propertyInfo.PropertyType.Name}"); if (!propertyInfo.GetCustomAttributes(true).Any(x => x.GetType() == typeof(JsonIgnoreAttribute)) && !propertyInfo.GetCustomAttributes(true).Any(x => x.GetType() == typeof(NotMappedAttribute)) && !(propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IList <>)) && !(propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(IEnumerable <>)) && !(propertyInfo.PropertyType.IsGenericType && propertyInfo.PropertyType.GetGenericTypeDefinition() == typeof(ICollection <>)) && !(typeof(ICollection).IsAssignableFrom(propertyInfo.PropertyType)) ) { properties.Add(propertyInfo.Name, propertyInfo.PropertyType); } } var columnStr = _httpContextAccessor.HttpContext.Request.Query.FirstOrDefault(x => x.Key.Equals("filter_by")).Value.ToString(); string pattern = @"\/|\|"; string[] columns = Regex.Split(columnStr, pattern); var divider = new List <string>(); Match match = Regex.Match(columnStr, pattern); // query filtro por AND o OR foreach (var(value, index) in columns.Select((v, i) => (v, i))) { if (index > 0) { match = match.NextMatch(); if (match.Success) { if (match.Value == "/") { divider.Add(" AND "); } else { divider.Add(" OR "); } } } else { if (match.Success) { if (match.Value == "/") { divider.Add(" AND "); } else { divider.Add(" OR "); } } } } var expresion = new StringBuilder(); List <object> values = new List <object>(); //Procesamiento query string dividerOld = ""; foreach (var(column, index) in columns.Select((v, i) => (v, i))) { allowCache = false; if (index > 0) { if (index > 1 && dividerOld != divider[index - 1]) { expresion.Append(")"); expresion.Append(divider[index - 1]); expresion.Append("("); } else { expresion.Append(divider[index - 1]); } dividerOld = divider[index - 1]; } else { expresion.Append("("); } var patternStr = @"\=|¬"; string[] value = Regex.Split(column, patternStr); if (string.IsNullOrEmpty(value[1])) { break; } if (value[0] == "$") { try { foreach (var(field, i) in properties.Select((v, i) => (v, i))) { SqlCommandExtension.ConcatFilter(values, expresion, string.Format("@{0}", i + index), field.Key, value[1], column, typeProperty: field.Value, index: i); } break; } catch (Exception) { throw; } } var paramName = string.Format("@{0}", index); SqlCommandExtension.ConcatFilter(values, expresion, paramName, value[0], value[1], column); } expresion.Append(")"); Console.WriteLine(expresion.ToString()); source = source.Where(expresion.ToString().ToLower(), values.ToArray()); } // Order By if (_httpContextAccessor.HttpContext.Request.Query.Any(x => x.Key.Equals("order_by"))) { source = source.OrderBy(_httpContextAccessor.HttpContext.Request.Query.FirstOrDefault(x => x.Key.Equals("order_by")).Value.ToString()); } // pagination if (_httpContextAccessor.HttpContext.Request.Query.Any(x => x.Key.Equals("enable_pagination")) && bool.TryParse(_httpContextAccessor.HttpContext.Request.Query.FirstOrDefault(x => x.Key.Equals("enable_pagination")).Value.ToString(), out bool enablePagination)) { var pageSizeRequest = _httpContextAccessor.HttpContext.Request.Query.FirstOrDefault(x => x.Key.Equals("page_size")).Value; var currentPageRequest = _httpContextAccessor.HttpContext.Request.Query.FirstOrDefault(x => x.Key.Equals("current_page")).Value; int pageSize = string.IsNullOrEmpty(pageSizeRequest) ? 20 : int.Parse(pageSizeRequest); int pageNumber = string.IsNullOrEmpty(currentPageRequest) ? 1 : int.Parse(currentPageRequest); var result = new PagedResultBase(); result.current_page = pageNumber; result.page_size = pageSize; int?rowCount = null; if (allowCache) { rowCount = source.CacheGetOrCreate(_httpContextAccessor); } result.row_count = rowCount ?? source.CountAsync().Result; var pageCount = (double)result.row_count / pageSize; result.page_count = (int)Math.Ceiling(pageCount); _fillDataExtensions.Add($"{typeof(T).Name.ToLower()}_list", result); //foreach (var propertyInfo in typeof(PagedResultBase).GetProperties()) //{ // var currentValue = propertyInfo.GetValue(result); // _fillDataExtensions.Add(propertyInfo.Name, currentValue); //} return(await source.Skip((pageNumber - 1) *pageSize).Take(pageSize).AsNoTracking().ToListAsync()); } return(await source.AsNoTracking().ToListAsync()); }
public GraphQLQuery( IDatabaseMetadata dbMetadata, ITableNameLookup tableNameLookup, IHttpContextAccessor httpContextAccessor, FillDataExtensions fillDataExtensions, IDataLoaderContextAccessor accessor, ISERFieldResolver <TUser, TRole, TUserRole> fieldResolver, IOptionsMonitor <SERGraphQlOptions> optionsDelegate ) { _dbMetadata = dbMetadata; _tableNameLookup = tableNameLookup; _httpContextAccessor = httpContextAccessor; _fillDataExtensions = fillDataExtensions; _accessor = accessor; _optionsDelegate = optionsDelegate; _fieldResolver = fieldResolver; Name = "Query"; var tables = _dbMetadata.GetTableMetadatas(); foreach (var metaTable in tables) { var friendlyTableName = metaTable.Type.Name.ToSnakeCase().ToLower(); dynamic objectGraphType = null; if (!_tableNameLookup.ExistGraphType(metaTable.Type.Name)) { var inherateType = typeof(TableType <>).MakeGenericType(new Type[] { metaTable.Type }); objectGraphType = Activator.CreateInstance(inherateType, new object[] { metaTable, _dbMetadata, _tableNameLookup, _httpContextAccessor, _accessor, _optionsDelegate }); } var tableType = _tableNameLookup.GetOrInsertGraphType(metaTable.Type.Name, objectGraphType); dynamic objectCountGraphType = null; if (!_tableNameLookup.ExistGraphType($"{metaTable.Type.Name}_count")) { var inherateType = typeof(CountTableType <>).MakeGenericType(new Type[] { metaTable.Type }); objectCountGraphType = Activator.CreateInstance(inherateType, new object[] { _dbMetadata, metaTable, _tableNameLookup, _optionsDelegate }); } var countTableType = _tableNameLookup.GetOrInsertGraphType($"{metaTable.Type.Name}_count", objectCountGraphType); dynamic objectSumGraphType = null; if (!_tableNameLookup.ExistGraphType($"{metaTable.Type.Name}_sum_plus")) { var inherateType = typeof(SumTableType <>).MakeGenericType(new Type[] { metaTable.Type }); objectSumGraphType = Activator.CreateInstance(inherateType, new object[] { _dbMetadata, metaTable, _tableNameLookup, _optionsDelegate }); } var sumTableType = _tableNameLookup.GetOrInsertGraphType($"{metaTable.Type.Name}_sum_plus", objectSumGraphType); var ttype = typeof(TableType <>).MakeGenericType(new Type[] { metaTable.Type }); AddField(new FieldType { Name = friendlyTableName, Type = tableType.GetType(), ResolvedType = tableType, Resolver = _fieldResolver, // new MyFieldResolver<TUser, TRole, TUserRole>(_fillDataExtensions, _httpContextAccessor), Arguments = new QueryArguments(tableType.TableArgs) }); var inherateListType = typeof(ListGraphType <>).MakeGenericType(new Type[] { tableType.GetType() }); dynamic listType = Activator.CreateInstance(inherateListType); listType.ResolvedType = tableType; AddField(new FieldType { Name = $"{friendlyTableName}_list", Type = listType.GetType(), ResolvedType = listType, Resolver = _fieldResolver, Arguments = new QueryArguments(tableType.TableArgs) }); AddField(new FieldType { Name = $"{friendlyTableName}_count", Type = countTableType.GetType(), ResolvedType = countTableType, Resolver = _fieldResolver, Arguments = new QueryArguments(countTableType.TableArgs) }); AddField(new FieldType { Name = $"{friendlyTableName}_sum", Type = ttype, ResolvedType = sumTableType, Resolver = _fieldResolver, Arguments = new QueryArguments(sumTableType.TableArgs) }); } }