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

Make ASP.NET Core integration more fluent #684

Open
dotnetjunkie opened this Issue Apr 15, 2019 · 0 comments

Comments

Projects
None yet
1 participant
@dotnetjunkie
Copy link
Collaborator

dotnetjunkie commented Apr 15, 2019

The current ASP.NET Core integration requires the user to add registrations to the IServiceCollection manually, for instance:

services.AddSingleton<IControllerActivator>(
    new SimpleInjectorControllerActivator(container));
services.AddSingleton<IViewComponentActivator>(
    new SimpleInjectorViewComponentActivator(container));

services.EnableSimpleInjectorCrossWiring(container);
services.UseSimpleInjectorAspNetRequestScoping(container);

I'd like to propose a more intuitive and fluent way of integrating Simple Injector with ASP.NET Core:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddSimpleInjector(container, options =>      // .Integration.ServiceCollection
        {
            options.AddAspNetCore()                   // .Integration.AspNetCore
                .AddControllerActivation()            // .Integration.AspNetCore.Mvc.Core
                .AddViewComponentActivation()         // .Integration.AspNetCore.Mvc.Core
                .AddPageModelActivation()             // .Integration.AspNetCore.Mvc
                .AddTagHelperActivation();            // .Integration.AspNetCore.Mvc
        });
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseSimpleInjector(container, options =>       // .Integration.ServiceCollection
    {
        options.UseMiddleware<CustomMiddleware1>(app);// .Integration.AspNetCore
        // Default value AutoCrossWireFrameworkComponents == true
        options.AutoCrossWireFrameworkComponents = true;// .Integration.AspNetCore

        // Or use CrossWire in case you don't want to auto cross wire
        options.CrossWire<ILoggerFactory>();          // .Integration.AspNetCore
        options.CrossWire<IOptions<IdentityCookieOptions>>();
    });
}

Explanation:

  • The AddSimpleInjector(Container, Action<Options>) extension method returns the IServiceCollection to allow other calls to be added fluently.
  • Additional configurations can be added by specifying an options => delegate.
  • This AddSimpleInjector extension method should do the following things:
    • Configures the container to make cross wiring possible (EnableSimpleInjectorCrossWiring)
  • AddAspNetCore integrates Simple Injector with ASP.NET Core and returns a builder to allow further configuration for e.g. MVC. This extension method should do the following things:
    • Set the Options.DefaultScopedLifestyle to AsyncScopedLifestyle, because this is the default lifestyle for ASP.NET Core applications.
    • Wrap each web request in an AsyncScopedLifestyle scope (i.e. UseSimpleInjectorAspNetRequestScoping)
    • Allow auto-cross-wired services to be resolved within the current web request, to prevent Torn Lifestyles.
    • Add an IHttpContextAccessor to IServiceCollection in case it is missing. An IHttpContextAccessor is required to achieve the auto cross wiring as described in the previous point.
  • AddControllerActivation is equivalent to adding the SimpleInjectorControllerActivator and calling RegisterMvcControllers
  • AddViewComponentActivation is equivalent to adding the SimpleInjectorViewComponentActivator and calling RegisterMvcViewComponents
  • AddPageModelActivation is equivalent to adding the SimpleInjectorPageModelActivatorProvider and calling RegisterPageModels
  • AddTagHelperActivation is equivalent to adding the AddSimpleInjectorTagHelperActivation and registering all tag helpers in Simple Injector (there currently is no RegisterTagHelpers!!)
  • UseSimpleInjector is called after ASP.NET Core's IServiceProvider has been built and allows to apply stuff that requires the availability of an IApplicationBuilder or IServiceProvider, making it impossible to apply them at an earlier stage:
    • options.UseMiddleware<T>(app) is equivalent to calling app.UseMiddleware<T>(container)
    • options.AutoCrossWireAspNetComponents() is equivalent to calling container.AutoCrossWireAspNetComponents(app)
    • options.CrossWire<T>() is equivalent to calling container.CrossWire<T>(app) and allows registering services that can't be auto cross wired (e.g. IEnumerable<T>), or when auto cross wiring is not enabled.

Questions:

  • As scoping is used by almost all users, should AddSimpleInjector enable request scoping automatically with the option to disable it, or the other way around? Downside of enabling this by default is that (in the current versions of ASP.NET Core) there is a performance penalty in having async state. Downside of disabling this by default is that 99% of the users actually need request scoping (or don't care about this performance penalty).
  • As cross wiring in ASP.NET Core requires an IHttpContextAccessor for resolving non-singleton services, should AddSimpleInjector automatically add an accessor with the risk of lowering the performance for users that don't require scoped services? (related to previous question)
  • As IServiceCollection (and the built-in container) can be used outside the context of ASP.NET Core, should these extension methods be designed in such way that it can possibly work outside of ASP.NET Core? (Related to #639) If so, this means that IHttpContextAccessor can't be added automatically by AddSimpleInjector. The same holds for UseSimpleInjector that depends on IApplicationBuilder, which is an ASP.NET Core-specific interface. And AutoCrossWireAspNetComponents currently depends on the existence of IHttpContextAccessor which is ASP.NET Core-specific as well. In the current design suggestion, the AddSimpleInjector and UseSimpleInjector methods are extracted to a non ASP.NET-specific library called (SimpleInjector.Integration.ServiceCollection).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.