-
Notifications
You must be signed in to change notification settings - Fork 33
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
Support for new .net 8.0 features #314
base: master
Are you sure you want to change the base?
Conversation
Can be used to register built-in .net DI attributes
I've done the adapters, with some noteworthy implementation details: Important I have opted for a Warning I have turned Warning In |
@ipjohnson can I enable the latest C# 12 compiler in csproj? would your appveyor CI build support it? I'm sticking to the current csproj for now but the code would benefit from target typing, better pattern matching, or collection literals. |
I'm all for enabling the new features. Looks like .net 8 sdk is included so I'd imagine it works. |
ok, great! I have a massive (unfortunately) patch coming up for Locate Key injection. |
I've done an implementation of key injection. Sadly, this turned out to be a massive change. One option could be to "bake in" the key inside the compiled delegate, but it would not work with the next feature "AnyKey" exports. The key has to be dynamic, so it must be passed into Note It helps to keep in mind that top-level requests and nested requests work slightly differently: To keep internal structure changes minimal, I've decided to encode the concept of "injecting the import key" by introducing a well-known singleton key: Any type can be imported as keyed by
As a result the new public API surface is pretty small:
There's one part of this PR that I'm not really satisfied with, but I couldn't find any better way. It's for dynamic strategies, please take a careful look at this: 81b086e#diff-53219a75f4a18ed35629d49fa3559693bb7f0ae284d0915f15febf2e6f2fd214R114-R117 I was writing tests to cover more wrapped strategies, like lifestyles, |
I have opted into the latest C# compiler version with I took this opportunity to introduce a global The build is fixed (failure was myself carelessly using a C# 9 feature, which didn't work when compiling for old fx as the default C# version depends on target fx). There are 3 (new) tests failing, it's related to Meta, Lazy and IEnumerable as explained in my previous comment. |
I agree this should work and agree it should be fixed. As for the dynamic strategies that's not a horrible solution, dynamic strategies in and of themselves are a bit hacky. |
Do you know how, and have the time to do it? If not, I'll try to take a look. In the meantime I intend on tackling the "any key" feature, shouldn't be too hard. |
WIP: Lifestyles (singletons, etc.) do not work yet. Added a skipped test for LocateAll (keyed IEnumerable not supported yet)
Progress on New public API surface is small:
Lifestyles are sill WIP (I have one failing test for them). @ipjohnson several points worth your attention:
|
Key is lost at top-level when using Singleton lifestyle.
@ipjohnson Would love your opinion how you would implement the Lifestyles, it's tricky. As of now I don't see an "easy" way to fix this. Also I added a failing test: when locating (top-level) a singleton, the key is lost. This is because at the top-level the key is not in As long as the located instance doesn't inject I haven't fixed this, because it is closely related to the problem of |
I must admit I missed the nuance of the It very much seems like the key is viral and needs to be carried though the lifestyle. Is it possible to treat it like |
It's still gonna be a complex change. For regular lifestyles, Based on this we could inject some "per-key" lifestyle logic but one issue is that I'm not sure where to store state (it'd need an immutable hashmap based on key, with a cloned lifestyle for each), short of adding that optional hashmap to all lifestyles. At this point I'm thinking: let's go full breaking change and introduce an abstract base This does not solve everything, though. (I'm writing as I'm thinking here:)
Then there's the case of Things would be simpler if we could more easily relate a lifestyle with a registered key. There's one last point that's unclear to me: is this behavior specific to when |
One question: is there a specific point in code where all registrations are "frozen" and processed, before anything is located, and after which nothing can be modified anymore? That would be a solution as we could look for |
I coded a solution for the lifetime-per-key behavior of @ipjohnson can you carefully review commit 7f13aec ? it's not big.
Somehow I noticed that all lifestyles basically compile and cache an |
Fixed the Singleton lifecycle as well, by merging Kept |
Great news as this should be everything for .net 8 (phew that was a lot more than I expected 😩). |
What would the signature change look like? |
Not sure! I didn't spend too much time thinking about it as I went for the fully compatible solution first. |
It was not taking Keyed imports into account (fixes 4 failures in MS DI specifications). Added PolySharp dependency in .net 4.6.2 to be able to use new C# features.
MS keyed DI specifications led to me to find a bug/limitation in the "Best Match" ctor selection: it was not considering keys import. I have fixed this in be118fc. Note that for .net fx 4.6.2 I added a new dependency: PolySharp @ipjohnson Note that the Dynamic construtor selection suffers from the same lack of keyed imports support. |
@stephenlautier Yes, this error indicates that the DI provider (in this case Grace 7.0) does not support MS keyed DI interfaces from .net 8.0, so you can't use them. (Note that Grace 7.0 can still be used as a DI provider because MS separated the keyed interface and made them "optional" for back-compat. Also Grace has had keyed exports for a long time and they also work fine, just not with MS DI attributes / interfaces.) And yes, the version from this branch will fix that and provide full MS DI keyed interfaces support. |
Yes, we do use keyed from Grace (and still does) though the issue Microsoft Orleans 8 uses the new Keyed internally which why it breaks and we don't have control over 😞 Looking forward for this change to get merged ❤️ |
@stephenlautier working on it, it's almost complete now. |
Return true for keyed collections and some wrappers (both previously unsupported).
Required by MS DI specifications
Focused on fixing remaining incompatibilities with MS DI:
I have also changed a behavior I previously described: when using I did not change the behavior when importing a non-keyed service: Please note that although the MS spec is now 100% passing 🎉, this PR is not yet fully complete. I have a bit of work left on the collection strategies. |
@jods4 would this fix the above issue that @stephenlautier mentioned? If yes @ipjohnson would it be possible to release a dev (pre-release) package from this branch? this will help us a lot to continue working on our migration and also we will be testing this feature. |
👆 |
@jods4 I downloaded your repo and built them and gave our app a test During startup Im having the following exception (which is not from our code but from Orleans) Alto seeing the code its seems "intended" as its marked as required and no default This is their usage (from Microsoft Orleans) return serviceProvider.GetServices<NamedService<IGrainDirectory>>() ?? Enumerable.Empty<NamedService<IGrainDirectory>>(); https://github.com/dotnet/orleans/blob/main/src/Orleans.Runtime/Hosting/DirectorySiloBuilderExtensions.cs#L71 This is our config for grace (though tried to comment the Behaviors but still the same) var graceConfig = new InjectionScopeConfiguration
{
Behaviors =
{
AllowInstanceAndFactoryToReturnNull = true,
}
}; Not sure if we need to configure something specifically, or its a bug |
Some more updates to isolate a bit the issue I added a very basic test to test similar what they are doing however that succeeds And i also replicated the issue with a basic orleans sample in order to see the issue (and also isolate from our stuff)
You should get the above exception |
@stephenlautier |
Just tried it now, but didnt change anything |
@stephenlautier You should probably open an issue separate from this PR to not mix discussions. It might help if you posted the full In your unit test I'm not seeing any registration code and that's probably the key difference: |
@jods4 agreed, will open a separate issue however will link to this as it might be related to this (unsure) as it used to work (pre .net8) From their end no it looks "simple" were i gave the usage right above it theres the registration which is this one https://github.com/dotnet/orleans/blob/main/src/Orleans.Runtime/Hosting/DirectorySiloBuilderExtensions.cs#L42 collection.AddSingleton(sp => new NamedService<IGrainDirectory>(name, implementationFactory(sp, name)));
// Check if the grain directory implements ILifecycleParticipant<ISiloLifecycle>
if (typeof(ILifecycleParticipant<ISiloLifecycle>).IsAssignableFrom(typeof(T)))
{
collection.AddSingleton(s => (ILifecycleParticipant<ISiloLifecycle>)s.GetGrainDirectory(name));
} I'll try to dig a bit further and open another issue as you suggested. Sorry for hijacking this 🙏 |
I'm all for releasing a version from this branch. Sorry I've been incommunicado, between home life and work life I have very little time for anything these days. |
Try to respect `RootedRequest` more, whatever that means
@ipjohnson I have modified Grace design when it comes to
This helped me simplify the wrappers, collections, and lifestyles code. Warning When compiling an export registered as |
@ipjohnson It turns out that this change did not fully solve the "non-core" collections case. Other collections such as They are implemented as "missing handlers", which means they only work if you have This led me to notice that missing handlers are never registered as keyed, so it just doesn't work yet -- something more I need to fix. It's also worth noting that special collections are registered as concrete types: there is no A lofty goal could be to handle collections like C# 12 handles collection expressions:
|
@ipjohnson I have added a new public API to more easily export custom Wrapper strategies: Its usage is demonstrated in updated |
In the end, fixing the collection strategies was much easier than expected. So the change for collections is minimal: they are still added by the default missing strategy provider, as open generic types, but they export themselves as both keyless and keyed for I added keyed tests for supported collection types, and everything is green. |
@ipjohnson At this point, I think I've covered all features of Grace that I could think of with the newly improved keyed support. You can merge this and publish a new 8.0 pre-release when you're ok with this PR. There at least one point that I'd like to check with you before making a final release: caching. Is there a reason the main cache doesn't use |
@ipjohnson I hope you can find a little bit of time to help me move this forward? |
@ipjohnson it would be nice if you can find some time to get this merged, so we can use stable version from the main repo. Thanks 🙏 |
This branch adds support for new .net 8.0 DI features, to support ipjohnson/Grace.DependencyInjection.Extensions#36
Required features:
IImportAttribute
, such as[FromKeyedServices]
.I'll write implementation notes in comment below as I go.
Things worth following-up:
Locate
only caches non-keyed ones. Digging the call graph, some end up being cached lower down the stack but I don't think all do:LocateEnumerableStrategy
,Scoped<>
,CompiledWrapperStrategy
.