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

EnableCurrentScope option gets overwritten #193

Open
kemsky opened this issue Jan 12, 2022 · 6 comments
Open

EnableCurrentScope option gets overwritten #193

kemsky opened this issue Jan 12, 2022 · 6 comments

Comments

@kemsky
Copy link

kemsky commented Jan 12, 2022

Currently we are migrating legacy app to Asp.Net Core 2.2 as the first step, so we are using LightInject.Microsoft.AspNetCore.Hosting.

There are several interceptors that access current scope, for example transaction interceptor that automatically starts DB transaction, within interceptor we want to get scoped instance of EF context: Container.GetInstance<IContext>(), it requires current scope to work. I've tried the following:

        public static IWebHost CreateWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseLightInject(options =>
                {
                    options.EnableCurrentScope = true;
                })
                .UseStartup<Startup>()
                .Build();

But it turns out that EnableCurrentScope gets overwritten:

        public LightInjectServiceProviderFactory(ContainerOptions options)
        {
            var clonedOptions = options.Clone();
            clonedOptions.WithMicrosoftSettings(); // <--- Here!
            containerFactory = () => new ServiceContainer(clonedOptions);
        }

Now I'm confused, was it intentional? Maybe we are doing something wrong?

Looks like this is the same issue as #87.


I tried another overload:

                .UseLightInject(new ServiceContainer(new ContainerOptions
                {
                    EnableVariance = false,
                    EnableCurrentScope = true,
                    EnableOptionalArguments = true,
                    EnablePropertyInjection = false
                }))

It kinda works, but only for the first call, next times scopes are in incorrect order and it breaks.

Does LightInject support current scope/nested scopes in Asp.Net Core at all?

@kemsky
Copy link
Author

kemsky commented Jan 14, 2022

@seesharper, could you please give an advice?

@seesharper
Copy link
Owner

Hi @kemsky

The reason that LightInject disables the "current scope" is because the default DI provider does not support this either. Instead it relies on passing the scope rather than storing the current scope in an AsyncLocal<T>. The "Current scope" feature is only kept for backward compatibility and should be avoided in Asp.Net Core apps. Since I don't know exactly what you are trying to do here it might be simpler if you could come up with a simple repro app and maybe I can show you how to do this in another way 👍

On a side note. If you are migrating your apps you should really go for net5.0 or net6.0. netcoreapp2.2 is no longer supported by Microsoft and netcoreapp3.1 will be EOL within this year :)

@kemsky
Copy link
Author

kemsky commented Jan 14, 2022

@seesharper, I wish I could migrate to net6.0, but it is almost impossible to update all our dependencies at once within limited timeframe (as always), so I started with the easiest possible way.

I'm not sure if it is worth creating sample repo at this stage, I'll try to describe my problem better first.

We use LightInject interception package a lot, for example:

// Transactional attribute is a marker for async interceptor
[Transactional]
public virtual Task SaveAsync(Entity entity)
{
   // this is just for illustration purposes, code executed inside transaction
    await Context.SaveAsync();
}

Async interceptor simply calls Context.Database.BeginTransaction() and Context.Database.EndTransaction(), but this makes inteceptor to depend on scoped instance of Context. The problem is that inteceptor itself is not created immmediately (lazy), it is initialized only when corresponding method (SaveAsync in this example) is invoked, and it obviously can not work without some scope. I tried using ProxyDefinition(type, useLazyTarget: false) to make interceptors eager(?), but it does not help for some reason, still complains that there is no current scope. I think interception package could capture proxy scope and use it later to initialize interceptor instances, that would solve this problem I guess.

By now I've implemented custom ScopeManager that uses AsyncLocal, it looks promising, but it would be better to avoid such custom code.

Thanks in advance.

@seesharper
Copy link
Owner

seesharper commented Jan 15, 2022

Hi again @kemsky . I understand your concern about moving all the way to net6, but I would at least recommend that you move to netcoreapp3.1. Then you can go live with a runtime that is supported by Microsoft :)

Regarding the scope problem you're having. It is not that I don't want to help you, but I have spent so much time in the past trying to guess what the actual scenario is :) . I don't have any experience with Entity Framework either so too many unknowns :) I would really like to help you out, but that would require a simple repro of the problem. In this case I would guess a simple WebAPI app that uses. LightInject, LightInject.Interception and Entity Framework?

@kemsky
Copy link
Author

kemsky commented Jan 18, 2022

@seesharper, alright, this is example project: https://github.com/kemsky/lightinject-aspnet-core

@kemsky
Copy link
Author

kemsky commented Jan 31, 2022

@seesharper, hi, did you have a chance to look at it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants