Skip to content

Commit 252ad5d

Browse files
authored
Throw if resolving keyed service from non-keyed container (#53051)
* Throw if resolving keyed service from non-keyed container * Update message and add tests * Fix reference * Check for RDF exception at construction time
1 parent c284950 commit 252ad5d

File tree

3 files changed

+51
-0
lines changed

3 files changed

+51
-0
lines changed

src/Http/Http.Extensions/gen/StaticRouteHandlerModel/Emitters/EndpointParameterEmitter.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,11 @@ internal static void EmitKeyedServiceParameterPreparation(this EndpointParameter
335335
{
336336
codeWriter.WriteLine(endpointParameter.EmitParameterDiagnosticComment());
337337

338+
codeWriter.WriteLine("if (httpContext.RequestServices.GetService<IServiceProviderIsService>() is not IServiceProviderIsKeyedService)");
339+
codeWriter.StartBlock();
340+
codeWriter.WriteLine(@"throw new InvalidOperationException($""Unable to resolve {nameof(FromKeyedServicesAttribute)}. This service provider doesn't support keyed services."");");
341+
codeWriter.EndBlock();
342+
338343
var assigningCode = endpointParameter.IsOptional ?
339344
$"httpContext.RequestServices.GetKeyedService<{endpointParameter.Type}>({endpointParameter.KeyedServiceKey});" :
340345
$"httpContext.RequestServices.GetRequiredKeyedService<{endpointParameter.Type}>({endpointParameter.KeyedServiceKey})";

src/Http/Http.Extensions/src/RequestDelegateFactory.cs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -788,6 +788,10 @@ private static Expression CreateArgument(ParameterInfo parameter, RequestDelegat
788788
}
789789
else if (parameterCustomAttributes.OfType<FromKeyedServicesAttribute>().FirstOrDefault() is { } keyedServicesAttribute)
790790
{
791+
if (factoryContext.ServiceProviderIsService is not IServiceProviderIsKeyedService)
792+
{
793+
throw new InvalidOperationException($"Unable to resolve {nameof(FromKeyedServicesAttribute)}. This service provider doesn't support keyed services.");
794+
}
791795
var key = keyedServicesAttribute.Key;
792796
return BindParameterFromKeyedService(parameter, key, factoryContext);
793797
}

src/Http/Http.Extensions/test/RequestDelegateGenerator/RequestDelegateCreationTests.KeyServices.cs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
using Microsoft.AspNetCore.Http.Metadata;
44
using Microsoft.AspNetCore.Http.RequestDelegateGenerator;
55
using Microsoft.Extensions.DependencyInjection;
6+
using Microsoft.Extensions.Logging.Abstractions;
7+
68
namespace Microsoft.AspNetCore.Http.Generators.Tests;
79

810
public partial class RequestDelegateCreationTests : RequestDelegateCreationTestBase
@@ -197,4 +199,44 @@ public async Task SupportsMultipleKeyedAndNonKeyedServices()
197199
Assert.IsType<TestService>(httpContext.Items["arg2"]);
198200
Assert.Same(myOriginalService2, httpContext.Items["arg3"]);
199201
}
202+
203+
[Fact]
204+
public async Task ThrowsIfDiContainerDoesNotSupportKeyedServices()
205+
{
206+
var source = """
207+
app.MapGet("/", (HttpContext context, [FromKeyedServices("service1")] TestService arg1) =>
208+
{
209+
context.Items["arg1"] = arg1;
210+
});
211+
""";
212+
var (_, compilation) = await RunGeneratorAsync(source);
213+
var serviceProvider = new MockServiceProvider();
214+
if (!IsGeneratorEnabled)
215+
{
216+
var runtimeException = Assert.Throws<InvalidOperationException>(() => GetEndpointFromCompilation(compilation, serviceProvider: serviceProvider));
217+
Assert.Equal("Unable to resolve FromKeyedServicesAttribute. This service provider doesn't support keyed services.", runtimeException.Message);
218+
return;
219+
}
220+
var endpoint = GetEndpointFromCompilation(compilation, serviceProvider: serviceProvider);
221+
222+
var httpContext = CreateHttpContext(serviceProvider);
223+
var exception = await Assert.ThrowsAsync<InvalidOperationException>(async () => await endpoint.RequestDelegate(httpContext));
224+
Assert.Equal("Unable to resolve FromKeyedServicesAttribute. This service provider doesn't support keyed services.", exception.Message);
225+
}
226+
227+
private class MockServiceProvider : IServiceProvider, ISupportRequiredService
228+
{
229+
public object GetService(Type serviceType)
230+
{
231+
if (serviceType == typeof(Microsoft.Extensions.Logging.ILoggerFactory))
232+
{
233+
return NullLoggerFactory.Instance;
234+
}
235+
return null;
236+
}
237+
public object GetRequiredService(Type serviceType)
238+
{
239+
return GetService(serviceType);
240+
}
241+
}
200242
}

0 commit comments

Comments
 (0)