Skip to content

Commit

Permalink
Merge pull request #299 from ServiceComposer/di-registration-bug
Browse files Browse the repository at this point in the history
Fix: Application startup fails if ASPNETCORE_ENVIRONMENT is set to Development
  • Loading branch information
mauroservienti authored Apr 1, 2021
2 parents 71fdd5a + f9f377f commit 1291e40
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<PackageReference Include="FakeItEasy" Version="6.1.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.6.1" />
<PackageReference Include="PublicApiGenerator" Version="10.1.2" />
<PackageReference Include="ServiceComposer.AspNetCore.Testing" Version="1.1.0" />
<PackageReference Include="ServiceComposer.AspNetCore.Testing" Version="1.3.0" />
<PackageReference Include="xunit" Version="2.4.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.2">
<PrivateAssets>all</PrivateAssets>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json.Linq;
using ServiceComposer.AspNetCore.Testing;
using Xunit;

namespace ServiceComposer.AspNetCore.Endpoints.Tests
{
public class When_validating_container_configuration
{
class EmptyResponseHandler : ICompositionRequestsHandler
{
[HttpGet("/empty-response/{id}")]
public Task Handle(HttpRequest request)
{
var vm = request.GetComposedResponseModel();
var ctx = request.GetCompositionContext();
vm.RequestId = ctx.RequestId;

return Task.CompletedTask;
}
}

[Fact]
public async Task Startup_should_not_fail()
{
// Arrange
using var webApp = new SelfContainedWebApplicationFactoryWithHost<Dummy>
(
configureServices: services =>
{
services.AddViewModelComposition(options =>
{
options.AssemblyScanner.Disable();
options.RegisterCompositionHandler<EmptyResponseHandler>();
});
services.AddRouting();
},
configure: app =>
{
app.UseRouting();
app.UseEndpoints(builder => builder.MapCompositionHandlers());
}
)
{
HostBuilderCustomization = builder =>
{
builder.UseDefaultServiceProvider(options =>
{
options.ValidateScopes = true;
options.ValidateOnBuild = true;
});
}
};

var client = webApp.CreateClient();

// Act
var response = await client.GetAsync("/empty-response/1");

// Assert
Assert.True(response.IsSuccessStatusCode);

var contentString = await response.Content.ReadAsStringAsync();
dynamic body = JObject.Parse(contentString);
Assert.NotNull(body.requestId);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
#if NET5_0 || NETCOREAPP3_1

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
Expand All @@ -12,20 +11,7 @@ public static class HttpRequestModelBinderExtension
public static Task<T> Bind<T>(this HttpRequest request) where T : new()
{
var context = request.HttpContext;
RequestModelBinder binder;
try
{
binder = context.RequestServices.GetRequiredService<RequestModelBinder>();
}
catch (InvalidOperationException e)
{
throw new InvalidOperationException("Unable to resolve one of the services required to support model binding. " +
"Make sure the application is configured to use MVC services by calling either " +
$"services.{nameof(MvcServiceCollectionExtensions.AddControllers)}(), or " +
$"services.{nameof(MvcServiceCollectionExtensions.AddControllersWithViews)}(), or " +
$"services.{nameof(MvcServiceCollectionExtensions.AddMvc)}(), or " +
$"services.{nameof(MvcServiceCollectionExtensions.AddRazorPages)}().", e);
}
var binder = context.RequestServices.GetRequiredService<RequestModelBinder>();

return binder.Bind<T>(request);
}
Expand Down
24 changes: 23 additions & 1 deletion src/ServiceComposer.AspNetCore/ViewModelCompositionOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
using System.Linq;
using System.Reflection;
using Microsoft.Extensions.DependencyInjection;
#if NETCOREAPP3_1 || NET5_0
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.Extensions.Options;
#endif

namespace ServiceComposer.AspNetCore
{
Expand Down Expand Up @@ -79,7 +84,24 @@ internal void InitializeServiceCollection()
});
}

Services.AddSingleton<RequestModelBinder>();
Services.AddSingleton(container =>
{
var modelBinderFactory = container.GetService<IModelBinderFactory>();
var modelMetadataProvider = container.GetService<IModelMetadataProvider>();
var mvcOptions = container.GetService<IOptions<MvcOptions>>();

if (modelBinderFactory == null || modelMetadataProvider == null || mvcOptions == null)
{
throw new InvalidOperationException("Unable to resolve one of the services required to support model binding. " +
"Make sure the application is configured to use MVC services by calling either " +
$"services.{nameof(MvcServiceCollectionExtensions.AddControllers)}(), or " +
$"services.{nameof(MvcServiceCollectionExtensions.AddControllersWithViews)}(), or " +
$"services.{nameof(MvcServiceCollectionExtensions.AddMvc)}(), or " +
$"services.{nameof(MvcServiceCollectionExtensions.AddRazorPages)}().");
}

return new RequestModelBinder(modelBinderFactory, modelMetadataProvider, mvcOptions);
});
#endif

if (AssemblyScanner.IsEnabled)
Expand Down

0 comments on commit 1291e40

Please sign in to comment.