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

Update to .NET 8 and leverage keyed services for decoration #209

Merged
merged 22 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
93e158b
Whitespace and line break tweaks
khellang Aug 18, 2023
ade71de
Bump target framework versions to match MS.Ext.DI
khellang Aug 18, 2023
84c456e
Validate scopes on build in tests
khellang Aug 18, 2023
3cf6f7d
Leverage keyed services for decoration instead of DecoratedType hack
khellang Aug 18, 2023
a6b3528
Bump .NET version in action
khellang Aug 18, 2023
17b0f66
Remove traces of .NET Core
khellang Aug 18, 2023
f60f908
Remove Obsolete methods
khellang Sep 1, 2023
63dea3f
Use sets internally to avoid duplicate types and assemblies
khellang Sep 1, 2023
40e9680
Address PR feedback
khellang Sep 1, 2023
080891c
Extract methods
khellang Sep 1, 2023
ad5c936
Use switch expressions
khellang Sep 1, 2023
67d09f8
Fix test to work with ServiceKey
khellang Sep 1, 2023
cd2018b
Create activator factory outside of factory delegate
khellang Sep 1, 2023
acda745
Fix exception message names
khellang Sep 1, 2023
12c653c
Filter out IEnumerables when registering as implemented interfaces. #65
khellang Sep 5, 2023
d2bda34
Reuse same logic for getting interfaces between AsImplementedInterfac…
khellang Sep 5, 2023
109fad6
Add AsSelfWithInterfaces overload with predicate
khellang Sep 5, 2023
14b8511
Add plumbing to support decorating keyed services
khellang Nov 15, 2023
6ebbfdf
Bump dependencies to RTM
khellang Nov 15, 2023
4270df8
Bump major version
khellang Nov 15, 2023
04a3f7e
FromExecutingAssembly and FromCallingAssembly are misleading #92
savornicesei Feb 5, 2024
4d0ecf4
Update package versions
khellang Sep 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,13 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3

- name: Setup .NET Core SDK
uses: actions/setup-dotnet@v1
- name: Setup .NET 8 SDK
uses: actions/setup-dotnet@v3
with:
dotnet-version: "3.1.x"

- name: Setup .NET 7 SDK
uses: actions/setup-dotnet@v1
with:
dotnet-version: "7.0.x"
dotnet-version: "8.x"
dotnet-quality: "preview"

- name: Test
run: dotnet test --collect:"XPlat Code Coverage"
Expand Down
1 change: 1 addition & 0 deletions NuGet.Config
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
<configuration>
<packageSources>
<add key="api.nuget.org" value="https://api.nuget.org/v3/index.json" />
<add key="dotnet8" value="https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet8/nuget/v3/index.json" />
</packageSources>
</configuration>
6 changes: 3 additions & 3 deletions src/Scrutor/AttributeSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ namespace Scrutor;

internal class AttributeSelector : ISelector
{
public AttributeSelector(IEnumerable<Type> types)
public AttributeSelector(ISet<Type> types)
{
Types = types;
}

private IEnumerable<Type> Types { get; }
private ISet<Type> Types { get; }

void ISelector.Populate(IServiceCollection services, RegistrationStrategy? registrationStrategy)
{
Expand Down Expand Up @@ -49,4 +49,4 @@ private static IEnumerable<ServiceDescriptorAttribute> GetDuplicates(IEnumerable
{
return attributes.GroupBy(s => s.ServiceType).SelectMany(grp => grp.Skip(1));
}
}
}
14 changes: 7 additions & 7 deletions src/Scrutor/ClosedTypeDecorationStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ namespace Scrutor;

internal sealed class ClosedTypeDecorationStrategy : DecorationStrategy
{
public ClosedTypeDecorationStrategy(Type serviceType, Type? decoratorType, Func<object, IServiceProvider, object>? decoratorFactory) : base(serviceType)
public ClosedTypeDecorationStrategy(Type serviceType, string? serviceKey, Type? decoratorType, Func<object, IServiceProvider, object>? decoratorFactory) : base(serviceType, serviceKey)
{
DecoratorType = decoratorType;
DecoratorFactory = decoratorFactory;
Expand All @@ -14,20 +14,20 @@ public ClosedTypeDecorationStrategy(Type serviceType, Type? decoratorType, Func<

private Func<object, IServiceProvider, object>? DecoratorFactory { get; }

public override bool CanDecorate(Type serviceType) => ServiceType == serviceType;
protected override bool CanDecorate(Type serviceType) => ServiceType == serviceType;

public override Func<IServiceProvider, object> CreateDecorator(Type serviceType)
public override Func<IServiceProvider, object?, object> CreateDecorator(Type serviceType, string serviceKey)
{
if (DecoratorType is not null)
{
return TypeDecorator(serviceType, DecoratorType);
return TypeDecorator(serviceType, serviceKey, DecoratorType);
}

if (DecoratorFactory is not null)
{
return FactoryDecorator(serviceType, DecoratorFactory);
return FactoryDecorator(serviceType, serviceKey, DecoratorFactory);
}

throw new InvalidOperationException($"Both serviceType and decoratorFactory can not be null.");
}
throw new InvalidOperationException($"Both {nameof(DecoratorType)} and {nameof(DecoratorFactory)} can not be null.");
}
}
119 changes: 0 additions & 119 deletions src/Scrutor/DecoratedType.cs

This file was deleted.

2 changes: 1 addition & 1 deletion src/Scrutor/DecorationException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ public DecorationException(DecorationStrategy strategy) : base(strategy.ServiceT
{
Strategy = strategy;
}

public DecorationStrategy Strategy { get; }
}
54 changes: 32 additions & 22 deletions src/Scrutor/DecorationStrategy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,52 @@ namespace Scrutor;

public abstract class DecorationStrategy
{
protected DecorationStrategy(Type serviceType)
protected DecorationStrategy(Type serviceType, string? serviceKey)
{
ServiceType = serviceType;
ServiceKey = serviceKey;
}

public Type ServiceType { get; }

public abstract bool CanDecorate(Type serviceType);

public abstract Func<IServiceProvider, object> CreateDecorator(Type serviceType);

internal static DecorationStrategy WithType(Type serviceType, Type decoratorType) =>
Create(serviceType, decoratorType, decoratorFactory: null);

internal static DecorationStrategy WithFactory(Type serviceType, Func<object, IServiceProvider, object> decoratorFactory) =>
Create(serviceType, decoratorType: null, decoratorFactory);

protected static Func<IServiceProvider, object> TypeDecorator(Type serviceType, Type decoratorType) => serviceProvider =>

public string? ServiceKey { get; }

public virtual bool CanDecorate(ServiceDescriptor descriptor) =>
string.Equals(ServiceKey, descriptor.ServiceKey) && CanDecorate(descriptor.ServiceType);

protected abstract bool CanDecorate(Type serviceType);

public abstract Func<IServiceProvider, object?, object> CreateDecorator(Type serviceType, string serviceKey);

internal static DecorationStrategy WithType(Type serviceType, string? serviceKey, Type decoratorType) =>
Create(serviceType, serviceKey, decoratorType, decoratorFactory: null);

internal static DecorationStrategy WithFactory(Type serviceType, string? serviceKey, Func<object, IServiceProvider, object> decoratorFactory) =>
Create(serviceType, serviceKey, decoratorType: null, decoratorFactory);

protected static Func<IServiceProvider, object?, object> TypeDecorator(Type serviceType, string serviceKey, Type decoratorType)
{
var instanceToDecorate = serviceProvider.GetRequiredService(serviceType);
return ActivatorUtilities.CreateInstance(serviceProvider, decoratorType, instanceToDecorate);
};
var factory = ActivatorUtilities.CreateFactory(decoratorType, new[] { serviceType });
return (serviceProvider, _) =>
{
var instanceToDecorate = serviceProvider.GetRequiredKeyedService(serviceType, serviceKey);
return factory(serviceProvider, new object[] { instanceToDecorate });
};
}

protected static Func<IServiceProvider, object> FactoryDecorator(Type decorated, Func<object, IServiceProvider, object> decoratorFactory) => serviceProvider =>
protected static Func<IServiceProvider, object?, object> FactoryDecorator(Type serviceType, string serviceKey, Func<object, IServiceProvider, object> decoratorFactory) => (serviceProvider, _) =>
{
var instanceToDecorate = serviceProvider.GetRequiredService(decorated);
var instanceToDecorate = serviceProvider.GetRequiredKeyedService(serviceType, serviceKey);
return decoratorFactory(instanceToDecorate, serviceProvider);
};

private static DecorationStrategy Create(Type serviceType, Type? decoratorType, Func<object, IServiceProvider, object>? decoratorFactory)
private static DecorationStrategy Create(Type serviceType, string? serviceKey, Type? decoratorType, Func<object, IServiceProvider, object>? decoratorFactory)
{
if (serviceType.IsOpenGeneric())
{
return new OpenGenericDecorationStrategy(serviceType, decoratorType, decoratorFactory);
return new OpenGenericDecorationStrategy(serviceType, serviceKey, decoratorType, decoratorFactory);
}

return new ClosedTypeDecorationStrategy(serviceType, decoratorType, decoratorFactory);
return new ClosedTypeDecorationStrategy(serviceType, serviceKey, decoratorType, decoratorFactory);
}
}
20 changes: 20 additions & 0 deletions src/Scrutor/EnumerableExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
#if !NET8_0_OR_GREATER

using System.Collections.Generic;

namespace Scrutor;

internal static class EnumerableExtensions
{
public static ISet<T> ToHashSet<T>(this IEnumerable<T> source)
{
if (source is ISet<T> set)
{
return set;
}

return new HashSet<T>(source);
}
}

#endif
2 changes: 1 addition & 1 deletion src/Scrutor/IAssemblySelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,4 @@ public interface IAssemblySelector : IFluentInterface
/// <param name="assemblies">The assemblies to should be scanned.</param>
/// <exception cref="ArgumentNullException">If the <paramref name="assemblies"/> argument is <c>null</c>.</exception>
IImplementationTypeSelector FromAssemblies(IEnumerable<Assembly> assemblies);
}
}
2 changes: 1 addition & 1 deletion src/Scrutor/IFluentInterface.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ public interface IFluentInterface

[EditorBrowsable(EditorBrowsableState.Never)]
bool Equals(object? obj);
}
}
2 changes: 1 addition & 1 deletion src/Scrutor/IImplementationTypeFilter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -155,4 +155,4 @@ public interface IImplementationTypeFilter : IFluentInterface
/// <param name="predicate">The predicate to match types.</param>
/// <exception cref="ArgumentNullException">If the <paramref name="predicate" /> argument is <c>null</c>.</exception>
IImplementationTypeFilter Where(Func<Type, bool> predicate);
}
}
2 changes: 1 addition & 1 deletion src/Scrutor/IImplementationTypeSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ public interface IImplementationTypeSelector : IAssemblySelector
/// <exception cref="ArgumentNullException">If the <paramref name="action"/> argument is <c>null</c>.</exception>
/// <param name="publicOnly">Specifies whether too add public types only.</param>
IServiceTypeSelector AddClasses(Action<IImplementationTypeFilter> action, bool publicOnly);
}
}
2 changes: 1 addition & 1 deletion src/Scrutor/ILifetimeSelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ public interface ILifetimeSelector : IServiceTypeSelector
/// Registers each matching concrete type with the specified <paramref name="lifetime"/>.
/// </summary>
IImplementationTypeSelector WithLifetime(ServiceLifetime lifetime);
}
}
2 changes: 1 addition & 1 deletion src/Scrutor/ISelector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ namespace Scrutor;
public interface ISelector
{
void Populate(IServiceCollection services, RegistrationStrategy? options);
}
}
Loading
Loading