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

Using try add for shape attribute provider #12284

Merged
merged 3 commits into from Sep 16, 2022
Merged

Using try add for shape attribute provider #12284

merged 3 commits into from Sep 16, 2022

Conversation

ns8482e
Copy link
Contributor

@ns8482e ns8482e commented Aug 28, 2022

Using try add for shape attribute provider to add only once

@@ -29,7 +30,7 @@ public static class ShapeProviderExtensions
{
public static IServiceCollection AddShapeAttributes<T>(this IServiceCollection services) where T : class, IShapeAttributeProvider
{
services.AddScoped<T>();
services.TryAddScoped<T>();
Copy link
Member

Choose a reason for hiding this comment

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

Is there any issue with AddScoped()?

@@ -29,7 +30,7 @@ public static class ShapeProviderExtensions
{
public static IServiceCollection AddShapeAttributes<T>(this IServiceCollection services) where T : class, IShapeAttributeProvider
{
services.AddScoped<T>();
services.TryAddScoped<T>();
services.AddScoped<IShapeAttributeProvider>(sp => sp.GetService<T>());
Copy link
Member

Choose a reason for hiding this comment

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

Normally in a given module we don't call twice AddShapeAttributes() for a given shape type.

Otherwise we would need to also use TryAddScoped() here but it may not work when we pass a factory delegate.

Maybe we could have our own TryAddScoped() that would be used before line 33 and that would return a bool, so that if it returns false we would not re-register this IShapeAttributeProvider too.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Technically it's not issue as it's same class registered more than once and only last one is used. However registration is needed only once.

Useful when having shared shape library not attached to any module , that adds such shapes to service collection, and can be safely called more than once from different modules

Copy link
Member

Choose a reason for hiding this comment

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

@ns8482e

What I meant is that we could also prevent to re-register

services.AddScoped<IShapeAttributeProvider>(sp => sp.GetService<T>());

But TryAddScoped() only checks the service type, here IShapeAttributeProvider;

So what you could use is TryAddEnumerable(), was not sure so I looked at the dotnet code (see below), because it also checks the implementation type, anf if it is an implementation factory as here, it also checks the return type of the factory.

services.TryAddEnumerable(
    ServiceDescriptor.Scope<IShapeAttributeProvider>(sp => sp.GetRequiredService<T>()));

https://github.com/dotnet/runtime/blob/231255dac0fe015ebc6fb55466c75cf5b4e05f56/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/Extensions/ServiceCollectionDescriptorExtensions.cs#L451

https://github.com/dotnet/runtime/blob/231255dac0fe015ebc6fb55466c75cf5b4e05f56/src/libraries/Microsoft.Extensions.DependencyInjection.Abstractions/src/ServiceDescriptor.cs#L104

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated to use TryAddEnumerable

@jtkech
Copy link
Member

jtkech commented Sep 5, 2022

Oops but unit tests are failing

System.ArgumentException : Implementation type cannot be 'OrchardCore.DisplayManagement.Descriptors.IShapeAttributeProvider' because it is indistinguishable from other services registered for 'OrchardCore.DisplayManagement.Descriptors.IShapeAttributeProvider'. (Parameter 'descriptor')

I will check it, maybe just use a cast

ServiceDescriptor.Scoped<IShapeAttributeProvider>(sp => (T)sp.GetRequiredService<T>()));

@jtkech
Copy link
Member

jtkech commented Sep 5, 2022

Okay, should be

services.TryAddEnumerable(
    ServiceDescriptor.Scoped<IShapeAttributeProvider, T>(sp => sp.GetRequiredService<T>()));

I will update it.

@@ -1,5 +1,6 @@
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
Copy link
Contributor

Choose a reason for hiding this comment

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

Any perf degradation?

Copy link
Member

Choose a reason for hiding this comment

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

If AddShapeAttributes<T>() is called once per shape type it is as before.

If called multiple times for a given shape type, less registrations, so better for perf.

Copy link
Contributor

Choose a reason for hiding this comment

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

I meant, does the reflection here makes it slower on an equivalent request?

Copy link
Member

Choose a reason for hiding this comment

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

There is no additional reflection, just a generic extension helper as before.

@Skrypt Skrypt merged commit 6e2c8e9 into main Sep 16, 2022
@Skrypt Skrypt deleted the ns/shape-attributes branch September 16, 2022 18:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants