镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

[API Proposal]: Use Source Generators in default DependencyInjector #82679

Closed

Description

@Rabadash8820

Background and motivation

Source generators are a pretty handy replacement for lots of traditionally reflection-based systems, like dependency injection and IoC containers. Rather than looking up constructors and invoking them via reflection, source generator-based libraries can generate classes at build time that call specific constructors explicitly, dramatically improving the speed of service resolution at runtime. Several community libraries are already pursuing this approach for DI, including:

Unfortunately, all of these libraries are still pretty immature, with little exposure in the community, meaning there are few tutorials/articles written about them, spotty support, etc. Some of them may become more popular and outcompete the mainstays like Autofac, Ninject, Zenject, etc., but for now, their adoption is a hard sell, despite the performance benefits.

I've tried looking through the source code of the Microsoft.Extensions.DependencyInjection namespace, but it's still pretty over my head. It's unclear to me whether those implementations are already using source generators, but I'm pretty sure I read elsewhere that they're not. Seems to me that the default DI system provided by .NET should be as performant as possible, and source generators are an ideal way to achieve this.

API Proposal

This less of an API Proposal, and more of an "implementation suggestion". If the IoC containers in Microsoft.Extensions.DependencyInjection are not already using source generators, then I think that they should be!

API Usage

APIs will probably look/feel the same, but just generate a type with explicit constructor calls at build time.

Alternative Designs

The existing design. :P

Risks

Would probably involve a pretty significant rewrite of types in Microsoft.Extensions.DependencyInjection, which could take up a lot of time/resources.

Activity

  1. added
    api-suggestionEarly API idea and discussion, it is NOT ready for implementation
    on Feb 25, 2023
  2. ghost added
    untriagedNew issue has not been triaged by the area owner
    on Feb 25, 2023
  3. jkotas commented on Feb 26, 2023

    @jkotas
    Member

    Microsoft.Extensions.DependencyInjection does not use source generators.

    APIs will probably look/feel the same

    This is the hard part. The current Microsoft.Extensions.DependencyInjection model is too dynamic, without enough static information, to make source generators work. We would need an alternative model (different APIs, custom attributes) to make source generators work well for dependency injection. The projects that you have linked demonstrate possible implementations of such alternative model.

  4. Rabadash8820 commented on Feb 26, 2023

    @Rabadash8820
    Author

    Makes sense. Maybe this would need a new Microsoft.Extensions.DependencyInjection.SourceGenerated namespace or something, to give you all the freedom to restructure the APIs. Either way, now the feature request is here; I knew it would be a while before anything like this actually materializes.

    In the meantime, do you (either you personally or MS as a whole) have any recommendation for a good source-generator-based DI framework? I haven't looked into any of the above super thoroughly yet...

  5. jkotas commented on Feb 26, 2023

    @jkotas
    Member

    @davidfowl Any recommendations for a good source-generator based DI framework?

  6. davidfowl commented on Feb 26, 2023

    @davidfowl
    Member

    My opinion is tainted by the fact that @pakrym used to work on MEDI and built https://github.com/pakrym/jab after long discussions we had about what that model would look like. I haven't looked at the other ones in depth enough to give a good opinion on which ones to use.

  7. Sergio0694 commented on Feb 26, 2023

    @Sergio0694
    Contributor

    "This is the hard part. The current Microsoft.Extensions.DependencyInjection model is too dynamic, without enough static information, to make source generators work."

    Not necessarily. For instance, I wrote a source generator which we're currently using in the Microsoft Store, which effectively just generates stubs to register services over MS.Ex.Di. It uses a syntax very similar to what Jab does (which is cool, considering we both designed it without knowing about each other's project), ie. with attributes to define services and interfaces, and then generates the appropriate registration calls over a target IServiceCollection. This makes it AOT and trim-safe, because services will always be registered with generated factories that will handle all dependency resolution. It also makes it pretty general, as it can work over any arbitrary service collection, as long as it implements IServiceCollection. And it also generates useful diagnostics in case there's some registration errors at compile time. Wondering if something like this could be an approach that would make sense for MS.Ex.DI, given it's purely additive and backwards compatible? Happy to ask if I can open source the code in case it could be useful 🙂

  8. Rabadash8820 commented on Feb 27, 2023

    @Rabadash8820
    Author

    Yeah something like what @Sergio0694 is describing sounds awesome. For now I'll definitely take a closer look at jab, sounds like it's got some strong talent behind it. Mainly I'm just looking for something that will be maintained for the foreseeable future, and the MS extensions are pretty much the best in that regard. 👌

  9. pakrym commented on Mar 2, 2023

    @pakrym
    Contributor

    Source generation can't be a goal in itself; it has to solve some problems like startup performance, trimability, or runtime performance.

    It looks like .NET team mostly figured out trimming.

    The runtime performance of MEDI is better than source-generated DI implementations on .NET Core because it can "rewrite" resolution code at runtime and do tricks like embedding direct references to singleton objects into transient service factory implementations and skipping extra checks that source-generated implementations can't avoid.

    Source-generated containers have better startup performance because they can compute the service graph and run checks during the compilation. Unfortunately, this doesn't fit well into Microsoft.Extension.* ecosystem where the set of dependency injection services is controlled at runtime as @jkotas pointed out above.

    Knowing the service graph requires running the code, and every time you run the code, you can get a different graph. I toyed with the idea of a double-tap source-generated container where on the first app run it dumps the service graph, and on the second compilation, the graph gets turned into a source-gen container. Unfortunately, there is no guarantee that the service graph doesn't change between two invocations so the compilation result might instantly be wrong.

    Another limitation that source-generated containers have is that they can only operate only on types accessible to the compiled assembly. MEDI doesn't have this limitation, and ASP.NET heavily relies on the ability of service implementations to stay internal.

    In short, my opinion is that source-generated containers might be useful in short-lived applications where the entire service graph is controlled by the author. Unfortunately in .NET ecosystem right now, this means not using any Microsoft.Extensions or ASP.NET Core libraries.

    For things really to change and enable true source-gen DI, Microsoft.Extensions.* and Microsoft.AspNetCore.* libraries will have to provide static (e.g. attribute-based) descriptions of their service graphs and public implementations of their services. In that case, it will be possible for a source-generated container to implement a IServiceProvider for ASP.NET Core application. Having said that, I'm not sure whether this is realistic considering how embedded the idea of using dependency injection as a configuration primitive is in the .NET ecosystem.

  10. added
    source-generatorIndicates an issue with a source generator feature
    and removed
    untriagedNew issue has not been triaged by the area owner
    on Mar 13, 2023
  11. eerhardt commented on Apr 25, 2023

    @eerhardt
    Member

    For completeness, I'm linking my notes on this topic here. They are mostly just duplicates of what is said above.

    I believe this issue is a duplicate #44432.

  12. Rabadash8820 commented on Apr 25, 2023

    @Rabadash8820
    Author

    Thanks for the discussion, all. I agree that this issue is a duplicate, so feel free to close.

  13. ghost locked as resolved and limited conversation to collaborators on May 26, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions