Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mark old IGraphQLBuilder extension methods obsolete and create new ones #602

Merged
merged 24 commits into from
Dec 27, 2021

Conversation

Shane32
Copy link
Member

@Shane32 Shane32 commented Jul 19, 2021

See: graphql-dotnet/graphql-dotnet#2429

I don't like how the new SystemTextJson and NewtonsoftJson extension methods are handled. Currently the new methods (AddSystemTextJson and AddNewtonsoftJson) conflict with the methods of the same name in the base GraphQL library. But they are necessary because they support deserialization and websockets. I think that for the next major version, the remaining functionality should be moved into the base project. It's very little code and fits well there -- the base library's serialization projects already support serialization, so why not deserialization as well? However, as a non-breaking change, and to allow an upgrade path, we have the changes as proposed in this PR. (The next major version will remove the old IGraphQLBuilder interface.)

@Shane32 Shane32 requested a review from sungam3r July 19, 2021 21:34
@Shane32 Shane32 self-assigned this Jul 19, 2021
@github-actions github-actions bot added the test label Jul 19, 2021
@Shane32
Copy link
Member Author

Shane32 commented Jul 19, 2021

I have yet to update the samples....

Shane32 added 4 commits July 19, 2021 18:13

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Shane32 added 3 commits August 1, 2021 11:09

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
Shane32 added 3 commits August 1, 2021 17:11

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
@Shane32
Copy link
Member Author

Shane32 commented Oct 30, 2021

@sungam3r

P.S. I returned back after a long break from the OSS.

Welcome back! GraphQL.Net 4.6.x has been very stable with very few issues. The biggest outstanding issues relate to WebSockets in conjunction with a load balancer (#621), and federation. I don't use either so I'm having trouble helping.

There is only two issues here merged but not released:

Also I finished migrating IGraphQLBuilder to the main project, which is merged and released and works very well. I have not updated the server project - but it is ready within this PR. If I remember right, merging this PR will retain the server project as binary-compatible, but likely breaks source compatibility. I would follow up with a separate PR removing all the deprecated methods for the next major version. I wasn't sure if this was beneficial to include this PR within this major version or not. So since nobody has asked for it, I have not merged or released this PR. It's also noteworth that this upgrade would require the latest version of GraphQL.Net. Another reason not to include it in this major version. I thought perhaps when the next major version of the server project is released (6.x), we could simultaneously release the final version of 5.x which would include this PR. In that manner people could use this last version as a way to migrate to the new version easier.

I think the next major version of the server project should eliminate Newtonsoft dependencies when using System.Text.Json. Also would like to fix the websockets problem. But I have not worked on either (partially since I don't use the server project in my applications).

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
@Shane32
Copy link
Member Author

Shane32 commented Nov 7, 2021

@sungam3r I'd like to merge this so I can use the new IGraphQLBuilder design in my projects that use server. Please lmk your thoughts.

@sungam3r
Copy link
Member

I'm in process of reading all that email from this and other projects: 87 left for server. I read every comment and review each PR. There is little time, a lot of work. Gradually, I will get to the current state of the project. Now I am somewhere in the July emails.

@sungam3r
Copy link
Member

@Shane32 This issue is the single one left for me to read about from server project. I will try to review tomorrow.

@sungam3r
Copy link
Member

I see you bumped version to 4.6.1 to use new APIs from GraphQL.NET so it will require me more time to figure out since I have not yet watched all changes there.

@sungam3r
Copy link
Member

Waiting for graphql-dotnet/graphql-dotnet#2811 to merge?

@Shane32
Copy link
Member Author

Shane32 commented Dec 26, 2021

Waiting for graphql-dotnet/graphql-dotnet#2811 to merge?

Not necessarily. This PR is designed to work with GraphQL.NET v4.6.1+, and marks the old server project's IGraphQLBuilder interface and extension methods obsolete without removing them. This provides an 'upgrade path' for projects - they can use the new version of the server project and switch to the new IGraphQLBuilder as they have time. Then they can move to GraphQL.NET v5 (and Server v6) easier. This would be the last release before releasing Server v6, of course, and Server v6 would eliminate all of the classes and methods that this PR marks as obsolete. Changes would need to be made within Server v6 to account for the PR you mentioned, which targets GraphQL.NET v5.

@Shane32
Copy link
Member Author

Shane32 commented Dec 26, 2021

Please note that I will be on the road for the next few days, so I may be a little slow to respond, but I'll try to review your PRs promptly as I'm able.

/// <returns>Reference to the passed <paramref name="builder"/>.</returns>
public static DI.IGraphQLBuilder AddGraphQLAuthorization(this DI.IGraphQLBuilder builder, Action<AuthorizationOptions> configure)
{
if (!(builder is IServiceCollection services))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now I see...

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would remove : IServiceCollection from GraphQLBuilder and add that:

public interface IServiceCollectionProvider
{
    public IServiceCollection ServiceCollection { get; }
}

Then

internal class GraphQLBuilder : GraphQLBuilderBase, IServiceRegister, IServiceCollectionProvider
{
        public override IServiceRegister Services => this;

        public IServiceCollection ServiceCollection { get; }
}

+ remove

 int ICollection<ServiceDescriptor>.Count => ServiceCollection.Count;
        bool ICollection<ServiceDescriptor>.IsReadOnly => ServiceCollection.IsReadOnly;
        ServiceDescriptor IList<ServiceDescriptor>.this[int index] { get => ServiceCollection[index]; set => ServiceCollection[index] = value; }
        int IList<ServiceDescriptor>.IndexOf(ServiceDescriptor item) => ServiceCollection.IndexOf(item);
        void IList<ServiceDescriptor>.Insert(int index, ServiceDescriptor item) => ServiceCollection.Insert(index, item);
        void IList<ServiceDescriptor>.RemoveAt(int index) => ServiceCollection.RemoveAt(index);
        void ICollection<ServiceDescriptor>.Add(ServiceDescriptor item) => ServiceCollection.Add(item);
        void ICollection<ServiceDescriptor>.Clear() => ServiceCollection.Clear();
        bool ICollection<ServiceDescriptor>.Contains(ServiceDescriptor item) => ServiceCollection.Contains(item);
        void ICollection<ServiceDescriptor>.CopyTo(ServiceDescriptor[] array, int arrayIndex) => ServiceCollection.CopyTo(array, arrayIndex);
        bool ICollection<ServiceDescriptor>.Remove(ServiceDescriptor item) => ServiceCollection.Remove(item);
        IEnumerator<ServiceDescriptor> IEnumerable<ServiceDescriptor>.GetEnumerator() => ServiceCollection.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)ServiceCollection).GetEnumerator();

Then cast builder.Services to IServiceCollectionProvider

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fine (for v5 obviously). This is the 3rd option I mentioned. It will require a dependency on GraphQL.MicrosoftDI from the server project. Since it only works for Microsoft DI, the dependency makes sense.

GraphQLBuilder should remain public so that if someone wants to add additional initialization code to RegisterDefaultServices, they don't need to rewrite the entire class. There's no reason to make it internal/private.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But... then project needs a reference to IServiceCollectionProvider... So... Let's just move : IServiceCollection from IGraphQLBuilder to IServiceRegister.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If OK I'll do a PR to graphql-net/develop

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GraphQLBuilder should remain public so that if someone wants to add additional initialization code to RegisterDefaultServices, they don't need to rewrite the entire class. There's no reason to make it internal/private.

OK.

It will require a dependency on GraphQL.MicrosoftDI from the server project.

I think we will be able to go without it.

/// </param>
/// <returns>GraphQL Builder.</returns>
public static DI.IGraphQLBuilder AddNewtonsoftJson(this DI.IGraphQLBuilder builder,
Action<JsonSerializerSettings> configureDeserializerSettings = null,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nullable annotations may be added later.

builder.Register<IUserContextBuilder, TUserContextBuilder>(DI.ServiceLifetime.Singleton);
builder.ConfigureExecution(async options =>
{
if (options.UserContext == null || options.UserContext.Count == 0 && options.UserContext.GetType() == typeof(Dictionary<string, object>))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Debatable.
изображение

After
options.UserContext = await contextBuilder.BuildUserContext(httpContext);
UserContext may become null.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also I doubt about BuildUserContext double call .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From ExecutionOptions:
изображение

Probably it harms us.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's postpone this issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
builder
.Register(typeof(IWebSocketConnectionFactory<>), typeof(WebSocketConnectionFactory<>), DI.ServiceLifetime.Transient)
.Register<IOperationMessageListener, LogMessagesListener>(DI.ServiceLifetime.Transient)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would not add LogMessagesListener. At least add bool or fluent argument:

public static DI.IGraphQLBuilder AddWebSockets(this DI.IGraphQLBuilder builder, Action<IWebSocketsBuilder> configure)

Then:

services.AddGraphQL(b => b.AddWebSockets(opt => opt.AddLogging(...)));

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keep in mind that one of the disadvantages of the project I see unnecessary dependencies, namely Microsoft.Extensions.Logging and Newtonsoft.Json.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For sure. Right now even when using System.Text.Json there is a dependency on Newtonsoft.Json. That’s one of the things I want to solve when embedding both serialization and deserialization into GraphQL.SystemTextJson and GraphQL.NewtonsoftJson in an abstract fashion.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.AddGraphQL((options, provider) =>
.AddSingleton<ChatSchema>();

MicrosoftDI.GraphQLBuilderExtensions.AddGraphQL(services)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apparently, this is a temporary inconvenience.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Although it is binary compatible it is probably not source compatible. There should be notes somewhere in here to that effect.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(That may happen when using GraphQL 4.6.1 regardless of the changes in this PR.)

Copy link
Member

@sungam3r sungam3r Dec 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should be notes somewhere

I suggest to use GraphQL.NET documentation site as a single place for projects' documentation. I would to make new sidebar section for server project.
изображение

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sungam3r sungam3r added the enhancement New feature or request label Dec 27, 2021
Copy link
Member

@sungam3r sungam3r left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tests failed.

@Shane32
Copy link
Member Author

Shane32 commented Dec 27, 2021

I’ll fix it sometime today.

@codecov-commenter
Copy link

Codecov Report

Merging #602 (8286d77) into master (08b16aa) will decrease coverage by 3.84%.
The diff coverage is 53.07%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master     #602      +/-   ##
==========================================
- Coverage   55.09%   51.25%   -3.85%     
==========================================
  Files          64       65       +1     
  Lines        1590     1715     +125     
  Branches      158      166       +8     
==========================================
+ Hits          876      879       +3     
- Misses        660      789     +129     
+ Partials       54       47       -7     
Impacted Files Coverage Δ
...spNetCore/GraphQLBuilderAuthorizationExtensions.cs 0.00% <0.00%> (ø)
src/Core/DefaultGraphQLExecuter.cs 25.00% <ø> (-63.47%) ⬇️
src/Core/Extensions/ServiceCollectionExtensions.cs 56.52% <ø> (ø)
src/Core/GraphQLBuilder.cs 100.00% <ø> (ø)
.../Extensions/GraphQLBuilderUserContextExtensions.cs 0.00% <0.00%> (ø)
...rc/Core/Extensions/GraphQLBuilderCoreExtensions.cs 14.81% <50.00%> (-45.72%) ⬇️
src/Core/BasicGraphQLExecuter.cs 100.00% <100.00%> (ø)
...TextJson/GraphQLBuilderSystemTextJsonExtensions.cs 57.14% <100.00%> (-9.53%) ⬇️
...tCore.SystemTextJson/GraphQLRequestDeserializer.cs 83.09% <100.00%> (+1.40%) ⬆️
...spNetCore.SystemTextJson/InternalGraphQLRequest.cs 100.00% <100.00%> (ø)
... and 5 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 08b16aa...8286d77. Read the comment docs.

@Shane32 Shane32 merged commit 7d780f7 into master Dec 27, 2021
@Shane32 Shane32 deleted the builder2 branch December 27, 2021 19:25
@Shane32 Shane32 added this to the v5.2 milestone Dec 29, 2021
@basvandriel
Copy link

Can the version for the PR be released? Can't seem to find docs for an older version!

@Shane32
Copy link
Member Author

Shane32 commented Dec 30, 2021

Hopefully tomorrow. #688

@sungam3r
Copy link
Member

#693 is coming 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants