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

Proposal: allow service providers registered in the root scope to be invoked with values and other providers in the scoped injector #83

Open
chunming-lu opened this issue May 14, 2024 · 1 comment
Labels
question Further information is requested

Comments

@chunming-lu
Copy link

Thanks for the framework, which provides perfect experience on dependency injection in my application.

However when I'm using the framework, I find that the providers registered in the root/parent scope will only be invoked in the registered scope. For example the test case blow:

type SomeService struct {
	someRuntimeVal int
}

func ProvideSomeService(injector do.Injector) (*SomeService, error) {
	val := do.MustInvokeNamed[int](injector, "someVal")
	return &SomeService{
		someRuntimeVal: val,
	}, nil
}

func TestRuntimeInvoke(t *testing.T) {
	rootInjector := do.DefaultRootScope
	do.Provide(rootInjector, ProvideSomeService)

	runtimeInjector := rootInjector.Clone().Scope("runtime")
	do.ProvideNamedValue(runtimeInjector, "someVal", 100)
	service, err := do.Invoke[*SomeService](runtimeInjector)
	if err != nil {
		t.Errorf("Failed to invoke service: %v", err)
	} else if service.someRuntimeVal != 100 {
		t.Errorf("Wrong instance initialization: expected: 100, actual: %v", service.someRuntimeVal)
	}
}

I would expect the service provider can be injected in the root scope, and can be invoked correctly in each forked scope, with correct runtime values. In current framework, the test case will fail when invoking *SomeService, with error message:

Failed to invoke service: DI: could not find service someVal, available services: *SomeService, path: *SomeService -> someVal

I read the code and find that when creating scopes, the services are not deep copied to the scoped injector, so the child scopes are using the same service instance in the parent scope. It's the same with Injector.Clone() method since it also only shadow copies the services. It would be best if each injector can have its own provider management namespace and invoke the owning and inheriting providers independently.

@samber
Copy link
Owner

samber commented May 16, 2024

A service can depend on a service of the same scope or from ancestors.

In your example, *SomeService should be injected in runtimeInjector and someVal in root scope.

@samber samber added the question Further information is requested label May 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants