Skip to content

Commit 9ee967d

Browse files
Make InsertProvider idempotent and remove reflection
1 parent b922f29 commit 9ee967d

2 files changed

Lines changed: 56 additions & 22 deletions

File tree

src/ImageSharp.Web/DependencyInjection/ImageSharpBuilderExtensions.cs

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System;
55
using System.Linq;
6-
using System.Reflection;
76
using Microsoft.Extensions.Configuration;
87
using Microsoft.Extensions.DependencyInjection;
98
using Microsoft.Extensions.DependencyInjection.Extensions;
@@ -166,11 +165,12 @@ public static IImageSharpBuilder InsertProvider<TProvider>(this IImageSharpBuild
166165
where TProvider : class, IImageProvider
167166
{
168167
var descriptors = builder.Services.Where(x => x.ServiceType == typeof(IImageProvider)).ToList();
169-
builder.ClearProviders();
170-
168+
descriptors.RemoveAll(x => x.GetImplementationType() == typeof(TProvider));
171169
descriptors.Insert(index, ServiceDescriptor.Singleton<IImageProvider, TProvider>());
172170

171+
builder.ClearProviders();
173172
builder.Services.TryAddEnumerable(descriptors);
173+
174174
return builder;
175175
}
176176

@@ -186,11 +186,12 @@ public static IImageSharpBuilder InsertProvider<TProvider>(this IImageSharpBuild
186186
where TProvider : class, IImageProvider
187187
{
188188
var descriptors = builder.Services.Where(x => x.ServiceType == typeof(IImageProvider)).ToList();
189-
builder.ClearProviders();
190-
189+
descriptors.RemoveAll(x => x.GetImplementationType() == typeof(TProvider));
191190
descriptors.Insert(index, ServiceDescriptor.Singleton<IImageProvider>(implementationFactory));
192191

192+
builder.ClearProviders();
193193
builder.Services.TryAddEnumerable(descriptors);
194+
194195
return builder;
195196
}
196197

@@ -203,11 +204,7 @@ public static IImageSharpBuilder InsertProvider<TProvider>(this IImageSharpBuild
203204
public static IImageSharpBuilder RemoveProvider<TProvider>(this IImageSharpBuilder builder)
204205
where TProvider : class, IImageProvider
205206
{
206-
ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x =>
207-
x.ServiceType == typeof(IImageProvider)
208-
&& (x.ImplementationType == typeof(TProvider)
209-
|| (x.ImplementationFactory?.GetMethodInfo().ReturnType == typeof(TProvider))));
210-
207+
ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageProvider) && x.GetImplementationType() == typeof(TProvider));
211208
if (descriptor != null)
212209
{
213210
builder.Services.Remove(descriptor);
@@ -264,12 +261,7 @@ public static IImageSharpBuilder AddProcessor<TProcessor>(this IImageSharpBuilde
264261
public static IImageSharpBuilder RemoveProcessor<TProcessor>(this IImageSharpBuilder builder)
265262
where TProcessor : class, IImageWebProcessor
266263
{
267-
ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x =>
268-
x.ServiceType == typeof(IImageWebProcessor)
269-
&& x.Lifetime == ServiceLifetime.Singleton
270-
&& (x.ImplementationType == typeof(TProcessor)
271-
|| (x.ImplementationFactory?.GetMethodInfo().ReturnType == typeof(TProcessor))));
272-
264+
ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(IImageWebProcessor) && x.GetImplementationType() == typeof(TProcessor));
273265
if (descriptor != null)
274266
{
275267
builder.Services.Remove(descriptor);
@@ -326,12 +318,7 @@ public static IImageSharpBuilder AddConverter<TConverter>(this IImageSharpBuilde
326318
public static IImageSharpBuilder RemoveConverter<TConverter>(this IImageSharpBuilder builder)
327319
where TConverter : class, ICommandConverter
328320
{
329-
ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x =>
330-
x.ServiceType == typeof(ICommandConverter)
331-
&& x.Lifetime == ServiceLifetime.Singleton
332-
&& (x.ImplementationType == typeof(TConverter)
333-
|| (x.ImplementationFactory?.GetMethodInfo().ReturnType == typeof(TConverter))));
334-
321+
ServiceDescriptor descriptor = builder.Services.FirstOrDefault(x => x.ServiceType == typeof(ICommandConverter) && x.GetImplementationType() == typeof(TConverter));
335322
if (descriptor != null)
336323
{
337324
builder.Services.Remove(descriptor);
@@ -379,5 +366,10 @@ public static IImageSharpBuilder Configure<TOptions>(this IImageSharpBuilder bui
379366
builder.Services.Configure(configureOptions);
380367
return builder;
381368
}
369+
370+
private static Type GetImplementationType(this ServiceDescriptor descriptor)
371+
=> descriptor.ImplementationType
372+
?? descriptor.ImplementationInstance?.GetType()
373+
?? descriptor.ImplementationFactory?.GetType().GenericTypeArguments[1];
382374
}
383375
}

tests/ImageSharp.Web.Tests/DependencyInjection/ServiceRegistrationExtensionsTests.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Copyright (c) Six Labors.
22
// Licensed under the Apache License, Version 2.0.
33

4+
using System;
45
using System.Collections.Generic;
56
using System.Linq;
67
using System.Reflection;
@@ -191,11 +192,32 @@ public void CanInsertRemoveImageProviders()
191192
IReadOnlyList<ServiceDescriptor> providers = GetCollection<IImageProvider>(services);
192193
Assert.Equal(2, providers.Count);
193194
Assert.True(IsService<IImageProvider, MockImageProvider>(providers[0]));
195+
Assert.True(IsServiceImplementationType<IImageProvider, MockImageProvider>(providers[0]));
194196

195197
builder.RemoveProvider<MockImageProvider>();
196198
Assert.DoesNotContain(services, IsService<IImageProvider, MockImageProvider>);
197199
}
198200

201+
[Fact]
202+
public void CanInsertIdempotentImageProviders()
203+
{
204+
var services = new ServiceCollection();
205+
IImageSharpBuilder builder = services.AddImageSharp();
206+
207+
builder.InsertProvider<MockImageProvider>(0);
208+
builder.InsertProvider<MockImageProvider>(1);
209+
210+
Assert.Throws<ArgumentOutOfRangeException>(() => builder.InsertProvider<MockImageProvider>(2));
211+
212+
Assert.Single(services, IsService<IImageProvider, MockImageProvider>);
213+
Assert.Single(services, IsServiceImplementationType<IImageProvider, MockImageProvider>);
214+
215+
IReadOnlyList<ServiceDescriptor> providers = GetCollection<IImageProvider>(services);
216+
Assert.Equal(2, providers.Count);
217+
Assert.True(IsService<IImageProvider, MockImageProvider>(providers[1]));
218+
Assert.True(IsServiceImplementationType<IImageProvider, MockImageProvider>(providers[1]));
219+
}
220+
199221
[Fact]
200222
public void CanAddRemoveFactoryImageProviders()
201223
{
@@ -210,6 +232,26 @@ public void CanAddRemoveFactoryImageProviders()
210232
Assert.DoesNotContain(services, IsService<IImageProvider, MockImageProvider>);
211233
}
212234

235+
[Fact]
236+
public void CanInsertIdempotentFactoryImageProviders()
237+
{
238+
var services = new ServiceCollection();
239+
IImageSharpBuilder builder = services.AddImageSharp();
240+
241+
builder.InsertProvider(0, _ => new MockImageProvider());
242+
builder.InsertProvider(1, _ => new MockImageProvider());
243+
244+
Assert.Throws<ArgumentOutOfRangeException>(() => builder.InsertProvider(2, _ => new MockImageProvider()));
245+
246+
Assert.Single(services, IsService<IImageProvider, MockImageProvider>);
247+
Assert.Single(services, IsServiceImplementationFactory<IImageProvider, MockImageProvider>);
248+
249+
IReadOnlyList<ServiceDescriptor> providers = GetCollection<IImageProvider>(services);
250+
Assert.Equal(2, providers.Count);
251+
Assert.True(IsService<IImageProvider, MockImageProvider>(providers[1]));
252+
Assert.True(IsServiceImplementationFactory<IImageProvider, MockImageProvider>(providers[1]));
253+
}
254+
213255
[Fact]
214256
public void CanInsertRemoveFactoryImageProviders()
215257
{

0 commit comments

Comments
 (0)