From 064cd9a44c5dde9dc29d0a753334d2965e266f05 Mon Sep 17 00:00:00 2001 From: Hisham Bin Ateya Date: Tue, 14 Feb 2023 09:09:21 +0300 Subject: [PATCH 01/25] Upgrade to GraphQL 7.2.2 --- src/OrchardCore.Build/Dependencies.props | 8 +-- .../Extensions/DocumentWriterExtensions.cs | 4 +- .../GraphQLMiddleware.cs | 44 +++++++------- .../OrchardCore.Apis.GraphQL/Startup.cs | 2 +- .../MaxNumberOfResultsValidationRule.cs | 24 +++++--- .../RequiresPermissionValidationRule.cs | 22 +++---- .../GraphQL/Types/HtmlFieldQueryObjectType.cs | 5 +- .../GraphQL/Types/TimeSpanGraphType.cs | 6 +- .../GraphQL/LocalizationQueryObjectType.cs | 28 ++++----- .../GraphQL/FlowAlignmentEnum.cs | 8 +-- .../GraphQL/HtmlBodyQueryObjectType.cs | 5 +- .../GraphQL/LayerQueryObjectType.cs | 33 ++++++----- .../GraphQL/SiteLayersQuery.cs | 5 +- .../GraphQL/SiteCulturesQuery.cs | 4 +- .../GraphQL/MarkdownBodyQueryObjectType.cs | 2 +- .../GraphQL/MarkdownFieldQueryObjectType.cs | 2 +- .../GraphQL/MediaAssetQuery.cs | 4 +- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 57 +++++++++--------- .../GraphQL/ElasticQueryFieldTypeProvider.cs | 58 ++++++++++--------- .../GraphQL/LuceneQueryFieldTypeProvider.cs | 58 ++++++++++--------- .../GraphQL/TaxonomyFieldQueryObjectType.cs | 7 ++- .../FieldBuilderResolverExtensions.cs | 2 +- .../Resolvers/LockedAsyncFieldResolver.cs | 28 +++------ .../Queries/ContentItemQuery.cs | 7 ++- .../Queries/ContentItemsFieldType.cs | 4 +- .../Queries/PublicationStatusEnum.cs | 8 +-- .../Queries/Types/ContentItemOrderByInput.cs | 4 +- .../Queries/Types/ContentItemType.cs | 42 ++++++++------ .../Queries/Types/TypedContentTypeBuilder.cs | 2 +- src/docs/resources/libraries/README.md | 2 +- .../GraphQL/ContentItemsFieldTypeTests.cs | 16 ++--- .../RequiresPermissionValidationRuleTests.cs | 27 ++++----- 32 files changed, 273 insertions(+), 255 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index dd82e3c0490..441d3c821a8 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -20,10 +20,10 @@ - - - - + + + + diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Extensions/DocumentWriterExtensions.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Extensions/DocumentWriterExtensions.cs index 3da70d976ef..f47c5e68e72 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Extensions/DocumentWriterExtensions.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Extensions/DocumentWriterExtensions.cs @@ -9,7 +9,7 @@ namespace OrchardCore.Apis.GraphQL { internal static class DocumentWriterExtensions { - public static async Task WriteErrorAsync(this IDocumentWriter documentWriter, HttpContext context, string message, Exception e = null) + public static async Task WriteErrorAsync(this IGraphQLSerializer graphQLSerializer, HttpContext context, string message, Exception e = null) { if (message == null) { @@ -33,7 +33,7 @@ public static async Task WriteErrorAsync(this IDocumentWriter documentWriter, Ht context.Response.StatusCode = (int)HttpStatusCode.BadRequest; context.Response.ContentType = MediaTypeNames.Application.Json; - await documentWriter.WriteAsync(context.Response.Body, errorResult); + await graphQLSerializer.WriteAsync(context.Response.Body, errorResult); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index 7ecc4528545..70a91a8b9aa 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -11,10 +11,12 @@ using GraphQL.SystemTextJson; using GraphQL.Validation; using GraphQL.Validation.Complexity; +using GraphQL.Validation.Rules.Custom; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Formatters; +using Microsoft.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; using OrchardCore.Apis.GraphQL.Queries; using OrchardCore.Apis.GraphQL.ValidationRules; @@ -42,7 +44,7 @@ public GraphQLMiddleware( _executer = executer; } - public async Task Invoke(HttpContext context, IAuthorizationService authorizationService, IAuthenticationService authenticationService, ISchemaFactory schemaService, IDocumentWriter documentWriter) + public async Task Invoke(HttpContext context, IAuthorizationService authorizationService, IAuthenticationService authenticationService, ISchemaFactory schemaService, IGraphQLSerializer graphQLSerializer) { if (!IsGraphQLRequest(context)) { @@ -61,7 +63,7 @@ public async Task Invoke(HttpContext context, IAuthorizationService authorizatio if (authorized) { - await ExecuteAsync(context, schemaService, documentWriter); + await ExecuteAsync(context, schemaService, graphQLSerializer); } else { @@ -75,7 +77,7 @@ private bool IsGraphQLRequest(HttpContext context) return context.Request.Path.StartsWithNormalizedSegments(_settings.Path, StringComparison.OrdinalIgnoreCase); } - private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaService, IDocumentWriter documentWriter) + private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaService, IGraphQLSerializer graphQLSerializer) { GraphQLRequest request = null; @@ -121,7 +123,7 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic } catch (Exception e) { - await documentWriter.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e); + await graphQLSerializer.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e); return; } @@ -140,23 +142,23 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic var schema = await schemaService.GetSchemaAsync(); var dataLoaderDocumentListener = context.RequestServices.GetRequiredService(); - var result = await _executer.ExecuteAsync(_ => + var result = await _executer.ExecuteAsync(options => { - _.Schema = schema; - _.Query = queryToExecute; - _.OperationName = request.OperationName; - _.Inputs = request.Variables.ToInputs(); - _.UserContext = _settings.BuildUserContext?.Invoke(context); - _.ValidationRules = DocumentValidator.CoreRules - .Concat(context.RequestServices.GetServices()); - _.ComplexityConfiguration = new ComplexityConfiguration - { - MaxDepth = _settings.MaxDepth, - MaxComplexity = _settings.MaxComplexity, - FieldImpact = _settings.FieldImpact - }; - _.Listeners.Add(dataLoaderDocumentListener); - _.RequestServices = context.RequestServices; + options.Schema = schema; + options.Query = queryToExecute; + options.OperationName = request.OperationName; + options.Variables = new GraphQLSerializer().Deserialize(request.Variables.GetString()); + options.UserContext = _settings.BuildUserContext?.Invoke(context); + options.ValidationRules = DocumentValidator.CoreRules + .Concat(context.RequestServices.GetServices()) + .Append(new ComplexityValidationRule(new ComplexityConfiguration + { + MaxDepth = _settings.MaxDepth, + MaxComplexity = _settings.MaxComplexity, + FieldImpact = _settings.FieldImpact + })); + options.Listeners.Add(dataLoaderDocumentListener); + options.RequestServices = context.RequestServices; }); context.Response.StatusCode = (int)(result.Errors == null || result.Errors.Count == 0 @@ -167,7 +169,7 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic context.Response.ContentType = MediaTypeNames.Application.Json; - await documentWriter.WriteAsync(context.Response.Body, result); + await graphQLSerializer.WriteAsync(context.Response.Body, result); } private static GraphQLRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs index bfd5da0eabd..3b1cd1799dc 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs @@ -36,7 +36,7 @@ public Startup(IOptions adminOptions, IHostEnvironment hostingEnvi public override void ConfigureServices(IServiceCollection services) { services.AddSingleton(); - services.AddSingleton(); + services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs index abbaa436e9f..fb657c7e1ce 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs @@ -1,6 +1,7 @@ +using System; using System.Threading.Tasks; -using GraphQL.Language.AST; using GraphQL.Validation; +using GraphQLParser.AST; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -23,10 +24,10 @@ public MaxNumberOfResultsValidationRule(IOptions options, IStri _logger = logger; } - public Task ValidateAsync(ValidationContext validationContext) + public ValueTask ValidateAsync(ValidationContext validationContext) { - return Task.FromResult((INodeVisitor)new NodeVisitors( - new MatchingNodeVisitor((arg, visitorContext) => + return ValueTask.FromResult((INodeVisitor)new NodeVisitors( + new MatchingNodeVisitor((arg, visitorContext) => { if ((arg.Name == "first" || arg.Name == "last") && arg.Value != null) { @@ -34,13 +35,13 @@ public Task ValidateAsync(ValidationContext validationContext) int? value = null; - if (arg.Value is IntValue) + if (arg.Value is GraphQLIntValue) { - value = ((IntValue)arg.Value)?.Value; + value = Int32.Parse((arg.Value as GraphQLIntValue).Value); } else { - if (validationContext.Inputs.TryGetValue(arg.Value.ToString(), out var input)) + if (validationContext.Variables.TryGetValue(arg.Value.ToString(), out var input)) { value = (int?)input; } @@ -53,7 +54,7 @@ public Task ValidateAsync(ValidationContext validationContext) if (_maxNumberOfResultsValidationMode == MaxNumberOfResultsValidationMode.Enabled) { validationContext.ReportError(new ValidationError( - validationContext.Document.OriginalQuery, + validationContext.Document.Source, "ArgumentInputError", errorMessage, arg)); @@ -61,7 +62,12 @@ public Task ValidateAsync(ValidationContext validationContext) else { _logger.LogInformation(errorMessage); - arg = new Argument(arg.NameNode, new IntValue(_maxNumberOfResults)); // if disabled mode we just log info and override the arg to be maxvalue + + arg = new GraphQLArgument + { + Name = arg.Name, + Value = new GraphQLIntValue(_maxNumberOfResults) + }; // if disabled mode we just log info and override the arg to be maxvalue } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs index d16f2aea5b0..579e7a7ec36 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/RequiresPermissionValidationRule.cs @@ -2,9 +2,9 @@ using System.Linq; using System.Threading.Tasks; using GraphQL; -using GraphQL.Language.AST; using GraphQL.Types; using GraphQL.Validation; +using GraphQLParser.AST; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.Localization; @@ -22,17 +22,17 @@ public RequiresPermissionValidationRule(IAuthorizationService authorizationServi S = s; } - public async Task ValidateAsync(ValidationContext validationContext) + public async ValueTask ValidateAsync(ValidationContext validationContext) { // shouldn't we access UserContext from validationcontext inside MatchingNodeVisitor actions? var userContext = (GraphQLUserContext)validationContext.UserContext; return await Task.FromResult(new NodeVisitors( - new MatchingNodeVisitor(async (astType, validationContext) => + new MatchingNodeVisitor(async (operationDefinition, validationContext) => { - await AuthorizeOperationAsync(astType, validationContext, userContext, astType.OperationType, astType.Name); + await AuthorizeOperationAsync(operationDefinition, validationContext, userContext, operationDefinition.Operation, operationDefinition.Name.StringValue); }), - new MatchingNodeVisitor(async (objectFieldAst, validationContext) => + new MatchingNodeVisitor(async (objectFieldAst, validationContext) => { if (validationContext.TypeInfo.GetArgument()?.ResolvedType.GetNamedType() is IComplexGraphType argumentType) { @@ -40,7 +40,7 @@ public async Task ValidateAsync(ValidationContext validationContex await AuthorizeNodePermissionAsync(objectFieldAst, fieldType, validationContext, userContext); } }), - new MatchingNodeVisitor(async (fieldAst, validationContext) => + new MatchingNodeVisitor(async (fieldAst, validationContext) => { var fieldDef = validationContext.TypeInfo.GetFieldDef(); @@ -55,19 +55,19 @@ public async Task ValidateAsync(ValidationContext validationContex )); } - private async Task AuthorizeOperationAsync(INode node, ValidationContext validationContext, GraphQLUserContext userContext, OperationType? operationType, string operationName) + private async Task AuthorizeOperationAsync(ASTNode node, ValidationContext validationContext, GraphQLUserContext userContext, OperationType? operationType, string operationName) { if (operationType == OperationType.Mutation && !(await _authorizationService.AuthorizeAsync(userContext.User, Permissions.ExecuteGraphQLMutations))) { validationContext.ReportError(new ValidationError( - validationContext.Document.OriginalQuery, + validationContext.Document.Source, ErrorCode, S["Authorization is required to access {0}.", operationName], node)); } } - private async Task AuthorizeNodePermissionAsync(INode node, IFieldType fieldType, ValidationContext validationContext, GraphQLUserContext userContext) + private async Task AuthorizeNodePermissionAsync(ASTNode node, IFieldType fieldType, ValidationContext validationContext, GraphQLUserContext userContext) { var permissions = fieldType?.GetPermissions(); @@ -110,10 +110,10 @@ private async Task AuthorizeNodePermissionAsync(INode node, IFieldType fieldType } } - private void AddPermissionValidationError(ValidationContext validationContext, INode node, string nodeName) + private void AddPermissionValidationError(ValidationContext validationContext, ASTNode node, string nodeName) { validationContext.ReportError(new ValidationError( - validationContext.Document.OriginalQuery, + validationContext.Document.Source, ErrorCode, S["Authorization is required to access the node. {0}", nodeName], node)); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/HtmlFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/HtmlFieldQueryObjectType.cs index e45b87ceff2..112dd44027d 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/HtmlFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/HtmlFieldQueryObjectType.cs @@ -27,13 +27,12 @@ public HtmlFieldQueryObjectType(IStringLocalizer S) Name = nameof(HtmlField); Description = S["Content stored as HTML."]; - Field() - .Name("html") + Field("html") .Description(S["the HTML content"]) .ResolveLockedAsync(RenderHtml); } - private static async Task RenderHtml(IResolveFieldContext ctx) + private static async ValueTask RenderHtml(IResolveFieldContext ctx) { var serviceProvider = ctx.RequestServices; var shortcodeService = serviceProvider.GetRequiredService(); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/TimeSpanGraphType.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/TimeSpanGraphType.cs index b310c2de5f5..4575b4067b6 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/TimeSpanGraphType.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Types/TimeSpanGraphType.cs @@ -1,7 +1,7 @@ using System; using System.Globalization; -using GraphQL.Language.AST; using GraphQL.Types; +using GraphQLParser.AST; namespace OrchardCore.ContentFields.GraphQL.Types { @@ -26,9 +26,9 @@ public override object ParseValue(object value) : (TimeSpan?)TimeSpan.Parse(timespan, CultureInfo.CurrentCulture); } - public override object ParseLiteral(IValue value) + public override object ParseLiteral(GraphQLValue value) { - var str = value as StringValue; + var str = value as GraphQLStringValue; if (str != null) { return ParseValue(str.Value); diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs index 5d14461e9e8..e4e9f1c2842 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; using GraphQL; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; @@ -21,24 +22,25 @@ public LocalizationQueryObjectType(IStringLocalizer Field(x => x.Culture).Description(S["The culture for your content item."]); Field(x => x.LocalizationSet).Description(S["The localization set for your content item."]); - Field, IEnumerable>() - .Name("Localizations") + Field, IEnumerable>("Localizations") .Description(S["The localizations of the content item."]) .Argument("culture", "the culture of the content item") - .ResolveLockedAsync(async ctx => - { - var culture = ctx.GetArgument("culture"); - var contentLocalizationManager = ctx.RequestServices.GetService(); + .ResolveLockedAsync(GetContentItemsByLocalizationSetAsync); + } + + private static async ValueTask> GetContentItemsByLocalizationSetAsync(IResolveFieldContext context) + { + var culture = context.GetArgument("culture"); + var contentLocalizationManager = context.RequestServices.GetService(); - if (culture != null) - { - var contentItem = await contentLocalizationManager.GetContentItemAsync(ctx.Source.LocalizationSet, culture); + if (culture != null) + { + var contentItem = await contentLocalizationManager.GetContentItemAsync(context.Source.LocalizationSet, culture); - return contentItem != null ? new[] { contentItem } : Enumerable.Empty(); - } + return contentItem != null ? new[] { contentItem } : Enumerable.Empty(); + } - return await contentLocalizationManager.GetItemsForSetAsync(ctx.Source.LocalizationSet); - }); + return await contentLocalizationManager.GetItemsForSetAsync(context.Source.LocalizationSet); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowAlignmentEnum.cs b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowAlignmentEnum.cs index d73706e39d7..e0b3397bbd2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowAlignmentEnum.cs +++ b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowAlignmentEnum.cs @@ -9,10 +9,10 @@ public FlowAlignmentEnum() Name = "FlowAlignment"; Description = "The widget alignment."; - AddValue("Left", "Left alignment.", 0); - AddValue("Center", "Center alignment.", 1); - AddValue("Right", "Right alignment.", 2); - AddValue("Justify", "Justify alignment.", 3); + Add("Left", 0, "Left alignment."); + Add("Center", 1, "Center alignment."); + Add("Right", 2, "Right alignment."); + Add("Justify", 3, "Justify alignment."); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Html/GraphQL/HtmlBodyQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Html/GraphQL/HtmlBodyQueryObjectType.cs index 7aece9c58f3..8665ab6fe66 100644 --- a/src/OrchardCore.Modules/OrchardCore.Html/GraphQL/HtmlBodyQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Html/GraphQL/HtmlBodyQueryObjectType.cs @@ -25,13 +25,12 @@ public HtmlBodyQueryObjectType(IStringLocalizer S) Name = "HtmlBodyPart"; Description = S["Content stored as HTML."]; - Field() - .Name("html") + Field("html") .Description(S["the HTML content"]) .ResolveLockedAsync(RenderHtml); } - private static async Task RenderHtml(IResolveFieldContext ctx) + private static async ValueTask RenderHtml(IResolveFieldContext ctx) { var shortcodeService = ctx.RequestServices.GetRequiredService(); var contentDefinitionManager = ctx.RequestServices.GetRequiredService(); diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs index b079a6f5396..27b2ebc9690 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; +using System.Threading.Tasks; using GraphQL; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; @@ -25,31 +26,31 @@ public LayerQueryObjectType() #pragma warning disable 0618 Field(layer => layer.Rule).Description("Deprecated. The rule that activates the layer."); #pragma warning restore 0618 - Field, IEnumerable>() - .Name("layerrule") + Field, IEnumerable>("layerrule") .Description("The rule that activates the layer.") .Resolve(ctx => ctx.Source.LayerRule.Conditions); Field(layer => layer.Description).Description("The description of the layer."); - Field, IEnumerable>() - .Name("widgets") + Field, IEnumerable>("widgets") .Description("The widgets for this layer.") .Argument("status", "publication status of the widgets") - .ResolveLockedAsync(async ctx => - { - var layerService = ctx.RequestServices.GetService(); + .ResolveLockedAsync(GetWidgetsForLayerAsync); - var filter = GetVersionFilter(ctx.GetArgument("status")); - var widgets = await layerService.GetLayerWidgetsAsync(filter); + async ValueTask> GetWidgetsForLayerAsync(IResolveFieldContext context) + { + var layerService = context.RequestServices.GetService(); - var layerWidgets = widgets?.Where(item => - { - var metadata = item.As(); - if (metadata == null) return false; - return metadata.Layer == ctx.Source.Name; - }); + var filter = GetVersionFilter(context.GetArgument("status")); + var widgets = await layerService.GetLayerWidgetsAsync(filter); - return layerWidgets; + var layerWidgets = widgets?.Where(item => + { + var metadata = item.As(); + if (metadata == null) return false; + return metadata.Layer == context.Source.Name; }); + + return layerWidgets; + } } private Expression> GetVersionFilter(PublicationStatusEnum status) diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index 38a07b23d1a..2162e2e37da 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -41,7 +41,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteLayers", Description = S["Site layers define the rules and zone placement for widgets."], Type = typeof(ListGraphType), - Resolver = new LockedAsyncFieldResolver>(ResolveAsync) + Resolver = new LockedAsyncFieldResolver(ResolveAsync) }; schema.Query.AddField(field); @@ -49,10 +49,11 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private async Task> ResolveAsync(IResolveFieldContext resolveContext) + private async Task ResolveAsync(IResolveFieldContext resolveContext) { var layerService = resolveContext.RequestServices.GetService(); var allLayers = await layerService.GetLayersAsync(); + return allLayers.Layers; } } diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index c1d8b96a1d9..f77420b3f58 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -50,7 +50,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteCultures", Description = S["The active cultures configured for the site."], Type = typeof(ListGraphType), - Resolver = new LockedAsyncFieldResolver>(ResolveAsync) + Resolver = new LockedAsyncFieldResolver(ResolveAsync) }; schema.Query.AddField(field); @@ -58,7 +58,7 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private async Task> ResolveAsync(IResolveFieldContext resolveContext) + private async Task ResolveAsync(IResolveFieldContext resolveContext) { var localizationService = resolveContext.RequestServices.GetService(); diff --git a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs index 3244851b569..3c5408e6755 100644 --- a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs @@ -35,7 +35,7 @@ public MarkdownBodyQueryObjectType(IStringLocalizer .ResolveLockedAsync(ToHtml); } - private static async Task ToHtml(IResolveFieldContext ctx) + private static async ValueTask ToHtml(IResolveFieldContext ctx) { if (string.IsNullOrEmpty(ctx.Source.Markdown)) { diff --git a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs index b47b4a76da1..e8e8ead7986 100644 --- a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs @@ -37,7 +37,7 @@ public MarkdownFieldQueryObjectType(IStringLocalizer ToHtml(IResolveFieldContext ctx) + private static async ValueTask ToHtml(IResolveFieldContext ctx) { if (string.IsNullOrEmpty(ctx.Source.Markdown)) { diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 179be78e297..fbfde039520 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -53,7 +53,7 @@ public Task BuildAsync(ISchema schema) Description = S["Whether to get the assets from just the top directory or from all sub-directories as well."] } ), - Resolver = new LockedAsyncFieldResolver>(ResolveAsync) + Resolver = new LockedAsyncFieldResolver(ResolveAsync) }; schema.Query.AddField(field); @@ -61,7 +61,7 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private async Task> ResolveAsync(IResolveFieldContext resolveContext) + private async Task ResolveAsync(IResolveFieldContext resolveContext) { var mediaFileStore = resolveContext.RequestServices.GetService(); diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index 4c4891f8e52..ce4e0603061 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -140,22 +140,25 @@ private FieldType BuildSchemaBasedFieldType(SqlQuery query, JToken querySchema, Name = fieldTypeName, Description = "Represents the " + query.Source + " Query : " + query.Name, ResolvedType = new ListGraphType(typetype), - Resolver = new LockedAsyncFieldResolver(async context => - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + Resolver = new LockedAsyncFieldResolver(ResolveAsync), + Type = typeof(ListGraphType>) + }; - var parameters = context.GetArgument("parameters"); + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var parameters = context.GetArgument("parameters"); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - }), - Type = typeof(ListGraphType>) - }; + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); + + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + + return result.Items; + } return fieldType; } @@ -177,22 +180,24 @@ private FieldType BuildContentTypeFieldType(ISchema schema, string contentType, Name = fieldTypeName, Description = "Represents the " + query.Source + " Query : " + query.Name, ResolvedType = typetype.ResolvedType, - Resolver = new LockedAsyncFieldResolver(async context => - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + Resolver = new LockedAsyncFieldResolver(ResolveAsync), + Type = typetype.Type + }; + + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var parameters = context.GetArgument("parameters"); + var parameters = context.GetArgument("parameters"); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - }), - Type = typetype.Type - }; + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + return result.Items; + } return fieldType; } diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs index f52c8671a7c..0d84aa180b8 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs @@ -141,22 +141,25 @@ private FieldType BuildSchemaBasedFieldType(ElasticQuery query, JToken querySche Name = fieldTypeName, Description = "Represents the " + query.Source + " Query : " + query.Name, ResolvedType = new ListGraphType(typetype), - Resolver = new LockedAsyncFieldResolver(async context => - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + Resolver = new LockedAsyncFieldResolver(ResolveAsync), + Type = typeof(ListGraphType>) + }; - var parameters = context.GetArgument("parameters"); + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var parameters = context.GetArgument("parameters"); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - }), - Type = typeof(ListGraphType>) - }; + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); + + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + + return result.Items; + } return fieldType; } @@ -179,22 +182,25 @@ private FieldType BuildContentTypeFieldType(ISchema schema, string contentType, Name = fieldTypeName, Description = "Represents the " + query.Source + " Query : " + query.Name, ResolvedType = typetype.ResolvedType, - Resolver = new LockedAsyncFieldResolver(async context => - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + Resolver = new LockedAsyncFieldResolver(ResolveAsync), + Type = typetype.Type + }; - var parameters = context.GetArgument("parameters"); + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var parameters = context.GetArgument("parameters"); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - }), - Type = typetype.Type - }; + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); + + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + + return result.Items; + } return fieldType; } diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs index d2bcdf74c12..61e926e4b2e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs @@ -140,22 +140,25 @@ private FieldType BuildSchemaBasedFieldType(LuceneQuery query, JToken querySchem Name = fieldTypeName, Description = "Represents the " + query.Source + " Query : " + query.Name, ResolvedType = new ListGraphType(typetype), - Resolver = new LockedAsyncFieldResolver(async context => - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + Resolver = new LockedAsyncFieldResolver(ResolveAsync), + Type = typeof(ListGraphType>) + }; - var parameters = context.GetArgument("parameters"); + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var parameters = context.GetArgument("parameters"); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - }), - Type = typeof(ListGraphType>) - }; + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); + + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + + return result.Items; + } return fieldType; } @@ -178,22 +181,25 @@ private FieldType BuildContentTypeFieldType(ISchema schema, string contentType, Name = fieldTypeName, Description = "Represents the " + query.Source + " Query : " + query.Name, ResolvedType = typetype.ResolvedType, - Resolver = new LockedAsyncFieldResolver(async context => - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + Resolver = new LockedAsyncFieldResolver(ResolveAsync), + Type = typetype.Type + }; - var parameters = context.GetArgument("parameters"); + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var parameters = context.GetArgument("parameters"); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - }), - Type = typetype.Type - }; + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); + + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + + return result.Items; + } return fieldType; } diff --git a/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs index a25d2c08110..579054dde7e 100644 --- a/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs @@ -62,10 +62,11 @@ public TaxonomyFieldQueryObjectType() Field() .Name("taxonomyContentItem") .Description("the taxonomy content item") - .ResolveLockedAsync(x => + .ResolveLockedAsync(async context => { - var contentManager = x.RequestServices.GetService(); - return contentManager.GetAsync(x.Source.TaxonomyContentItemId); + var contentManager = context.RequestServices.GetService(); + + return await contentManager.GetAsync(context.Source.TaxonomyContentItemId); }); } } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs index d48a0463e03..d3c507b26da 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs @@ -8,7 +8,7 @@ namespace OrchardCore.Apis.GraphQL { public static class FieldBuilderResolverExtensions { - public static FieldBuilder ResolveLockedAsync(this FieldBuilder builder, Func, Task> resolve) + public static FieldBuilder ResolveLockedAsync(this FieldBuilder builder, Func, ValueTask> resolve) { return builder.Resolve(new LockedAsyncFieldResolver(resolve)); } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs index 808c227549e..98dfbfaf04a 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs @@ -5,16 +5,16 @@ namespace OrchardCore.Apis.GraphQL.Resolvers { - public class LockedAsyncFieldResolver : IFieldResolver> + public class LockedAsyncFieldResolver : IFieldResolver { - private readonly Func> _resolver; + private readonly Func> _resolver; - public LockedAsyncFieldResolver(Func> resolver) + public LockedAsyncFieldResolver(Func> resolver) { _resolver = resolver; } - public async Task Resolve(IResolveFieldContext context) + public async ValueTask ResolveAsync(IResolveFieldContext context) { var graphContext = (GraphQLUserContext)context.UserContext; @@ -22,44 +22,34 @@ public async Task Resolve(IResolveFieldContext context) try { - return await _resolver(context); + return _resolver(context); } finally { graphContext.ExecutionContextLock.Release(); } } - - object IFieldResolver.Resolve(IResolveFieldContext context) - { - return Resolve(context); - } } - public class LockedAsyncFieldResolver : AsyncFieldResolver, IFieldResolver> + public class LockedAsyncFieldResolver : FuncFieldResolver { - public LockedAsyncFieldResolver(Func, Task> resolver) : base(resolver) + public LockedAsyncFieldResolver(Func, ValueTask> resolver) : base(resolver) { } - public new async Task Resolve(IResolveFieldContext context) + public new async Task ResolveAsync(IResolveFieldContext context) { var graphContext = (GraphQLUserContext)context.UserContext; await graphContext.ExecutionContextLock.WaitAsync(); try { - return await base.Resolve(context); + return await base.ResolveAsync(context); } finally { graphContext.ExecutionContextLock.Release(); } } - - object IFieldResolver.Resolve(IResolveFieldContext context) - { - return Resolve(context); - } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs index 2853846f87b..91169670924 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemQuery.cs @@ -40,7 +40,7 @@ public Task BuildAsync(ISchema schema) Description = S["Content item id"] } ), - Resolver = new AsyncFieldResolver(ResolveAsync) + Resolver = new FuncFieldResolver(ResolveAsync) }; schema.Query.AddField(field); @@ -48,11 +48,12 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private Task ResolveAsync(IResolveFieldContext context) + private async ValueTask ResolveAsync(IResolveFieldContext context) { var contentItemId = context.GetArgument("contentItemId"); var contentManager = _httpContextAccessor.HttpContext.RequestServices.GetService(); - return contentManager.GetAsync(contentItemId); + + return await contentManager.GetAsync(contentItemId); } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 17aca956fd6..1618031c75e 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -55,7 +55,7 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions { Name = "status", Description = "publication status of the content item", ResolvedType = new PublicationStatusGraphType(), DefaultValue = PublicationStatusEnum.Published } ); - Resolver = new LockedAsyncFieldResolver>(Resolve); + Resolver = new LockedAsyncFieldResolver(Resolve); schema.RegisterType(whereInput); schema.RegisterType(orderByInput); @@ -64,7 +64,7 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions> Resolve(IResolveFieldContext context) + private async Task Resolve(IResolveFieldContext context) { var versionOption = VersionOptions.Published; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusEnum.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusEnum.cs index 5af75bae9b6..6ac61611660 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusEnum.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusEnum.cs @@ -16,10 +16,10 @@ public PublicationStatusGraphType() { Name = "Status"; Description = "publication status"; - AddValue("PUBLISHED", "published content item version", PublicationStatusEnum.Published); - AddValue("DRAFT", "draft content item version", PublicationStatusEnum.Draft); - AddValue("LATEST", "the latest version, either published or draft", PublicationStatusEnum.Latest); - AddValue("ALL", "all historical versions", PublicationStatusEnum.All); + Add("PUBLISHED", PublicationStatusEnum.Published, "published content item version"); + Add("DRAFT", PublicationStatusEnum.Draft, "draft content item version"); + Add("LATEST", PublicationStatusEnum.Latest, "the latest version, either published or draft"); + Add("ALL", PublicationStatusEnum.All, "all historical versions"); } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs index a1a2691f144..1a8f49f1da9 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemOrderByInput.cs @@ -34,8 +34,8 @@ public OrderByDirectionGraphType() { Name = "OrderByDirection"; Description = "the order by direction"; - AddValue("ASC", "orders content items in ascending order", OrderByDirection.Ascending); - AddValue("DESC", "orders content items in descending order", OrderByDirection.Descending); + Add("ASC", OrderByDirection.Ascending, "orders content items in ascending order"); + Add("DESC", OrderByDirection.Descending, "orders content items in descending order"); } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs index f30183fe8a0..9810c12bdf4 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemType.cs @@ -1,4 +1,6 @@ using System.Text.Encodings.Web; +using System.Threading.Tasks; +using GraphQL; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; @@ -33,25 +35,8 @@ public ContentItemType(IOptions optionsAccessor) Field(ci => ci.Owner).Description("The owner of the content item"); Field(ci => ci.Author).Description("The author of the content item"); - Field() - .Name("render") - .ResolveLockedAsync(async context => - { - var serviceProvider = context.RequestServices; - - // Build shape - var displayManager = serviceProvider.GetRequiredService(); - var updateModelAccessor = serviceProvider.GetRequiredService(); - var model = await displayManager.BuildDisplayAsync(context.Source, updateModelAccessor.ModelUpdater); - - var displayHelper = serviceProvider.GetRequiredService(); - var htmlEncoder = serviceProvider.GetRequiredService(); - - using var sw = new ZStringWriter(); - var htmlContent = await displayHelper.ShapeExecuteAsync(model); - htmlContent.WriteTo(sw, htmlEncoder); - return sw.ToString(); - }); + Field("render") + .ResolveLockedAsync(RenderShapeAsync); Interface(); @@ -72,5 +57,24 @@ public override FieldType AddField(FieldType fieldType) return null; } + + private static async ValueTask RenderShapeAsync(IResolveFieldContext context) + { + var serviceProvider = context.RequestServices; + + // Build shape + var displayManager = serviceProvider.GetRequiredService(); + var updateModelAccessor = serviceProvider.GetRequiredService(); + var model = await displayManager.BuildDisplayAsync(context.Source, updateModelAccessor.ModelUpdater); + + var displayHelper = serviceProvider.GetRequiredService(); + var htmlEncoder = serviceProvider.GetRequiredService(); + + using var sw = new ZStringWriter(); + var htmlContent = await displayHelper.ShapeExecuteAsync(model); + htmlContent.WriteTo(sw, htmlEncoder); + + return sw.ToString(); + } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 48a21b7d9c0..9e942075d34 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -73,7 +73,7 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin var nameToResolve = partName; var resolvedPart = context.Source.Get(activator.Type, nameToResolve); - return field.Resolver.Resolve(new ResolveFieldContext + return field.Resolver.ResolveAsync(new ResolveFieldContext { Arguments = context.Arguments, Source = resolvedPart, diff --git a/src/docs/resources/libraries/README.md b/src/docs/resources/libraries/README.md index 41ee12d9b00..cbbf1ac1c04 100644 --- a/src/docs/resources/libraries/README.md +++ b/src/docs/resources/libraries/README.md @@ -13,7 +13,7 @@ The below table lists the different .NET libraries used in Orchard Core: | [Azure Storage Blobs for DataProtection](https://github.com/Azure/azure-sdk-for-net/blob/Azure.Extensions.AspNetCore.DataProtection.Blobs_1.2.3/sdk/extensions/Azure.Extensions.AspNetCore.DataProtection.Blobs/README.md) | Allows storing ASP.NET Core DataProtection keys in Azure Blob Storage. | 1.2.3 |[MIT](https://github.com/Azure/azure-sdk-for-net/blob/master/LICENSE.txt) | | [Castle.Core](https://github.com/castleproject/Core) | Castle DynamicProxy. | 5.1.1 |[Apache-2.0](https://github.com/castleproject/Core/blob/master/LICENSE) | | [Fluid.Core](https://github.com/sebastienros/fluid) | .NET Liquid template engine. | 2.3.1 | [MIT](https://github.com/sebastienros/fluid/blob/dev/LICENSE) | -| [GraphQL](https://github.com/graphql/graphiql) | GraphiQL & GraphQL. | 4.6.1 | [MIT](https://github.com/graphql/graphiql/blob/main/LICENSE) | +| [GraphQL](https://github.com/graphql/graphiql) | GraphiQL & GraphQL. | 7.2.2 | [MIT](https://github.com/graphql/graphiql/blob/main/LICENSE) | | [HtmlSanitizer](https://github.com/mganss/HtmlSanitizer) | Cleans HTML to avoid XSS attacks. | 8.0.645 | [MIT](https://github.com/mganss/HtmlSanitizer/blob/master/LICENSE.md) | | [Image Sharp](https://github.com/SixLabors/ImageSharp.Web) | Middleware for ASP.NET-Core for image manipulation. | 2.0.2 |[Apache-2.0](https://github.com/SixLabors/ImageSharp.Web/blob/master/LICENSE) | | [Irony.Core](https://github.com/daxnet/irony) | A modified version of the Irony project with .NET Core support | 1.0.7 | [MIT](https://github.com/daxnet/irony/blob/master/LICENSE) | diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs index a063e5bd99f..7cd0405515f 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs @@ -137,7 +137,7 @@ public async Task ShouldFilterByContentItemIndex() var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); - var dogs = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -175,7 +175,7 @@ public async Task ShouldFilterByContentItemIndexWhenSqlTablePrefixIsUsed() var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); - var dogs = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -213,7 +213,7 @@ public async Task ShouldFilterByAliasIndexRegardlessOfInputFieldCase(string fiel var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse(string.Concat("{ ", fieldName, ": { name: \"doug\" } }")), ArgumentSource.Variable); - var dogs = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -248,13 +248,13 @@ public async Task ShouldBeAbleToUseTheSameIndexForMultipleAliases() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ cats: { name: \"doug\" } }"), ArgumentSource.Variable); - var cats = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var cats = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(cats); Assert.Equal("doug", cats.First().As().Name); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ dogs: { name: \"doug\" } }"), ArgumentSource.Variable); - var dogs = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -301,7 +301,7 @@ public async Task ShouldFilterOnMultipleIndexesOnSameAlias() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animals: { name: \"doug\", isScary: true } }"), ArgumentSource.Variable); - var animals = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var animals = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(animals); Assert.Equal("doug", animals.First().As().Name); @@ -338,7 +338,7 @@ public async Task ShouldFilterPartsWithoutAPrefixWhenThePartHasNoPrefix() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animal: { name: \"doug\" } }"), ArgumentSource.Variable); - var dogs = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -373,7 +373,7 @@ public async Task ShouldFilterByCollapsedWhereInputForCollapsedParts() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ name: \"doug\" }"), ArgumentSource.Variable); - var dogs = await ((LockedAsyncFieldResolver>)type.Resolver).Resolve(context); + var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs index d0ea2b3e2da..500b05c02f7 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs @@ -32,8 +32,8 @@ public async Task FieldsWithNoRequirePermissionsShouldResolve() Assert.Null(executionResult.Errors); - var writer = new DocumentWriter(); - var result = JObject.Parse(await writer.WriteToStringAsync(executionResult)); + var writer = new GraphQLSerializer(); + var result = JObject.Parse(writer.Serialize(executionResult)); Assert.Equal("Fantastic Fox Hates Permissions", result["data"]["test"]["noPermissions"].ToString()); } @@ -56,8 +56,8 @@ public async Task FieldsWithRequirePermissionsShouldResolveWhenUserHasPermission Assert.Null(executionResult.Errors); - var writer = new DocumentWriter(); - var result = JObject.Parse(await writer.WriteToStringAsync(executionResult)); + var writer = new GraphQLSerializer(); + var result = JObject.Parse(writer.Serialize(executionResult)); Assert.Equal(expectedFieldValue, result["data"]["test"][fieldName].ToString()); } @@ -94,8 +94,8 @@ public async Task FieldsWithMultipleRequirePermissionsShouldResolveWhenUserHasAl Assert.Null(executionResult.Errors); - var writer = new DocumentWriter(); - var result = JObject.Parse(await writer.WriteToStringAsync(executionResult)); + var writer = new GraphQLSerializer(); + var result = JObject.Parse(writer.Serialize(executionResult)); Assert.Equal("Fantastic Fox Loves Multiple Permissions", result["data"]["test"]["permissionMultiple"].ToString()); } @@ -143,8 +143,7 @@ private class ValidationQueryRoot : ObjectGraphType { public ValidationQueryRoot() { - Field() - .Name("test") + Field("test") .Returns() .Resolve(_ => new object()); } @@ -154,25 +153,21 @@ private class TestField : ObjectGraphType { public TestField() { - Field() - .Name("NoPermissions") + Field("NoPermissions") .Returns() .Resolve(_ => "Fantastic Fox Hates Permissions"); - Field() - .Name("PermissionOne") + Field("PermissionOne") .Returns() .RequirePermission(_permissions["permissionOne"]) .Resolve(_ => "Fantastic Fox Loves Permission One"); - Field() - .Name("PermissionTwo") + Field("PermissionTwo") .Returns() .RequirePermission(_permissions["permissionTwo"]) .Resolve(_ => "Fantastic Fox Loves Permission Two"); - Field() - .Name("PermissionMultiple") + Field("PermissionMultiple") .Returns() .RequirePermission(_permissions["permissionOne"]) .RequirePermission(_permissions["permissionTwo"]) From c3c2d82bfff9318a58c8381977cafa5c0c21332a Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sat, 6 Jan 2024 21:00:28 +0800 Subject: [PATCH 02/25] Add media filenames on MediaFieldType --- .../GraphQL/MediaFieldQueryObjectType.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs index 2f9b2cf328c..7fe0cce8dfb 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs @@ -27,6 +27,20 @@ public MediaFieldQueryObjectType() return x.Page(x.Source.Paths); }); + Field, IEnumerable>() + .Name("fileNames") + .Description("the media fileNames") + .PagingArguments() + .Resolve(x => + { + var fileNames = x.Page(x.Source.GetAttachedFileNames()); + if (fileNames is null) + { + return Array.Empty(); + } + return fileNames; + }); + Field, IEnumerable>() .Name("urls") .Description("the absolute urls of the media items") From 6998b7be19ecd03dd283a2bbda43a0c1ae81abe6 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sat, 20 Jan 2024 01:44:31 +0800 Subject: [PATCH 03/25] add logs to unit tests --- .../Apis/Context/SiteStartup.cs | 15 ++++++++- test/OrchardCore.Tests/NLog.config | 32 +++++++++++++++++++ .../OrchardCore.Tests.csproj | 7 +++- 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 test/OrchardCore.Tests/NLog.config diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index e021dea84ae..0f18bb48236 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -1,6 +1,10 @@ +using NLog.Config; +using NLog.Web; +using NLog; using OrchardCore.Modules; using OrchardCore.Modules.Manifest; using OrchardCore.Recipes.Services; +using OrchardCore.Logging; namespace OrchardCore.Tests.Apis.Context { @@ -17,6 +21,14 @@ static SiteStartup() public void ConfigureServices(IServiceCollection services) #pragma warning restore CA1822 // Mark members as static { + LogManager.Setup().SetupExtensions(delegate (ISetupExtensionsBuilder ext) + { + ext.RegisterLayoutRenderer("orchard-tenant-name"); + }); + services.AddLogging(loggingBuilder => + { + loggingBuilder.AddNLogWeb(); + }); services.AddOrchardCms(builder => builder.AddSetupFeatures( "OrchardCore.Tenants" @@ -39,10 +51,11 @@ public void ConfigureServices(IServiceCollection services) } #pragma warning disable CA1822 // Mark members as static - public void Configure(IApplicationBuilder app) + public void Configure(IApplicationBuilder app, IHostEnvironment env) #pragma warning restore CA1822 // Mark members as static { app.UseOrchardCore(); + LogManager.Configuration.Variables["configDir"] = env.ContentRootPath; } private class ModuleNamesProvider : IModuleNamesProvider diff --git a/test/OrchardCore.Tests/NLog.config b/test/OrchardCore.Tests/NLog.config new file mode 100644 index 00000000000..b6e0eb2aa6b --- /dev/null +++ b/test/OrchardCore.Tests/NLog.config @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/test/OrchardCore.Tests/OrchardCore.Tests.csproj b/test/OrchardCore.Tests/OrchardCore.Tests.csproj index aaaf2f9d06f..39452ed49d2 100644 --- a/test/OrchardCore.Tests/OrchardCore.Tests.csproj +++ b/test/OrchardCore.Tests/OrchardCore.Tests.csproj @@ -13,7 +13,6 @@ - @@ -24,6 +23,7 @@ + @@ -33,6 +33,11 @@ + + PreserveNewest + true + PreserveNewest + From acfa5ce0e33a31c76055b4d0c00f48d17c693ce4 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sat, 20 Jan 2024 02:12:47 +0800 Subject: [PATCH 04/25] UseNLogHost() --- test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs | 3 +++ test/OrchardCore.Tests/Apis/Context/SiteStartup.cs | 11 +---------- test/OrchardCore.Tests/NLog.config | 2 +- 3 files changed, 5 insertions(+), 11 deletions(-) diff --git a/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs b/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs index f960ad8645e..80e717c6782 100644 --- a/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs +++ b/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs @@ -1,3 +1,5 @@ +using OrchardCore.Logging; + namespace OrchardCore.Tests.Apis.Context { public class OrchardTestFixture : WebApplicationFactory @@ -23,6 +25,7 @@ protected override IWebHostBuilder CreateWebHostBuilder() protected override IHostBuilder CreateHostBuilder() => Host.CreateDefaultBuilder() + .UseNLogHost() .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); } diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 0f18bb48236..6b15aeb0e23 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -21,14 +21,6 @@ static SiteStartup() public void ConfigureServices(IServiceCollection services) #pragma warning restore CA1822 // Mark members as static { - LogManager.Setup().SetupExtensions(delegate (ISetupExtensionsBuilder ext) - { - ext.RegisterLayoutRenderer("orchard-tenant-name"); - }); - services.AddLogging(loggingBuilder => - { - loggingBuilder.AddNLogWeb(); - }); services.AddOrchardCms(builder => builder.AddSetupFeatures( "OrchardCore.Tenants" @@ -51,11 +43,10 @@ public void ConfigureServices(IServiceCollection services) } #pragma warning disable CA1822 // Mark members as static - public void Configure(IApplicationBuilder app, IHostEnvironment env) + public void Configure(IApplicationBuilder app) #pragma warning restore CA1822 // Mark members as static { app.UseOrchardCore(); - LogManager.Configuration.Variables["configDir"] = env.ContentRootPath; } private class ModuleNamesProvider : IModuleNamesProvider diff --git a/test/OrchardCore.Tests/NLog.config b/test/OrchardCore.Tests/NLog.config index b6e0eb2aa6b..fe628219a48 100644 --- a/test/OrchardCore.Tests/NLog.config +++ b/test/OrchardCore.Tests/NLog.config @@ -24,7 +24,7 @@ - + From 32d8af316d55fcb1a2eba3ff9bf09ad0dba17812 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sat, 20 Jan 2024 02:14:21 +0800 Subject: [PATCH 05/25] restore changes --- test/OrchardCore.Tests/Apis/Context/SiteStartup.cs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs index 6b15aeb0e23..e021dea84ae 100644 --- a/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs +++ b/test/OrchardCore.Tests/Apis/Context/SiteStartup.cs @@ -1,10 +1,6 @@ -using NLog.Config; -using NLog.Web; -using NLog; using OrchardCore.Modules; using OrchardCore.Modules.Manifest; using OrchardCore.Recipes.Services; -using OrchardCore.Logging; namespace OrchardCore.Tests.Apis.Context { From 681dc52e63a43cc55b5b7b876af70e7af8968309 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sat, 20 Jan 2024 22:59:22 +0800 Subject: [PATCH 06/25] fix LockedAsyncFieldResolver --- .../GraphQLMiddleware.cs | 4 +- .../GraphQL/SiteLayersQuery.cs | 5 +- .../GraphQL/SiteCulturesQuery.cs | 4 +- .../GraphQL/MediaAssetQuery.cs | 4 +- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 55 +++++++++++-------- .../Resolvers/LockedAsyncFieldResolver.cs | 13 ++--- .../Queries/ContentItemsFieldType.cs | 5 +- .../GraphQL/ContentItemsFieldTypeTests.cs | 38 +++++++------ 8 files changed, 69 insertions(+), 59 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index 2981b027566..985a66c16c4 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -58,8 +58,8 @@ public async Task Invoke(HttpContext context, IAuthorizationService authorizatio { context.User = authenticateResult.Principal; } - - var authorized = await authorizationService.AuthorizeAsync(context.User, Permissions.ExecuteGraphQL); + var authorizationService = context.RequestServices.GetService(); + var authorized = await _authorizationService.AuthorizeAsync(context.User, Permissions.ExecuteGraphQL); if (authorized) { diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs index 411b1a342c8..5c34972ad69 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/SiteLayersQuery.cs @@ -41,7 +41,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteLayers", Description = S["Site layers define the rules and zone placement for widgets."], Type = typeof(ListGraphType), - Resolver = new LockedAsyncFieldResolver(ResolveAsync) + Resolver = new LockedAsyncFieldResolver>(ResolveAsync) }; schema.Query.AddField(field); @@ -49,11 +49,10 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private async Task ResolveAsync(IResolveFieldContext resolveContext) + private async ValueTask> ResolveAsync(IResolveFieldContext resolveContext) { var layerService = resolveContext.RequestServices.GetService(); var allLayers = await layerService.GetLayersAsync(); - return allLayers.Layers; } } diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs index b89c361cf33..a6c76859b2c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/SiteCulturesQuery.cs @@ -50,7 +50,7 @@ public Task BuildAsync(ISchema schema) Name = "SiteCultures", Description = S["The active cultures configured for the site."], Type = typeof(ListGraphType), - Resolver = new LockedAsyncFieldResolver(ResolveAsync) + Resolver = new LockedAsyncFieldResolver>(ResolveAsync) }; schema.Query.AddField(field); @@ -58,7 +58,7 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private async Task ResolveAsync(IResolveFieldContext resolveContext) + private async ValueTask> ResolveAsync(IResolveFieldContext resolveContext) { var localizationService = resolveContext.RequestServices.GetService(); diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs index 30e9298e9b3..447ef3bac0b 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetQuery.cs @@ -53,7 +53,7 @@ public Task BuildAsync(ISchema schema) Description = S["Whether to get the assets from just the top directory or from all sub-directories as well."] } ), - Resolver = new LockedAsyncFieldResolver(ResolveAsync) + Resolver = new LockedAsyncFieldResolver>(ResolveAsync) }; schema.Query.AddField(field); @@ -61,7 +61,7 @@ public Task BuildAsync(ISchema schema) return Task.CompletedTask; } - private async Task ResolveAsync(IResolveFieldContext resolveContext) + private async ValueTask> ResolveAsync(IResolveFieldContext resolveContext) { var mediaFileStore = resolveContext.RequestServices.GetService(); diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index 36801e4cd27..4fad4f7b2aa 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using GraphQL; +using GraphQL.Resolvers; using GraphQL.Types; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -105,29 +106,37 @@ private static FieldType BuildSchemaBasedFieldType(SqlQuery query, JToken queryS if (type == "string") { - var field = typetype.Field( - typeof(StringGraphType), - nameLower, - description: description, - resolve: context => + var field = new FieldType() + { + Name = nameLower, + Description = description, + Type = typeof(StringGraphType), + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); - }); + }), + }; field.Metadata.Add("Name", name); + typetype.AddField(field); } else if (type == "integer") { - var field = typetype.Field( - typeof(IntGraphType), - nameLower, - description: description, - resolve: context => + + var field = new FieldType() + { + Name = nameLower, + Description = description, + Type = typeof(IntGraphType), + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); - }); + }), + }; + field.Metadata.Add("Name", name); + typetype.AddField(field); } } @@ -144,21 +153,21 @@ private static FieldType BuildSchemaBasedFieldType(SqlQuery query, JToken queryS Type = typeof(ListGraphType>) }; - async ValueTask ResolveAsync(IResolveFieldContext context) - { - var queryManager = context.RequestServices.GetService(); - var iquery = await queryManager.GetQueryAsync(query.Name); + async ValueTask ResolveAsync(IResolveFieldContext context) + { + var queryManager = context.RequestServices.GetService(); + var iquery = await queryManager.GetQueryAsync(query.Name); - var parameters = context.GetArgument("parameters"); + var parameters = context.GetArgument("parameters"); - var queryParameters = parameters != null ? - JsonConvert.DeserializeObject>(parameters) - : new Dictionary(); + var queryParameters = parameters != null ? + JsonConvert.DeserializeObject>(parameters) + : new Dictionary(); - var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); + var result = await queryManager.ExecuteQueryAsync(iquery, queryParameters); - return result.Items; - } + return result.Items; + } return fieldType; } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs index 98dfbfaf04a..69ad5cbc625 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Resolvers/LockedAsyncFieldResolver.cs @@ -5,24 +5,21 @@ namespace OrchardCore.Apis.GraphQL.Resolvers { - public class LockedAsyncFieldResolver : IFieldResolver + public class LockedAsyncFieldResolver : FuncFieldResolver { - private readonly Func> _resolver; - - public LockedAsyncFieldResolver(Func> resolver) + public LockedAsyncFieldResolver(Func> resolver) : base(resolver) { - _resolver = resolver; + } - public async ValueTask ResolveAsync(IResolveFieldContext context) + public new async ValueTask ResolveAsync(IResolveFieldContext context) { var graphContext = (GraphQLUserContext)context.UserContext; - await graphContext.ExecutionContextLock.WaitAsync(); try { - return _resolver(context); + return await base.ResolveAsync(context); } finally { diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 5dfa7e445c0..906d52d9f53 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -55,7 +55,7 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions { Name = "status", Description = "publication status of the content item", ResolvedType = new PublicationStatusGraphType(), DefaultValue = PublicationStatusEnum.Published } ); - Resolver = new LockedAsyncFieldResolver(Resolve); + Resolver = new LockedAsyncFieldResolver>(Resolve); schema.RegisterType(whereInput); schema.RegisterType(orderByInput); @@ -64,7 +64,8 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions Resolve(IResolveFieldContext context) + private async ValueTask> Resolve(IResolveFieldContext context) + { var versionOption = VersionOptions.Published; diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs index 1fef46ce37d..7374c70463f 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs @@ -135,8 +135,9 @@ public async Task ShouldFilterByContentItemIndex() var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); + var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver) + .ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -171,8 +172,8 @@ public async Task ShouldFilterByContentItemIndexWhenSqlTablePrefixIsUsed() var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); + var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -205,10 +206,13 @@ public async Task ShouldFilterByAliasIndexRegardlessOfInputFieldCase(string fiel await session.SaveAsync(ci); await session.SaveChangesAsync(); - var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); + var type = new ContentItemsFieldType("Animal", + new Schema(services), + Options.Create(new GraphQLContentOptions()), + Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse(string.Concat("{ ", fieldName, ": { name: \"doug\" } }")), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse(string.Concat("{ ", fieldName, ": { name: \"doug\" } }")), ArgumentSource.Variable); + var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -240,14 +244,14 @@ public async Task ShouldBeAbleToUseTheSameIndexForMultipleAliases() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ cats: { name: \"doug\" } }"), ArgumentSource.Variable); - var cats = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ cats: { name: \"doug\" } }"), ArgumentSource.Variable); + var cats = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(cats); Assert.Equal("doug", cats.First().As().Name); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ dogs: { name: \"doug\" } }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ dogs: { name: \"doug\" } }"), ArgumentSource.Variable); + var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -291,8 +295,8 @@ public async Task ShouldFilterOnMultipleIndexesOnSameAlias() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animals: { name: \"doug\", isScary: true } }"), ArgumentSource.Variable); - var animals = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animals: { name: \"doug\", isScary: true } }"), ArgumentSource.Variable); + var animals = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(animals); Assert.Equal("doug", animals.First().As().Name); @@ -326,8 +330,8 @@ public async Task ShouldFilterPartsWithoutAPrefixWhenThePartHasNoPrefix() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animal: { name: \"doug\" } }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animal: { name: \"doug\" } }"), ArgumentSource.Variable); + var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -359,8 +363,8 @@ public async Task ShouldFilterByCollapsedWhereInputForCollapsedParts() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); - context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ name: \"doug\" }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver)type.Resolver).ResolveAsync(context)) as IEnumerable; + context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ name: \"doug\" }"), ArgumentSource.Variable); + var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); From 9d71c8b2a654691103d05e76cd82ee7a23c89a8f Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sun, 21 Jan 2024 01:32:47 +0800 Subject: [PATCH 07/25] try upgrade graphql 7.7.2 --- src/OrchardCore.Build/Dependencies.props | 8 +++--- .../GraphQLMiddleware.cs | 26 ++++++++--------- .../Services/SchemaService.cs | 24 ++++++++++------ .../OrchardCore.Apis.GraphQL/Startup.cs | 7 +++-- .../MaxNumberOfResultsValidationRule.cs | 8 ++---- .../GraphQL/LocalizationQueryObjectType.cs | 2 +- .../GraphQL/BagPartQueryObjectType.cs | 3 +- .../GraphQL/FlowMetadataContentTypeBuilder.cs | 6 ++-- .../GraphQL/FlowPartQueryObjectType.cs | 7 ++--- .../GraphQL/LabelPartQueryObjectType.cs | 5 +--- .../GraphQL/LayerQueryObjectType.cs | 2 +- .../GraphQL/LayerWidgetQueryObjectType.cs | 28 ++++++++----------- .../GraphQL/ListQueryObjectType.cs | 7 ++--- .../GraphQL/CultureQueryObjectType.cs | 4 +-- .../GraphQL/MarkdownBodyQueryObjectType.cs | 3 +- .../GraphQL/MarkdownFieldQueryObjectType.cs | 3 +- .../GraphQL/MediaAssetObjectType.cs | 7 +++-- .../GraphQL/MediaFieldQueryObjectType.cs | 6 ++-- .../GraphQL/MenuItemContentTypeBuilder.cs | 11 +++++--- .../GraphQL/MenuItemInterface.cs | 11 +++++++- .../GraphQL/MenuItemsListQueryObjectType.cs | 7 ++--- .../GraphQL/MetaEntryQueryObjectType.cs | 3 +- .../GraphQL/SeoMetaQueryObjectType.cs | 12 +++----- .../GraphQL/TaxonomyFieldQueryObjectType.cs | 12 +++----- .../GraphQL/TaxonomyPartQueryObjectType.cs | 3 +- .../FieldBuilderResolverExtensions.cs | 22 +++++++++++++++ .../Queries/PublicationStatusGraphType.cs | 1 + .../Queries/Types/ContentItemInterface.cs | 8 ++++-- test/OrchardCore.Tests/NLog.config | 2 +- 29 files changed, 131 insertions(+), 117 deletions(-) diff --git a/src/OrchardCore.Build/Dependencies.props b/src/OrchardCore.Build/Dependencies.props index 31e6930f701..6c36d8c2091 100644 --- a/src/OrchardCore.Build/Dependencies.props +++ b/src/OrchardCore.Build/Dependencies.props @@ -21,10 +21,10 @@ - - - - + + + + diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index 985a66c16c4..2ae7f565631 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -18,15 +18,15 @@ using Microsoft.AspNetCore.Mvc.Formatters; using Microsoft.CodeAnalysis; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; using OrchardCore.Apis.GraphQL.Queries; using OrchardCore.Apis.GraphQL.ValidationRules; using OrchardCore.Routing; namespace OrchardCore.Apis.GraphQL { - public class GraphQLMiddleware + public class GraphQLMiddleware : IMiddleware { - private readonly RequestDelegate _next; private readonly GraphQLSettings _settings; private readonly IDocumentExecuter _executer; internal static readonly Encoding _utf8Encoding = new UTF8Encoding(false); @@ -35,35 +35,32 @@ public class GraphQLMiddleware private readonly static JsonSerializerOptions _jsonSerializerOptions = new() { WriteIndented = false, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; public GraphQLMiddleware( - RequestDelegate next, - GraphQLSettings settings, + IOptions settingsOption, IDocumentExecuter executer) { - _next = next; - _settings = settings; + _settings = settingsOption.Value; _executer = executer; } - - public async Task Invoke(HttpContext context, IAuthorizationService authorizationService, IAuthenticationService authenticationService, ISchemaFactory schemaService, IGraphQLSerializer graphQLSerializer) + public async Task InvokeAsync(HttpContext context, RequestDelegate next) { if (!IsGraphQLRequest(context)) { - await _next(context); + await next(context); } else { + var authenticationService = context.RequestServices.GetService(); var authenticateResult = await authenticationService.AuthenticateAsync(context, "Api"); - if (authenticateResult.Succeeded) { context.User = authenticateResult.Principal; } var authorizationService = context.RequestServices.GetService(); - var authorized = await _authorizationService.AuthorizeAsync(context.User, Permissions.ExecuteGraphQL); + var authorized = await authorizationService.AuthorizeAsync(context.User, Permissions.ExecuteGraphQL); if (authorized) { - await ExecuteAsync(context, schemaService, graphQLSerializer); + await ExecuteAsync(context); } else { @@ -71,15 +68,15 @@ public async Task Invoke(HttpContext context, IAuthorizationService authorizatio } } } - private bool IsGraphQLRequest(HttpContext context) { return context.Request.Path.StartsWithNormalizedSegments(_settings.Path, StringComparison.OrdinalIgnoreCase); } - private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaService, IGraphQLSerializer graphQLSerializer) + private async Task ExecuteAsync(HttpContext context) { GraphQLRequest request = null; + var graphQLSerializer = context.RequestServices.GetService(); // c.f. https://graphql.org/learn/serving-over-http/#post-request @@ -140,6 +137,7 @@ private async Task ExecuteAsync(HttpContext context, ISchemaFactory schemaServic queryToExecute = queries[request.NamedQuery]; } + var schemaService = context.RequestServices.GetService(); var schema = await schemaService.GetSchemaAsync(); var dataLoaderDocumentListener = context.RequestServices.GetRequiredService(); var result = await _executer.ExecuteAsync(options => diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index bda808c37f6..0b69b14c158 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -72,15 +72,21 @@ public async Task GetSchemaAsync() NameConverter = new OrchardFieldNameConverter(), }; - foreach (var type in serviceProvider.GetServices()) - { - schema.RegisterType(type); - } - - foreach (var type in serviceProvider.GetServices()) - { - schema.RegisterType(type); - } + //foreach (var type in serviceProvider.GetServices()) + //{ + // if (!schema.AdditionalTypeInstances.Any(t => t == type)) + // { + // schema.RegisterType(type); + // } + //} + + //foreach (var type in serviceProvider.GetServices()) + //{ + // if (!schema.AdditionalTypeInstances.Any(t => t == type)) + // { + // schema.RegisterType(type); + // } + //} foreach (var builder in _schemaBuilders) { diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs index 3b1cd1799dc..620cd2002c0 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs @@ -47,11 +47,14 @@ public override void ConfigureServices(IServiceCollection services) services.AddSingleton(services => { var settings = services.GetRequiredService>(); - return new ErrorInfoProvider(new ErrorInfoProviderOptions { ExposeExceptionStackTrace = settings.Value.ExposeExceptions }); + return new ErrorInfoProvider(new ErrorInfoProviderOptions { ExposeExceptionDetails = settings.Value.ExposeExceptions }); }); services.AddScoped(); services.AddTransient(); + services.AddSingleton(); + services.AddGraphQL(builder => builder.AddSystemTextJson() + .AddAutoClrMappings(false, false)); services.AddOptions().Configure((c, configuration) => { @@ -90,7 +93,7 @@ public override void Configure(IApplicationBuilder app, IEndpointRouteBuilder ro defaults: new { controller = typeof(AdminController).ControllerName(), action = nameof(AdminController.Index) } ); - app.UseMiddleware(serviceProvider.GetService>().Value); + app.UseMiddleware(); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs index fec97200811..69059aa5380 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/ValidationRules/MaxNumberOfResultsValidationRule.cs @@ -40,7 +40,7 @@ public ValueTask ValidateAsync(ValidationContext validationContext if (arg.Value is GraphQLIntValue) { - value = Int32.Parse((arg.Value as GraphQLIntValue).Value); + value = int.Parse((arg.Value as GraphQLIntValue).Value); } else { @@ -66,11 +66,7 @@ public ValueTask ValidateAsync(ValidationContext validationContext { _logger.LogInformation(errorMessage); - arg = new GraphQLArgument - { - Name = arg.Name, - Value = new GraphQLIntValue(_maxNumberOfResults) - }; // if disabled mode we just log info and override the arg to be maxvalue + arg = new GraphQLArgument(arg.Name, new GraphQLIntValue(_maxNumberOfResults)); // if disabled mode we just log info and override the arg to be maxvalue } } } diff --git a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs index e4e9f1c2842..bdc22b2e14f 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentLocalization/GraphQL/LocalizationQueryObjectType.cs @@ -24,7 +24,7 @@ public LocalizationQueryObjectType(IStringLocalizer Field, IEnumerable>("Localizations") .Description(S["The localizations of the content item."]) - .Argument("culture", "the culture of the content item") + .Argument("culture", "the culture of the content item") .ResolveLockedAsync(GetContentItemsByLocalizationSetAsync); } diff --git a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/BagPartQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/BagPartQueryObjectType.cs index 5af59b8c899..bd7d7bd17af 100644 --- a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/BagPartQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/BagPartQueryObjectType.cs @@ -15,8 +15,7 @@ public BagPartQueryObjectType(IStringLocalizer S) Name = "BagPart"; Description = S["A BagPart allows to add content items directly within another content item"]; - Field, IEnumerable>() - .Name("contentItems") + Field, IEnumerable>("contentItems") .Description("the content items") .PagingArguments() .Resolve(x => x.Page(x.Source.ContentItems)); diff --git a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs index 0f00e82d58c..79a62f2e601 100644 --- a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowMetadataContentTypeBuilder.cs @@ -15,10 +15,8 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin return; } - contentItemType.Field( - "metadata", - resolve: context => context.Source.As() - ); + contentItemType.Field("metadata") + .Resolve(context => context.Source.As()); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowPartQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowPartQueryObjectType.cs index 5e71563b04b..7f3019906be 100644 --- a/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowPartQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Flows/GraphQL/FlowPartQueryObjectType.cs @@ -12,10 +12,9 @@ public FlowPartQueryObjectType(IStringLocalizer S) Name = "FlowPart"; Description = S["A FlowPart allows to add content items directly within another content item"]; - Field>( - "widgets", - "The widgets.", - resolve: context => context.Source.Widgets); + Field>("widgets") + .Description("The widgets.") + .Resolve(context => context.Source.Widgets); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Forms/GraphQL/LabelPartQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Forms/GraphQL/LabelPartQueryObjectType.cs index e91a7b76c73..a034917d3d9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Forms/GraphQL/LabelPartQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Forms/GraphQL/LabelPartQueryObjectType.cs @@ -10,10 +10,7 @@ public LabelPartQueryObjectType() Name = "LabelPart"; Field(x => x.For, nullable: true); - Field("value", resolve: context => - { - return context.Source.ContentItem.DisplayText; - }); + Field("value", context => context.ContentItem.DisplayText); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs index 3ff02bf6e7d..aabec619a61 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerQueryObjectType.cs @@ -32,7 +32,7 @@ public LayerQueryObjectType() Field(layer => layer.Description).Description("The description of the layer."); Field, IEnumerable>("widgets") .Description("The widgets for this layer.") - .Argument("status", "publication status of the widgets") + .Argument("status", "publication status of the widgets") .ResolveLockedAsync(GetWidgetsForLayerAsync); async ValueTask> GetWidgetsForLayerAsync(IResolveFieldContext context) diff --git a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerWidgetQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerWidgetQueryObjectType.cs index b553f3d94cd..ac252281451 100644 --- a/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerWidgetQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Layers/GraphQL/LayerWidgetQueryObjectType.cs @@ -11,25 +11,21 @@ public LayerWidgetQueryObjectType() { Name = "LayerWidget"; - Field( - "zone", - "The name of the widget's zone.", - resolve: context => context.Source.As()?.Zone); + Field("zone") + .Description("The name of the widget's zone.") + .Resolve(context => context.Source.As()?.Zone); - Field( - "position", - "The position of the widget in the zone.", - resolve: context => context.Source.As()?.Position); + Field("position") + .Description("The position of the widget in the zone.") + .Resolve(context => context.Source.As()?.Position); - Field( - "renderTitle", - "Whether to render the widget's title.", - resolve: context => context.Source.As()?.RenderTitle); + Field("renderTitle") + .Description("Whether to render the widget's title.") + .Resolve(context => context.Source.As()?.RenderTitle); - Field( - "widget", - "A widget on this layer.", - resolve: context => context.Source); + Field("widget") + .Description("A widget on this layer.") + .Resolve(context => context.Source); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Lists/GraphQL/ListQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Lists/GraphQL/ListQueryObjectType.cs index 72c33445cdf..246cc35bdb6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Lists/GraphQL/ListQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Lists/GraphQL/ListQueryObjectType.cs @@ -24,11 +24,10 @@ public ListQueryObjectType(IStringLocalizer S) Name = "ListPart"; Description = S["Represents a collection of content items."]; - Field, IEnumerable>() - .Name("contentItems") + Field, IEnumerable>("contentItems") .Description("the content items") - .Argument("first", "the first n elements (10 by default)", 10) - .Argument("skip", "the number of elements to skip", 0) + .Argument("first", "the first n elements (10 by default)", config => config.DefaultValue = 10) + .Argument("skip", "the number of elements to skip", config => config.DefaultValue = 0) // Important to use ResolveLockedAsync to prevent concurrency error on database query, when using nested content items with List part .ResolveLockedAsync(async g => { diff --git a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/CultureQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/CultureQueryObjectType.cs index 760181eab89..30d9a0d2a83 100644 --- a/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/CultureQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Localization/GraphQL/CultureQueryObjectType.cs @@ -14,8 +14,8 @@ public CultureQueryObjectType() { Name = "SiteCulture"; - Field("culture", "The culture code.", resolve: context => context.Source.Culture); - Field("default", "Whether this is the default culture.", resolve: context => context.Source.IsDefault); + Field("culture").Description("The culture code.").Resolve(context => context.Source.Culture); + Field("default").Description("Whether this is the default culture.").Resolve(context => context.Source.IsDefault); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs index 3dfaf2dd3e4..9614f1a2ee2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownBodyQueryObjectType.cs @@ -29,8 +29,7 @@ public MarkdownBodyQueryObjectType(IStringLocalizer Field("markdown", x => x.Markdown, nullable: true) .Description(S["the markdown value"]); - Field() - .Name("html") + Field("html") .Description(S["the HTML representation of the markdown content"]) .ResolveLockedAsync(ToHtml); } diff --git a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs index d9384b61178..e5b8cdd06d2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Markdown/GraphQL/MarkdownFieldQueryObjectType.cs @@ -31,8 +31,7 @@ public MarkdownFieldQueryObjectType(IStringLocalizer x.Markdown, nullable: true) .Description(S["the markdown value"]); - Field() - .Name("html") + Field("html") .Description(S["the HTML representation of the markdown content"]) .ResolveLockedAsync(ToHtml); } diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetObjectType.cs index eb7d5f63a24..467c5478e47 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaAssetObjectType.cs @@ -12,8 +12,7 @@ public MediaAssetObjectType() Field(file => file.Name).Description("The name of the asset."); - Field() - .Name("path") + Field("path") .Description("The url to the asset.") .Resolve(x => { @@ -23,7 +22,9 @@ public MediaAssetObjectType() }); Field(file => file.Length).Description("The length of the file."); - Field("lastModifiedUtc", resolve: file => file.Source.LastModifiedUtc, description: "The date and time in UTC when the asset was last modified."); + Field("lastModifiedUtc") + .Description("The date and time in UTC when the asset was last modified.") + .Resolve(file => file.Source.LastModifiedUtc); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs index 2f9b2cf328c..f2c7513c195 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs @@ -14,8 +14,7 @@ public MediaFieldQueryObjectType() { Name = nameof(MediaField); - Field, IEnumerable>() - .Name("paths") + Field, IEnumerable>("paths") .Description("the media paths") .PagingArguments() .Resolve(x => @@ -27,8 +26,7 @@ public MediaFieldQueryObjectType() return x.Page(x.Source.Paths); }); - Field, IEnumerable>() - .Name("urls") + Field, IEnumerable>("urls") .Description("the absolute urls of the media items") .PagingArguments() .Resolve(x => diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs index 6f2ec541b5b..ead2711ce86 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemContentTypeBuilder.cs @@ -1,3 +1,4 @@ +using GraphQL.Resolvers; using GraphQL.Types; using OrchardCore.ContentManagement; using OrchardCore.ContentManagement.GraphQL; @@ -16,10 +17,12 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin return; } - contentItemType.Field( - nameof(MenuItemsListPart).ToFieldName(), - resolve: context => context.Source.As() - ); + contentItemType.AddField(new FieldType + { + Type = typeof(MenuItemsListQueryObjectType), + Name = nameof(MenuItemsListPart).ToFieldName(), + Resolver = new FuncFieldResolver(context => context.Source.As()) + }); contentItemType.Interface(); } diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs index 263ec1afe19..64f8d309db7 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs @@ -1,3 +1,4 @@ +using GraphQL.Resolvers; using GraphQL.Types; using OrchardCore.ContentManagement; using OrchardCore.Menu.Models; @@ -9,8 +10,16 @@ public class MenuItemInterface : InterfaceGraphType public MenuItemInterface() { Name = "MenuItem"; + AddField(new FieldType() + { + Name = "menuItemsList", + ResolvedType = new MenuItemsListQueryObjectType(), + Resolver = new FuncFieldResolver(context => + { + return context.Source.As(); + }) - Field(typeof(MenuItemsListQueryObjectType), "menuItemsList", resolve: context => context.Source.As()); + }); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs index 486f2c74022..3b9d3d0ce53 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs @@ -9,10 +9,9 @@ public MenuItemsListQueryObjectType() { Name = "MenuItemsListPart"; - Field>( - "menuItems", - "The menu items.", - resolve: context => context.Source.MenuItems); + Field>("menuItems") + .Description("The menu items.") + .Resolve(context => context.Source.MenuItems); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/MetaEntryQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/MetaEntryQueryObjectType.cs index d472b4db559..b5cbb860867 100644 --- a/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/MetaEntryQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/MetaEntryQueryObjectType.cs @@ -23,8 +23,7 @@ public MetaEntryQueryObjectType(IStringLocalizer S) .Description("HttpEquiv of the meta entry"); Field(x => x.Charset) .Description("Charset of the meta entry"); - Field() - .Name("Tag") + Field("Tag") .Description("The generated tag of the meta entry") .Resolve(ctx => { diff --git a/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/SeoMetaQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/SeoMetaQueryObjectType.cs index 573ce38c17e..a3d92ff2fa0 100644 --- a/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/SeoMetaQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Seo/GraphQL/SeoMetaQueryObjectType.cs @@ -26,16 +26,13 @@ public SeoMetaQueryObjectType(IStringLocalizer S) Field(x => x.MetaRobots, true) .Description("The content item specific meta robots definition"); - Field>() - .Name("customMetaTags") + Field>("customMetaTags") .Resolve(ctx => ctx.Source.CustomMetaTags); - Field>() - .Name("defaultSocialImage") + Field>("defaultSocialImage") .Resolve(ctx => ctx.Source.DefaultSocialImage); - Field>() - .Name("openGraphImage") + Field>("openGraphImage") .Resolve(ctx => ctx.Source.OpenGraphImage); Field(x => x.OpenGraphType, true) @@ -45,8 +42,7 @@ public SeoMetaQueryObjectType(IStringLocalizer S) Field(x => x.OpenGraphDescription, true) .Description("The seo meta opengraph description"); - Field>() - .Name("twitterImage") + Field>("twitterImage") .Resolve(ctx => ctx.Source.TwitterImage); Field(x => x.TwitterTitle, true) diff --git a/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs index 579054dde7e..0392df3a1f0 100644 --- a/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyFieldQueryObjectType.cs @@ -15,8 +15,7 @@ public TaxonomyFieldQueryObjectType() { Name = nameof(TaxonomyField); - Field, IEnumerable>() - .Name("termContentItemIds") + Field, IEnumerable>("termContentItemIds") .Description("term content item ids") .PagingArguments() .Resolve(x => @@ -24,16 +23,14 @@ public TaxonomyFieldQueryObjectType() return x.Page(x.Source.TermContentItemIds); }); - Field() - .Name("taxonomyContentItemId") + Field("taxonomyContentItemId") .Description("taxonomy content item id") .Resolve(x => { return x.Source.TaxonomyContentItemId; }); - Field, List>() - .Name("termContentItems") + Field, List>("termContentItems") .Description("the term content items") .PagingArguments() .ResolveLockedAsync(async x => @@ -59,8 +56,7 @@ public TaxonomyFieldQueryObjectType() return terms; }); - Field() - .Name("taxonomyContentItem") + Field("taxonomyContentItem") .Description("the taxonomy content item") .ResolveLockedAsync(async context => { diff --git a/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyPartQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyPartQueryObjectType.cs index 4475ca4c1a5..f1fe006fa68 100644 --- a/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyPartQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Taxonomies/GraphQL/TaxonomyPartQueryObjectType.cs @@ -15,8 +15,7 @@ public TaxonomyPartQueryObjectType() Field(x => x.TermContentType); - Field, IEnumerable>() - .Name("contentItems") + Field, IEnumerable>("contentItems") .Description("the content items") .PagingArguments() .Resolve(x => x.Page(x.Source.Terms)); diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs index d3c507b26da..54e3b85d766 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs @@ -2,6 +2,9 @@ using System.Threading.Tasks; using GraphQL; using GraphQL.Builders; +using GraphQL.Resolvers; +using GraphQL.Types; +using Newtonsoft.Json.Linq; using OrchardCore.Apis.GraphQL.Resolvers; namespace OrchardCore.Apis.GraphQL @@ -12,5 +15,24 @@ public static FieldBuilder ResolveLockedAsync(resolve)); } + + public static FieldType AddField(this ComplexGraphType graphType, string name, Func, TOutType> resolve, string description = null) + { + + var fieldType = new FieldType() + { + Name = name, + Type = typeof(IntGraphType), + Resolver = new FuncFieldResolver(resolve) + }; + + if (description != null) + { + fieldType.Description = description; + } + + graphType.AddField(fieldType); + return fieldType; + } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs index 8dcefd2e92d..8673448d204 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/PublicationStatusGraphType.cs @@ -1,3 +1,4 @@ +using System; using GraphQL.Types; namespace OrchardCore.ContentManagement.GraphQL.Queries; diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs index 366a6c3980a..36d0768c48a 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/ContentItemInterface.cs @@ -1,3 +1,5 @@ +using System; +using GraphQL.Resolvers; using GraphQL.Types; using Microsoft.Extensions.Options; using OrchardCore.ContentManagement.GraphQL.Options; @@ -20,9 +22,9 @@ public ContentItemInterface(IOptions optionsAccessor) Field(ci => ci.DisplayText, nullable: true); Field(ci => ci.Published); Field(ci => ci.Latest); - Field("modifiedUtc").Resolve(ci => ci.Source.ModifiedUtc); - Field("publishedUtc").Resolve(ci => ci.Source.PublishedUtc); - Field("createdUtc").Resolve(ci => ci.Source.CreatedUtc); + Field(ci => ci.ModifiedUtc, nullable: true); + Field(ci => ci.PublishedUtc, nullable: true); + Field(ci => ci.CreatedUtc, nullable: true); Field(ci => ci.Owner); Field(ci => ci.Author); } diff --git a/test/OrchardCore.Tests/NLog.config b/test/OrchardCore.Tests/NLog.config index fe628219a48..49797bb43ce 100644 --- a/test/OrchardCore.Tests/NLog.config +++ b/test/OrchardCore.Tests/NLog.config @@ -13,7 +13,7 @@ From 5007446b1d4dc9dda6df0c64357d9771da2bc617 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sun, 21 Jan 2024 16:15:06 +0800 Subject: [PATCH 08/25] try remove all schema.RegisterType() --- .../Services/SchemaService.cs | 2 +- .../FieldBuilderResolverExtensions.cs | 22 ------------------- .../ServiceCollectionExtensions.cs | 12 +++++----- .../Queries/ContentItemsFieldType.cs | 6 ++--- .../Queries/ContentTypeQuery.cs | 2 +- 5 files changed, 11 insertions(+), 33 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 0b69b14c158..541299a76a9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -82,7 +82,7 @@ public async Task GetSchemaAsync() //foreach (var type in serviceProvider.GetServices()) //{ - // if (!schema.AdditionalTypeInstances.Any(t => t == type)) + // if (type != null && !schema.AdditionalTypeInstances.Any(t => t == type)) // { // schema.RegisterType(type); // } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs index 54e3b85d766..d3c507b26da 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/Extensions/FieldBuilderResolverExtensions.cs @@ -2,9 +2,6 @@ using System.Threading.Tasks; using GraphQL; using GraphQL.Builders; -using GraphQL.Resolvers; -using GraphQL.Types; -using Newtonsoft.Json.Linq; using OrchardCore.Apis.GraphQL.Resolvers; namespace OrchardCore.Apis.GraphQL @@ -15,24 +12,5 @@ public static FieldBuilder ResolveLockedAsync(resolve)); } - - public static FieldType AddField(this ComplexGraphType graphType, string name, Func, TOutType> resolve, string description = null) - { - - var fieldType = new FieldType() - { - Name = name, - Type = typeof(IntGraphType), - Resolver = new FuncFieldResolver(resolve) - }; - - if (description != null) - { - fieldType.Description = description; - } - - graphType.AddField(fieldType); - return fieldType; - } } } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs index 4d58122d4dd..62f76df573c 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs @@ -17,9 +17,9 @@ public static void AddInputObjectGraphType(this IServiceCo { // Instances are registered as singletons as their constructor holds the logic to configure the type // and doesn't need to run every time - services.AddSingleton(); - services.AddSingleton, TObjectType>(s => s.GetRequiredService()); - services.AddSingleton(s => s.GetRequiredService()); + //services.AddSingleton(); + //services.AddSingleton, TObjectType>(s => s.GetRequiredService()); + //services.AddSingleton(s => s.GetRequiredService()); } /// @@ -34,9 +34,9 @@ public static void AddObjectGraphType(this IServiceCollectio { // Instances are registered as singletons as their constructor holds the logic to configure the type // and doesn't need to run every time - services.AddSingleton(); - services.AddSingleton, TInputType>(s => s.GetRequiredService()); - services.AddSingleton(s => s.GetRequiredService()); + //services.AddSingleton(); + //services.AddSingleton, TInputType>(s => s.GetRequiredService()); + //services.AddSingleton(s => s.GetRequiredService()); } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 906d52d9f53..c691101ecd0 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -57,9 +57,9 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions>(Resolve); - schema.RegisterType(whereInput); - schema.RegisterType(orderByInput); - schema.RegisterType(); + //schema.RegisterType(whereInput); + //schema.RegisterType(orderByInput); + //schema.RegisterType(); _defaultNumberOfItems = settingsAccessor.Value.DefaultNumberOfResults; } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs index 3a90f4aadd6..9dac12e8861 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs @@ -83,7 +83,7 @@ public async Task BuildAsync(ISchema schema) else { // Register the content item type explicitly since it won't be discovered from the root 'query' type. - schema.RegisterType(typeType); + //schema.RegisterType(typeType); } } From 2349912fddf6b3668af75b2a8e642de18251df3b Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Sun, 21 Jan 2024 16:36:31 +0800 Subject: [PATCH 09/25] update dynamic field --- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 3 +- .../GraphQL/ElasticQueryFieldTypeProvider.cs | 32 ++++++++++++------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index 4fad4f7b2aa..218490ca12b 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -122,7 +122,6 @@ private static FieldType BuildSchemaBasedFieldType(SqlQuery query, JToken queryS } else if (type == "integer") { - var field = new FieldType() { Name = nameLower, @@ -134,7 +133,7 @@ private static FieldType BuildSchemaBasedFieldType(SqlQuery query, JToken queryS return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); }), }; - + field.Metadata.Add("Name", name); typetype.AddField(field); } diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs index 75944ed5c23..1151cb72c61 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using GraphQL; +using GraphQL.Resolvers; using GraphQL.Types; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -106,29 +107,36 @@ private static FieldType BuildSchemaBasedFieldType(ElasticQuery query, JToken qu if (type == "string") { - var field = typetype.Field( - typeof(StringGraphType), - nameLower, - description: description, - resolve: context => + var field = new FieldType() + { + Name = nameLower, + Description = description, + Type = typeof(StringGraphType), + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); - }); + }), + }; field.Metadata.Add("Name", name); + typetype.AddField(field); } else if (type == "integer") { - var field = typetype.Field( - typeof(IntGraphType), - nameLower, - description: description, - resolve: context => + var field = new FieldType() + { + Name = nameLower, + Description = description, + Type = typeof(IntGraphType), + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); - }); + }), + }; + field.Metadata.Add("Name", name); + typetype.AddField(field); } } From 43e28bf66da80bc54d971531a2c164613cf349d9 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Mon, 22 Jan 2024 00:10:36 +0800 Subject: [PATCH 10/25] update MenuItemInterface --- .../OrchardCore.Menu/GraphQL/MenuItemInterface.cs | 2 +- .../ServiceCollectionExtensions.cs | 4 ++-- .../Queries/ContentTypeQuery.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs index 64f8d309db7..1ee8cf880dd 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs @@ -13,7 +13,7 @@ public MenuItemInterface() AddField(new FieldType() { Name = "menuItemsList", - ResolvedType = new MenuItemsListQueryObjectType(), + Type = typeof(MenuItemsListQueryObjectType), Resolver = new FuncFieldResolver(context => { return context.Source.As(); diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs index 62f76df573c..7e765513a79 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs @@ -17,7 +17,7 @@ public static void AddInputObjectGraphType(this IServiceCo { // Instances are registered as singletons as their constructor holds the logic to configure the type // and doesn't need to run every time - //services.AddSingleton(); + services.AddSingleton(); //services.AddSingleton, TObjectType>(s => s.GetRequiredService()); //services.AddSingleton(s => s.GetRequiredService()); } @@ -34,7 +34,7 @@ public static void AddObjectGraphType(this IServiceCollectio { // Instances are registered as singletons as their constructor holds the logic to configure the type // and doesn't need to run every time - //services.AddSingleton(); + services.AddSingleton(); //services.AddSingleton, TInputType>(s => s.GetRequiredService()); //services.AddSingleton(s => s.GetRequiredService()); } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs index 9dac12e8861..3a90f4aadd6 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentTypeQuery.cs @@ -83,7 +83,7 @@ public async Task BuildAsync(ISchema schema) else { // Register the content item type explicitly since it won't be discovered from the root 'query' type. - //schema.RegisterType(typeType); + schema.RegisterType(typeType); } } From a8b36e2c4f74544bf470ea50d03595c85efbf6fa Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Mon, 22 Jan 2024 17:30:54 +0800 Subject: [PATCH 11/25] fix LuceneQueryFieldTypeProvider --- .../GraphQL/LuceneQueryFieldTypeProvider.cs | 32 ++++++++++++------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs index c0481e9cca0..b246a551458 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading.Tasks; using GraphQL; +using GraphQL.Resolvers; using GraphQL.Types; using Microsoft.AspNetCore.Http; using Microsoft.Extensions.DependencyInjection; @@ -105,29 +106,36 @@ private static FieldType BuildSchemaBasedFieldType(LuceneQuery query, JToken que if (type == "string") { - var field = typetype.Field( - typeof(StringGraphType), - nameLower, - description: description, - resolve: context => + var field = new FieldType() + { + Name = nameLower, + Description = description, + Type = typeof(StringGraphType), + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); - }); + }), + }; field.Metadata.Add("Name", name); + typetype.AddField(field); } else if (type == "integer") { - var field = typetype.Field( - typeof(IntGraphType), - nameLower, - description: description, - resolve: context => + var field = new FieldType() + { + Name = nameLower, + Description = description, + Type = typeof(IntGraphType), + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); - }); + }), + }; + field.Metadata.Add("Name", name); + typetype.AddField(field); } } From c8e4062c3e96977785b04aae3a40eb6b49e03f45 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Mon, 22 Jan 2024 19:07:28 +0800 Subject: [PATCH 12/25] add types cache --- .../Queries/Types/TypedContentTypeBuilder.cs | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 3799aea215c..0bee0db822d 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -1,3 +1,5 @@ +using System; +using System.Collections.Concurrent; using System.Linq; using GraphQL; using GraphQL.Resolvers; @@ -14,7 +16,9 @@ public class TypedContentTypeBuilder : IContentTypeBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly GraphQLContentOptions _contentOptions; - + private readonly ConcurrentDictionary PartTypes = new(); + private readonly ConcurrentDictionary ObjectGraphTypePartTypes = new(); + private readonly ConcurrentDictionary InputObjectGraphTypePartTypes = new(); public TypedContentTypeBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor) { @@ -47,9 +51,12 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin continue; } - var activator = typeActivator.GetTypeActivator(part.PartDefinition.Name); + var partType = PartTypes.GetOrAdd(part.PartDefinition.Name, key => typeActivator.GetTypeActivator(key).Type); - var queryGraphType = typeof(ObjectGraphType<>).MakeGenericType(activator.Type); + var queryGraphType = ObjectGraphTypePartTypes.GetOrAdd(partType, key => + { + return typeof(ObjectGraphType<>).MakeGenericType(key); + }); var collapsePart = _contentOptions.ShouldCollapse(part); @@ -71,7 +78,7 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin Resolver = new FuncFieldResolver(context => { var nameToResolve = partName; - var resolvedPart = context.Source.Get(activator.Type, nameToResolve); + var resolvedPart = context.Source.Get(partType, nameToResolve); return field.Resolver.ResolveAsync(new ResolveFieldContext { @@ -103,12 +110,14 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin var typeToResolve = context.FieldDefinition.ResolvedType.GetType().BaseType.GetGenericArguments().First(); return context.Source.Get(typeToResolve, nameToResolve); - }); + }); } } - var inputGraphType = typeof(InputObjectGraphType<>).MakeGenericType(activator.Type); - + var inputGraphType = InputObjectGraphTypePartTypes.GetOrAdd(partType, key => + { + return typeof(InputObjectGraphType<>).MakeGenericType(key); + }); if (serviceProvider.GetService(inputGraphType) is IInputObjectGraphType inputGraphTypeResolved) { var whereArgument = contentQuery.Arguments.FirstOrDefault(x => x.Name == "where"); From 6701ff0a2e0fa8103a53f6bb1a037e7e4b9a576f Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Mon, 22 Jan 2024 21:46:05 +0800 Subject: [PATCH 13/25] try cache types --- .../GraphQL/Fields/ObjectGraphTypeFieldProvider.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs index 13216a9e260..8cb94ebbde3 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs @@ -1,3 +1,5 @@ +using System.Collections.Concurrent; +using System; using System.Linq; using GraphQL.Resolvers; using GraphQL.Types; @@ -13,6 +15,8 @@ public class ObjectGraphTypeFieldProvider : IContentFieldProvider { private readonly IHttpContextAccessor _httpContextAccessor; + private readonly ConcurrentDictionary ContentTypeTypes = new(); + private readonly ConcurrentDictionary ObjectGraphTypePartTypes = new(); public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; @@ -22,9 +26,9 @@ public FieldType GetField(ContentPartFieldDefinition field) { var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; var typeActivator = serviceProvider.GetService>(); - var activator = typeActivator.GetTypeActivator(field.FieldDefinition.Name); + var contentTypeType = ContentTypeTypes.GetOrAdd(field.FieldDefinition.Name, key => typeActivator.GetTypeActivator(key).Type); - var queryGraphType = typeof(ObjectGraphType<>).MakeGenericType(activator.Type); + var queryGraphType = ObjectGraphTypePartTypes.GetOrAdd(contentTypeType, key => typeof(ObjectGraphType<>).MakeGenericType(key)); if (serviceProvider.GetService(queryGraphType) is IObjectGraphType) { From 4afb0d2933b413ef7d4189709f31b12f1a090ac4 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Tue, 23 Jan 2024 02:31:17 +0800 Subject: [PATCH 14/25] search type from di --- .../GraphQLMiddleware.cs | 12 ++++--- .../Services/SchemaService.cs | 30 ++++++++--------- .../GraphQL/Fields/ContentFieldsProvider.cs | 4 ++- .../Fields/ObjectGraphTypeFieldProvider.cs | 13 +++----- .../GraphQL/MenuItemInterface.cs | 12 +------ .../GraphQL/MenuItemsListQueryObjectType.cs | 1 + .../ServiceCollectionExtensions.cs | 8 ++--- .../Queries/Types/TypedContentTypeBuilder.cs | 33 ++++++++----------- 8 files changed, 50 insertions(+), 63 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index 2ae7f565631..4e812183347 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -28,6 +28,7 @@ namespace OrchardCore.Apis.GraphQL public class GraphQLMiddleware : IMiddleware { private readonly GraphQLSettings _settings; + private readonly IGraphQLSerializer _serializer; private readonly IDocumentExecuter _executer; internal static readonly Encoding _utf8Encoding = new UTF8Encoding(false); private readonly static MediaType _jsonMediaType = new("application/json"); @@ -36,10 +37,12 @@ public class GraphQLMiddleware : IMiddleware public GraphQLMiddleware( IOptions settingsOption, - IDocumentExecuter executer) + IDocumentExecuter executer, + IGraphQLSerializer serializer) { _settings = settingsOption.Value; _executer = executer; + _serializer = serializer; } public async Task InvokeAsync(HttpContext context, RequestDelegate next) { @@ -60,7 +63,7 @@ public async Task InvokeAsync(HttpContext context, RequestDelegate next) if (authorized) { - await ExecuteAsync(context); + await ExecuteAsync(context); } else { @@ -76,7 +79,6 @@ private bool IsGraphQLRequest(HttpContext context) private async Task ExecuteAsync(HttpContext context) { GraphQLRequest request = null; - var graphQLSerializer = context.RequestServices.GetService(); // c.f. https://graphql.org/learn/serving-over-http/#post-request @@ -120,7 +122,7 @@ private async Task ExecuteAsync(HttpContext context) } catch (Exception e) { - await graphQLSerializer.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e); + await _serializer.WriteErrorAsync(context, "An error occurred while processing the GraphQL query", e); return; } @@ -167,7 +169,7 @@ private async Task ExecuteAsync(HttpContext context) context.Response.ContentType = MediaTypeNames.Application.Json; - await graphQLSerializer.WriteAsync(context.Response.Body, result); + await _serializer.WriteAsync(context.Response.Body, result); } private static GraphQLRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 541299a76a9..296810856e6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -72,21 +72,21 @@ public async Task GetSchemaAsync() NameConverter = new OrchardFieldNameConverter(), }; - //foreach (var type in serviceProvider.GetServices()) - //{ - // if (!schema.AdditionalTypeInstances.Any(t => t == type)) - // { - // schema.RegisterType(type); - // } - //} - - //foreach (var type in serviceProvider.GetServices()) - //{ - // if (type != null && !schema.AdditionalTypeInstances.Any(t => t == type)) - // { - // schema.RegisterType(type); - // } - //} + foreach (var type in serviceProvider.GetServices()) + { + if (!schema.AdditionalTypeInstances.Any(t => t == type)) + { + schema.RegisterType(type); + } + } + + foreach (var type in serviceProvider.GetServices()) + { + if (type != null && !schema.AdditionalTypeInstances.Any(t => t == type)) + { + schema.RegisterType(type); + } + } foreach (var builder in _schemaBuilders) { diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 59f55d66be8..7d7ac7f988f 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -95,7 +95,7 @@ public FieldType GetField(ContentPartFieldDefinition field) } var fieldDescriptor = _contentFieldTypeMappings[field.FieldDefinition.Name]; - return new FieldType + var fieldType = new FieldType { Name = field.Name, Description = fieldDescriptor.Description, @@ -115,6 +115,8 @@ public FieldType GetField(ContentPartFieldDefinition field) return contentField == null ? null : fieldDescriptor.FieldAccessor(contentField); }), }; + + return fieldType; } private class FieldTypeDescriptor diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs index 8cb94ebbde3..dc9f3408c7d 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs @@ -1,5 +1,6 @@ -using System.Collections.Concurrent; using System; +using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using GraphQL.Resolvers; using GraphQL.Types; @@ -25,18 +26,14 @@ public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) public FieldType GetField(ContentPartFieldDefinition field) { var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; - var typeActivator = serviceProvider.GetService>(); - var contentTypeType = ContentTypeTypes.GetOrAdd(field.FieldDefinition.Name, key => typeActivator.GetTypeActivator(key).Type); - - var queryGraphType = ObjectGraphTypePartTypes.GetOrAdd(contentTypeType, key => typeof(ObjectGraphType<>).MakeGenericType(key)); - - if (serviceProvider.GetService(queryGraphType) is IObjectGraphType) + var queryGraphType = serviceProvider.GetService>()?.FirstOrDefault(x => x.Name == field.FieldDefinition.Name); + if (queryGraphType != null) { return new FieldType { Name = field.Name, Description = field.FieldDefinition.Name, - Type = queryGraphType, + Type = queryGraphType.GetType(), Resolver = new FuncFieldResolver(context => { var typeToResolve = context.FieldDefinition.ResolvedType.GetType().BaseType.GetGenericArguments().First(); diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs index 1ee8cf880dd..caf6cb1b44c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemInterface.cs @@ -1,4 +1,3 @@ -using GraphQL.Resolvers; using GraphQL.Types; using OrchardCore.ContentManagement; using OrchardCore.Menu.Models; @@ -10,16 +9,7 @@ public class MenuItemInterface : InterfaceGraphType public MenuItemInterface() { Name = "MenuItem"; - AddField(new FieldType() - { - Name = "menuItemsList", - Type = typeof(MenuItemsListQueryObjectType), - Resolver = new FuncFieldResolver(context => - { - return context.Source.As(); - }) - - }); + Field("menuItemsList"); } } } diff --git a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs index 3b9d3d0ce53..19ccba88ccc 100644 --- a/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Menu/GraphQL/MenuItemsListQueryObjectType.cs @@ -12,6 +12,7 @@ public MenuItemsListQueryObjectType() Field>("menuItems") .Description("The menu items.") .Resolve(context => context.Source.MenuItems); + } } } diff --git a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs index 7e765513a79..4d58122d4dd 100644 --- a/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs +++ b/src/OrchardCore/OrchardCore.Apis.GraphQL.Abstractions/ServiceCollectionExtensions.cs @@ -18,8 +18,8 @@ public static void AddInputObjectGraphType(this IServiceCo // Instances are registered as singletons as their constructor holds the logic to configure the type // and doesn't need to run every time services.AddSingleton(); - //services.AddSingleton, TObjectType>(s => s.GetRequiredService()); - //services.AddSingleton(s => s.GetRequiredService()); + services.AddSingleton, TObjectType>(s => s.GetRequiredService()); + services.AddSingleton(s => s.GetRequiredService()); } /// @@ -35,8 +35,8 @@ public static void AddObjectGraphType(this IServiceCollectio // Instances are registered as singletons as their constructor holds the logic to configure the type // and doesn't need to run every time services.AddSingleton(); - //services.AddSingleton, TInputType>(s => s.GetRequiredService()); - //services.AddSingleton(s => s.GetRequiredService()); + services.AddSingleton, TInputType>(s => s.GetRequiredService()); + services.AddSingleton(s => s.GetRequiredService()); } } } diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 0bee0db822d..03c59b60141 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Concurrent; +using System.Collections.Generic; using System.Linq; using GraphQL; using GraphQL.Resolvers; @@ -17,8 +18,6 @@ public class TypedContentTypeBuilder : IContentTypeBuilder private readonly IHttpContextAccessor _httpContextAccessor; private readonly GraphQLContentOptions _contentOptions; private readonly ConcurrentDictionary PartTypes = new(); - private readonly ConcurrentDictionary ObjectGraphTypePartTypes = new(); - private readonly ConcurrentDictionary InputObjectGraphTypePartTypes = new(); public TypedContentTypeBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor) { @@ -52,21 +51,17 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin } var partType = PartTypes.GetOrAdd(part.PartDefinition.Name, key => typeActivator.GetTypeActivator(key).Type); - - var queryGraphType = ObjectGraphTypePartTypes.GetOrAdd(partType, key => - { - return typeof(ObjectGraphType<>).MakeGenericType(key); - }); + var queryGraphType = serviceProvider.GetService>()?.FirstOrDefault(x => x.Name == part.PartDefinition.Name); var collapsePart = _contentOptions.ShouldCollapse(part); - if (serviceProvider.GetService(queryGraphType) is IObjectGraphType queryGraphTypeResolved) + if (queryGraphType != null) { if (collapsePart) { - foreach (var field in queryGraphTypeResolved.Fields) + foreach (var field in queryGraphType.Fields) { - if (_contentOptions.ShouldSkip(queryGraphType, field.Name)) continue; + if (_contentOptions.ShouldSkip(queryGraphType.GetType(), field.Name)) continue; var rolledUpField = new FieldType { @@ -99,11 +94,11 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin var field = new FieldType { Name = partName.ToFieldName(), - Type = queryGraphTypeResolved.GetType(), - Description = queryGraphTypeResolved.Description, + Type = queryGraphType.GetType(), + Description = queryGraphType.Description, }; - contentItemType.Field(partName.ToFieldName(), queryGraphTypeResolved.GetType()) - .Description(queryGraphTypeResolved.Description) + contentItemType.Field(partName.ToFieldName(), queryGraphType.GetType()) + .Description(queryGraphType.Description) .Resolve(context => { var nameToResolve = partName; @@ -114,11 +109,11 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin } } - var inputGraphType = InputObjectGraphTypePartTypes.GetOrAdd(partType, key => - { - return typeof(InputObjectGraphType<>).MakeGenericType(key); - }); - if (serviceProvider.GetService(inputGraphType) is IInputObjectGraphType inputGraphTypeResolved) + + var queryGraphTypes = serviceProvider.GetService>(); + var inputGraphTypeResolved = queryGraphTypes?.FirstOrDefault(x => x.Name == part.PartDefinition.Name); + + if (inputGraphTypeResolved != null) { var whereArgument = contentQuery.Arguments.FirstOrDefault(x => x.Name == "where"); if (whereArgument == null) From 056120be223a6ff0e026cf603dac85a8ff0f7a1c Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Tue, 23 Jan 2024 18:56:43 +0800 Subject: [PATCH 15/25] add log details use x => x.GetType().BaseType.GetGenericArguments().First().Name to filter Types --- .../GraphQL/Fields/ObjectGraphTypeFieldProvider.cs | 6 ++---- test/OrchardCore.Tests/NLog.config | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs index dc9f3408c7d..01fe713e61c 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs @@ -15,9 +15,6 @@ namespace OrchardCore.ContentFields.GraphQL.Fields public class ObjectGraphTypeFieldProvider : IContentFieldProvider { private readonly IHttpContextAccessor _httpContextAccessor; - - private readonly ConcurrentDictionary ContentTypeTypes = new(); - private readonly ConcurrentDictionary ObjectGraphTypePartTypes = new(); public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; @@ -26,7 +23,8 @@ public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) public FieldType GetField(ContentPartFieldDefinition field) { var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; - var queryGraphType = serviceProvider.GetService>()?.FirstOrDefault(x => x.Name == field.FieldDefinition.Name); + var queryGraphType = serviceProvider.GetService>()? + .FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == field.FieldDefinition.Name); if (queryGraphType != null) { return new FieldType diff --git a/test/OrchardCore.Tests/NLog.config b/test/OrchardCore.Tests/NLog.config index 49797bb43ce..83356bd486e 100644 --- a/test/OrchardCore.Tests/NLog.config +++ b/test/OrchardCore.Tests/NLog.config @@ -24,7 +24,7 @@ - + From 5e29e7d09d1453366a22b09787610b68ef59b9e2 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Mon, 29 Jan 2024 23:14:04 +0800 Subject: [PATCH 16/25] Operation is not valid due to the current state of the object. --- .../OrchardCore.Apis.GraphQL/Services/SchemaService.cs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs index 296810856e6..bda808c37f6 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Services/SchemaService.cs @@ -74,18 +74,12 @@ public async Task GetSchemaAsync() foreach (var type in serviceProvider.GetServices()) { - if (!schema.AdditionalTypeInstances.Any(t => t == type)) - { - schema.RegisterType(type); - } + schema.RegisterType(type); } foreach (var type in serviceProvider.GetServices()) { - if (type != null && !schema.AdditionalTypeInstances.Any(t => t == type)) - { - schema.RegisterType(type); - } + schema.RegisterType(type); } foreach (var builder in _schemaBuilders) From 7e565c390902a5bd48f7a3b17d8cc0e2fc80d7b3 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Tue, 30 Jan 2024 21:20:40 +0800 Subject: [PATCH 17/25] merge main --- .../OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs index 77ea585eded..5f917d0c0a3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Media/GraphQL/MediaFieldQueryObjectType.cs @@ -26,8 +26,7 @@ public MediaFieldQueryObjectType() return x.Page(x.Source.Paths); }); - Field, IEnumerable>() - .Name("fileNames") + Field, IEnumerable>("fileNames") .Description("the media fileNames") .PagingArguments() .Resolve(x => @@ -40,8 +39,7 @@ public MediaFieldQueryObjectType() return fileNames; }); - Field, IEnumerable>() - .Name("urls") + Field, IEnumerable>("urls") .Description("the absolute urls of the media items") .PagingArguments() .Resolve(x => From 571b9337336d72734c04b42a58757e0d37162dd9 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Wed, 31 Jan 2024 00:43:41 +0800 Subject: [PATCH 18/25] AutoroutePart Filter not work --- .../OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs | 15 ++++++++------- .../GraphQLNamedQueryRequest.cs | 10 ++++++++++ .../OrchardCore.Apis.GraphQL/GraphQLRequest.cs | 13 ------------- .../OrchardCore.Apis.GraphQL/Startup.cs | 7 +++---- .../Apis/GraphQL/Blog/BlogPostTests.cs | 2 +- 5 files changed, 22 insertions(+), 25 deletions(-) create mode 100644 src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLNamedQueryRequest.cs delete mode 100644 src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLRequest.cs diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs index 4e812183347..54567f933c2 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLMiddleware.cs @@ -78,7 +78,7 @@ private bool IsGraphQLRequest(HttpContext context) private async Task ExecuteAsync(HttpContext context) { - GraphQLRequest request = null; + GraphQLNamedQueryRequest request = null; // c.f. https://graphql.org/learn/serving-over-http/#post-request @@ -95,14 +95,15 @@ private async Task ExecuteAsync(HttpContext context) { using var sr = new StreamReader(context.Request.Body); - request = new GraphQLRequest + request = new GraphQLNamedQueryRequest { Query = await sr.ReadToEndAsync() }; } else { - request = await JsonSerializer.DeserializeAsync(context.Request.Body, _jsonSerializerOptions); + + request = await JsonSerializer.DeserializeAsync(context.Request.Body, _jsonSerializerOptions); } } else @@ -147,7 +148,7 @@ private async Task ExecuteAsync(HttpContext context) options.Schema = schema; options.Query = queryToExecute; options.OperationName = request.OperationName; - options.Variables = new GraphQLSerializer().Deserialize(request.Variables.GetString()); + options.Variables = request.Variables; options.UserContext = _settings.BuildUserContext?.Invoke(context); options.ValidationRules = DocumentValidator.CoreRules .Concat(context.RequestServices.GetServices()) @@ -172,7 +173,7 @@ private async Task ExecuteAsync(HttpContext context) await _serializer.WriteAsync(context.Response.Body, result); } - private static GraphQLRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false) + private GraphQLNamedQueryRequest CreateRequestFromQueryString(HttpContext context, bool validateQueryKey = false) { if (!context.Request.Query.ContainsKey("query")) { @@ -184,14 +185,14 @@ private static GraphQLRequest CreateRequestFromQueryString(HttpContext context, return null; } - var request = new GraphQLRequest + var request = new GraphQLNamedQueryRequest { Query = context.Request.Query["query"] }; if (context.Request.Query.ContainsKey("variables")) { - request.Variables = JsonSerializer.Deserialize(context.Request.Query["variables"], _jsonSerializerOptions); + request.Variables = JsonSerializer.Deserialize(context.Request.Query["variables"], _jsonSerializerOptions); } if (context.Request.Query.ContainsKey("operationName")) diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLNamedQueryRequest.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLNamedQueryRequest.cs new file mode 100644 index 00000000000..d27e7564088 --- /dev/null +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLNamedQueryRequest.cs @@ -0,0 +1,10 @@ + +using GraphQL.Transport; + +namespace OrchardCore.Apis.GraphQL +{ + public class GraphQLNamedQueryRequest : GraphQLRequest + { + public string NamedQuery { get; set; } + } +} diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLRequest.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLRequest.cs deleted file mode 100644 index ed4e5fddef6..00000000000 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/GraphQLRequest.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Text.Json; - -namespace OrchardCore.Apis.GraphQL -{ - public class GraphQLRequest - { - public string OperationName { get; set; } - public string NamedQuery { get; set; } - public string Query { get; set; } - - public JsonElement Variables { get; set; } - } -} diff --git a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs index 620cd2002c0..11219a87345 100644 --- a/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs +++ b/src/OrchardCore.Modules/OrchardCore.Apis.GraphQL/Startup.cs @@ -1,4 +1,5 @@ using System; +using System.Text.Json; using GraphQL; using GraphQL.DataLoader; using GraphQL.Execution; @@ -36,7 +37,6 @@ public Startup(IOptions adminOptions, IHostEnvironment hostingEnvi public override void ConfigureServices(IServiceCollection services) { services.AddSingleton(); - services.AddSingleton(); services.AddSingleton(); services.AddSingleton(); @@ -53,8 +53,7 @@ public override void ConfigureServices(IServiceCollection services) services.AddScoped(); services.AddTransient(); services.AddSingleton(); - services.AddGraphQL(builder => builder.AddSystemTextJson() - .AddAutoClrMappings(false, false)); + services.AddGraphQL(builder => builder.AddSystemTextJson()); services.AddOptions().Configure((c, configuration) => { @@ -75,7 +74,7 @@ public override void ConfigureServices(IServiceCollection services) User = ctx.User, }; c.ExposeExceptions = exposeExceptions; - c.MaxDepth = configuration.GetValue($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxDepth)}") ?? 20; + c.MaxDepth = configuration.GetValue($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxDepth)}") ?? 100; c.MaxComplexity = configuration.GetValue($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxComplexity)}"); c.FieldImpact = configuration.GetValue($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.FieldImpact)}"); c.MaxNumberOfResults = configuration.GetValue($"OrchardCore_Apis_GraphQL:{nameof(GraphQLSettings.MaxNumberOfResults)}") ?? 1000; diff --git a/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs index 3066e42bc1d..378c89d18f1 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/Blog/BlogPostTests.cs @@ -206,7 +206,7 @@ public async Task ShouldNotBeAbleToExecuteAnyQueriesWithoutPermission() await context.InitializeAsync(); var response = await context.GraphQLClient.Client.GetAsync("api/graphql"); - Assert.Equal(System.Net.HttpStatusCode.Unauthorized, response.StatusCode); + Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode); } [Fact] From 9d93d5c326db0352867ed3a700dfe9b6ac0ec401 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Wed, 31 Jan 2024 01:30:52 +0800 Subject: [PATCH 19/25] Fix all unit test --- .../Queries/Types/TypedContentTypeBuilder.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 03c59b60141..06ac93a9557 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -51,7 +51,8 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin } var partType = PartTypes.GetOrAdd(part.PartDefinition.Name, key => typeActivator.GetTypeActivator(key).Type); - var queryGraphType = serviceProvider.GetService>()?.FirstOrDefault(x => x.Name == part.PartDefinition.Name); + var queryGraphType = serviceProvider.GetService>() + ?.FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == part.PartDefinition.Name); var collapsePart = _contentOptions.ShouldCollapse(part); @@ -111,7 +112,8 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin var queryGraphTypes = serviceProvider.GetService>(); - var inputGraphTypeResolved = queryGraphTypes?.FirstOrDefault(x => x.Name == part.PartDefinition.Name); + var inputGraphTypeResolved = queryGraphTypes?.FirstOrDefault(x => + x.GetType().BaseType.GetGenericArguments().FirstOrDefault()?.Name == part.PartDefinition.Name); if (inputGraphTypeResolved != null) { From 8b996b38a5ca1e3c202d428464609a649c84ba7f Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Wed, 31 Jan 2024 21:39:39 +0800 Subject: [PATCH 20/25] fix error --- .../GraphQL/Fields/ContentFieldsProvider.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs index 9fb6cc336aa..410dc161988 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ContentFieldsProvider.cs @@ -115,8 +115,6 @@ public FieldType GetField(ContentPartFieldDefinition field) return contentField == null ? null : fieldDescriptor.FieldAccessor(contentField); }), }; - - return fieldType; } private class FieldTypeDescriptor From 6a601a595830ed9748f6677d12a3148816ac894f Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Fri, 2 Feb 2024 14:12:49 +0800 Subject: [PATCH 21/25] add function ResolveContentItems in unit test --- .../GraphQL/ContentItemsFieldTypeTests.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs index e1f432a6186..2438108d3b8 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs @@ -1,5 +1,6 @@ using GraphQL; using GraphQL.Execution; +using GraphQL.Resolvers; using GraphQL.Types; using OrchardCore.Apis.GraphQL; using OrchardCore.Apis.GraphQL.Queries; @@ -173,7 +174,7 @@ public async Task ShouldFilterByContentItemIndexWhenSqlTablePrefixIsUsed() var type = new ContentItemsFieldType("Animal", new Schema(services), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ contentItemId: \"1\" }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var dogs = await ResolveContentItems(type, context); Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -212,7 +213,7 @@ public async Task ShouldFilterByAliasIndexRegardlessOfInputFieldCase(string fiel Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse(string.Concat("{ ", fieldName, ": { name: \"doug\" } }")), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var dogs = await ResolveContentItems(type, context); Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -245,13 +246,13 @@ public async Task ShouldBeAbleToUseTheSameIndexForMultipleAliases() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ cats: { name: \"doug\" } }"), ArgumentSource.Variable); - var cats = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var cats = await ResolveContentItems(type, context); Assert.Single(cats); Assert.Equal("doug", cats.First().As().Name); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ dogs: { name: \"doug\" } }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var dogs = await ResolveContentItems(type, context); Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -296,7 +297,7 @@ public async Task ShouldFilterOnMultipleIndexesOnSameAlias() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animals: { name: \"doug\", isScary: true } }"), ArgumentSource.Variable); - var animals = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var animals = await ResolveContentItems(type, context); Assert.Single(animals); Assert.Equal("doug", animals.First().As().Name); @@ -331,7 +332,7 @@ public async Task ShouldFilterPartsWithoutAPrefixWhenThePartHasNoPrefix() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ animal: { name: \"doug\" } }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var dogs = await ResolveContentItems(type, context); Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); @@ -364,13 +365,16 @@ public async Task ShouldFilterByCollapsedWhereInputForCollapsedParts() var type = new ContentItemsFieldType("Animal", new Schema(), Options.Create(new GraphQLContentOptions()), Options.Create(new GraphQLSettings { DefaultNumberOfResults = 10 })); context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ name: \"doug\" }"), ArgumentSource.Variable); - var dogs = (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + var dogs = await ResolveContentItems(type, context); Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); } - + private static async Task> ResolveContentItems(ContentItemsFieldType type, ResolveFieldContext context) + { + return (await ((LockedAsyncFieldResolver>)type.Resolver).ResolveAsync(context)) as IEnumerable; + } private static ResolveFieldContext CreateAnimalFieldContext(IServiceProvider services, string fieldName = null, bool collapsed = false) { IGraphType where; From 6c18b6b0ec70e1b138fadb6fbfca638479650bd0 Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Fri, 2 Feb 2024 14:17:10 +0800 Subject: [PATCH 22/25] remove log in test --- .../Apis/Context/MvcTestFixture.cs | 3 -- test/OrchardCore.Tests/NLog.config | 32 ------------------- .../OrchardCore.Tests.csproj | 6 ---- 3 files changed, 41 deletions(-) delete mode 100644 test/OrchardCore.Tests/NLog.config diff --git a/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs b/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs index e1a272e5792..39344a8b46c 100644 --- a/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs +++ b/test/OrchardCore.Tests/Apis/Context/MvcTestFixture.cs @@ -1,5 +1,3 @@ -using OrchardCore.Logging; - namespace OrchardCore.Tests.Apis.Context { public class OrchardTestFixture : WebApplicationFactory @@ -25,7 +23,6 @@ protected override IWebHostBuilder CreateWebHostBuilder() protected override IHostBuilder CreateHostBuilder() => Host.CreateDefaultBuilder() - .UseNLogHost() .ConfigureWebHostDefaults(webBuilder => webBuilder.UseStartup()); } diff --git a/test/OrchardCore.Tests/NLog.config b/test/OrchardCore.Tests/NLog.config deleted file mode 100644 index 83356bd486e..00000000000 --- a/test/OrchardCore.Tests/NLog.config +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/OrchardCore.Tests/OrchardCore.Tests.csproj b/test/OrchardCore.Tests/OrchardCore.Tests.csproj index 39452ed49d2..e96c8ecd6cf 100644 --- a/test/OrchardCore.Tests/OrchardCore.Tests.csproj +++ b/test/OrchardCore.Tests/OrchardCore.Tests.csproj @@ -23,7 +23,6 @@ - @@ -33,11 +32,6 @@ - - PreserveNewest - true - PreserveNewest - From ba5f95c76e7f4719f29d8c00bc7b204b2e9e69db Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Fri, 2 Feb 2024 15:51:01 +0800 Subject: [PATCH 23/25] remove log in test --- .../Queries/ContentItemsFieldType.cs | 6 +++--- test/OrchardCore.Tests/OrchardCore.Tests.csproj | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs index 5376b2b5d29..bebebd9232b 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/ContentItemsFieldType.cs @@ -57,9 +57,9 @@ public ContentItemsFieldType(string contentItemName, ISchema schema, IOptions>(Resolve); - //schema.RegisterType(whereInput); - //schema.RegisterType(orderByInput); - //schema.RegisterType(); + schema.RegisterType(whereInput); + schema.RegisterType(orderByInput); + schema.RegisterType(); _defaultNumberOfItems = settingsAccessor.Value.DefaultNumberOfResults; } diff --git a/test/OrchardCore.Tests/OrchardCore.Tests.csproj b/test/OrchardCore.Tests/OrchardCore.Tests.csproj index e96c8ecd6cf..aaaf2f9d06f 100644 --- a/test/OrchardCore.Tests/OrchardCore.Tests.csproj +++ b/test/OrchardCore.Tests/OrchardCore.Tests.csproj @@ -13,6 +13,7 @@ + From 8ae797de86cbc667a7f591a991922cd48e7e8a1e Mon Sep 17 00:00:00 2001 From: hyzx86 Date: Fri, 2 Feb 2024 16:43:31 +0800 Subject: [PATCH 24/25] cache graphType --- .../Fields/ObjectGraphTypeFieldProvider.cs | 11 +++++--- .../Queries/Types/TypedContentTypeBuilder.cs | 26 ++++++++++++++----- 2 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs index 01fe713e61c..da745860768 100644 --- a/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.ContentFields/GraphQL/Fields/ObjectGraphTypeFieldProvider.cs @@ -15,6 +15,8 @@ namespace OrchardCore.ContentFields.GraphQL.Fields public class ObjectGraphTypeFieldProvider : IContentFieldProvider { private readonly IHttpContextAccessor _httpContextAccessor; + private static readonly ConcurrentDictionary PartObjectGraphTypes = new(); + public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; @@ -22,9 +24,12 @@ public ObjectGraphTypeFieldProvider(IHttpContextAccessor httpContextAccessor) public FieldType GetField(ContentPartFieldDefinition field) { - var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; - var queryGraphType = serviceProvider.GetService>()? - .FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == field.FieldDefinition.Name); + var serviceProvider = _httpContextAccessor.HttpContext.RequestServices; + var queryGraphType = PartObjectGraphTypes.GetOrAdd(field.FieldDefinition.Name, + partName => serviceProvider.GetService>()? + .FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == partName) + ); + if (queryGraphType != null) { return new FieldType diff --git a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs index 06ac93a9557..a3900c20992 100644 --- a/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs +++ b/src/OrchardCore/OrchardCore.ContentManagement.GraphQL/Queries/Types/TypedContentTypeBuilder.cs @@ -17,7 +17,10 @@ public class TypedContentTypeBuilder : IContentTypeBuilder { private readonly IHttpContextAccessor _httpContextAccessor; private readonly GraphQLContentOptions _contentOptions; - private readonly ConcurrentDictionary PartTypes = new(); + private static readonly ConcurrentDictionary PartTypes = new(); + private static readonly ConcurrentDictionary PartObjectGraphTypes = new(); + private static readonly ConcurrentDictionary PartInputObjectGraphTypes = new(); + public TypedContentTypeBuilder(IHttpContextAccessor httpContextAccessor, IOptions contentOptionsAccessor) { @@ -34,7 +37,8 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin { return; } - + IEnumerable queryObjectGraphTypes = null; + IEnumerable queryInputGraphTypes = null; foreach (var part in contentTypeDefinition.Parts) { if (_contentOptions.ShouldSkip(part)) @@ -51,8 +55,13 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin } var partType = PartTypes.GetOrAdd(part.PartDefinition.Name, key => typeActivator.GetTypeActivator(key).Type); - var queryGraphType = serviceProvider.GetService>() - ?.FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == part.PartDefinition.Name); + var queryGraphType = PartObjectGraphTypes.GetOrAdd(part.PartDefinition.Name, + partName => + { + queryObjectGraphTypes ??= serviceProvider.GetService>(); + return queryObjectGraphTypes?.FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().First().Name == partName); + } + ); var collapsePart = _contentOptions.ShouldCollapse(part); @@ -111,9 +120,12 @@ public void Build(FieldType contentQuery, ContentTypeDefinition contentTypeDefin } - var queryGraphTypes = serviceProvider.GetService>(); - var inputGraphTypeResolved = queryGraphTypes?.FirstOrDefault(x => - x.GetType().BaseType.GetGenericArguments().FirstOrDefault()?.Name == part.PartDefinition.Name); + + var inputGraphTypeResolved = PartInputObjectGraphTypes.GetOrAdd(part.PartDefinition.Name, partName => + { + queryInputGraphTypes ??= serviceProvider.GetService>(); + return queryInputGraphTypes?.FirstOrDefault(x => x.GetType().BaseType.GetGenericArguments().FirstOrDefault()?.Name == part.PartDefinition.Name); + }); if (inputGraphTypeResolved != null) { From da7ab9e0864676cf0a1907d0bd7fa42aa9b9e95b Mon Sep 17 00:00:00 2001 From: Sebastien Ros Date: Wed, 7 Feb 2024 10:00:22 -0800 Subject: [PATCH 25/25] Fix build --- .../Sql/GraphQL/SqlQueryFieldTypeProvider.cs | 4 +-- .../GraphQL/ElasticQueryFieldTypeProvider.cs | 4 +-- .../GraphQL/LuceneQueryFieldTypeProvider.cs | 4 +-- .../GraphQL/CurrentUserQuery.cs | 2 +- .../OrchardCore.Users/GraphQL/UserType.cs | 32 +++++++++++-------- .../core/Apis.GraphQL.Abstractions/README.md | 2 +- .../GraphQL/ContentItemsFieldTypeTests.cs | 2 +- .../RequiresPermissionValidationRuleTests.cs | 2 +- 8 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs index d53dce02d80..e8dad56d815 100644 --- a/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Queries/Sql/GraphQL/SqlQueryFieldTypeProvider.cs @@ -111,7 +111,7 @@ private static FieldType BuildSchemaBasedFieldType(SqlQuery query, JsonNode quer Name = nameLower, Description = description, Type = typeof(StringGraphType), - Resolver = new FuncFieldResolver(context => + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); @@ -127,7 +127,7 @@ private static FieldType BuildSchemaBasedFieldType(SqlQuery query, JsonNode quer Name = nameLower, Description = description, Type = typeof(IntGraphType), - Resolver = new FuncFieldResolver(context => + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs index da41c5345b3..b69614ba147 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Elasticsearch/GraphQL/ElasticQueryFieldTypeProvider.cs @@ -112,7 +112,7 @@ private static FieldType BuildSchemaBasedFieldType(ElasticQuery query, JsonNode Name = nameLower, Description = description, Type = typeof(StringGraphType), - Resolver = new FuncFieldResolver(context => + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); @@ -128,7 +128,7 @@ private static FieldType BuildSchemaBasedFieldType(ElasticQuery query, JsonNode Name = nameLower, Description = description, Type = typeof(IntGraphType), - Resolver = new FuncFieldResolver(context => + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); diff --git a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs index e0d8b4bd0de..bd1e655553f 100644 --- a/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs +++ b/src/OrchardCore.Modules/OrchardCore.Search.Lucene/GraphQL/LuceneQueryFieldTypeProvider.cs @@ -110,7 +110,7 @@ private static FieldType BuildSchemaBasedFieldType(LuceneQuery query, JsonNode q Name = nameLower, Description = description, Type = typeof(StringGraphType), - Resolver = new FuncFieldResolver(context => + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); @@ -126,7 +126,7 @@ private static FieldType BuildSchemaBasedFieldType(LuceneQuery query, JsonNode q Name = nameLower, Description = description, Type = typeof(IntGraphType), - Resolver = new FuncFieldResolver(context => + Resolver = new FuncFieldResolver(context => { var source = context.Source; return source[context.FieldDefinition.Metadata["Name"].ToString()].ToObject(); diff --git a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs b/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs index 7acaf54d6e3..68060243660 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/CurrentUserQuery.cs @@ -61,7 +61,7 @@ public async Task BuildAsync(ISchema schema) Name = "me", Description = S["Gets the currently authenticated user."], ResolvedType = userType, - Resolver = new AsyncFieldResolver(async context => + Resolver = new FuncFieldResolver(async context => { var userService = context.RequestServices!.GetRequiredService(); var user = await userService.GetAuthenticatedUserAsync(((GraphQLUserContext)context.UserContext).User); diff --git a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/UserType.cs b/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/UserType.cs index 9f43c89cc0f..9a8e7665d6c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/UserType.cs +++ b/src/OrchardCore.Modules/OrchardCore.Users/GraphQL/UserType.cs @@ -1,9 +1,11 @@ using System; using System.Linq; +using GraphQL.Resolvers; using GraphQL.Types; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Localization; using OrchardCore.ContentManagement.Metadata.Models; +using OrchardCore.DisplayManagement; using OrchardCore.Users.Models; using OrchardCore.Users.Services; @@ -30,25 +32,27 @@ public UserType(IStringLocalizer localizer) internal void AddField(ISchema schema, ContentTypeDefinition typeDefinition) { var contentItemType = schema.AdditionalTypeInstances.SingleOrDefault(t => t.Name == typeDefinition.Name); + if (contentItemType == null) { // This error would indicate that this graph type is build too early. throw new InvalidOperationException("ContentTypeDefinition has not been registered in GraphQL"); } - this.FieldAsync(typeDefinition.Name, contentItemType, S["Custom user settings of {0}.", typeDefinition.DisplayName], resolve: async context => - { - // We don't want to create an empty content item if it does not exist. - if (context.Source is User user && - user.Properties.ContainsKey(context.FieldDefinition.ResolvedType.Name)) - { - var customUserSettingsService = context.RequestServices!.GetRequiredService(); - var settingsType = await customUserSettingsService.GetSettingsTypeAsync(context.FieldDefinition.ResolvedType.Name); - - return await customUserSettingsService.GetSettingsAsync(user, settingsType); - } - - return null; - }); + var field = Field(typeDefinition.Name, contentItemType.GetType()) + .Description(S["Custom user settings of {0}.", typeDefinition.DisplayName]) + .ResolveAsync(static async context => { + // We don't want to create an empty content item if it does not exist. + if (context.Source is User user && + user.Properties.ContainsKey(context.FieldDefinition.ResolvedType.Name)) + { + var customUserSettingsService = context.RequestServices!.GetRequiredService(); + var settingsType = await customUserSettingsService.GetSettingsTypeAsync(context.FieldDefinition.ResolvedType.Name); + + return await customUserSettingsService.GetSettingsAsync(user, settingsType); + } + + return null; + }); } } diff --git a/src/docs/reference/core/Apis.GraphQL.Abstractions/README.md b/src/docs/reference/core/Apis.GraphQL.Abstractions/README.md index 10e3978cecd..ff37215f50a 100644 --- a/src/docs/reference/core/Apis.GraphQL.Abstractions/README.md +++ b/src/docs/reference/core/Apis.GraphQL.Abstractions/README.md @@ -38,7 +38,7 @@ public class AutoroutePart : ContentPart } ``` -This is the part that is attached to your content item. GraphQL doesnt know what this is, so we now need to create a GraphQL representation of this class; +This is the part that is attached to your content item. GraphQL doesn't know what this is, so we now need to create a GraphQL representation of this class; ```csharp public class AutorouteQueryObjectType : ObjectGraphType diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs index 95317991ba4..efc3f71707c 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ContentItemsFieldTypeTests.cs @@ -143,7 +143,7 @@ public async Task ShouldFilterByContentItemIndex() context.Arguments["where"] = new ArgumentValue(JObject.Parse("{ \"contentItemId\": \"1\" }"), ArgumentSource.Variable); var dogs = await ((LockedAsyncFieldResolver>)type.Resolver) - .ResolveAsync(context)) as IEnumerable; + .ResolveAsync(context) as IEnumerable; Assert.Single(dogs); Assert.Equal("doug", dogs.First().As().Name); diff --git a/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs b/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs index c1020f7a876..bbd24fb2a83 100644 --- a/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs +++ b/test/OrchardCore.Tests/Apis/GraphQL/ValidationRules/RequiresPermissionValidationRuleTests.cs @@ -35,7 +35,7 @@ public async Task FieldsWithNoRequirePermissionsShouldResolve() Assert.Null(executionResult.Errors); var writer = new GraphQLSerializer(); - var result = JsonObject.Parse(await writer.WriteToStringAsync(executionResult)); + var result = JsonObject.Parse(writer.Serialize(executionResult)); Assert.Equal("Fantastic Fox Hates Permissions", result["data"]["test"]["noPermissions"].ToString()); }