modular icon indicating copy to clipboard operation
modular copied to clipboard

Injeçao de Dependencias

Open julioffigueiredo opened this issue 1 year ago • 17 comments

Tenho no meu AppModule

image

Esses 2 ultimos binds selecionados serão importados na tela de login puxados qdo importo o LoginController que está declarado no LoginModule

image

LoginController() receba a injeção de ApiAuthService() que recebe a injeção de ApiAuthRepository();

O problema é que ele parece que não olha os binds declarados no app_module

Exception has occurred. BindNotFoundException (BindNotFoundException: UnregisteredInstance: ApiAuthService not registered. Trace: LoginController->ApiAuthService LoginController => ApiAuthService

Estou fazendo algo de errado ou isso é bug, como estou usando a versão 6 pela primeira vez estou com esse problema, na versão 5 sempre foi certinho assim.

Caso eu passe o bind do LoginController() do login_module pro app_module, ele acha e faz a criação das classes certinho!

julioffigueiredo avatar Feb 17 '24 21:02 julioffigueiredo

Estou com o mesmo problema. Parece que os modulos não estão sendo importados. No meu caso usei o exportedBinds e também não funcionou. Estou utilizando a versão 6.3.2 do modular

carlossulzer avatar Feb 18 '24 18:02 carlossulzer

Estou com o mesmo problema. Parece que os modulos não estão sendo importados. No meu caso usei o exportedBinds e também não funcionou. Estou utilizando a versão 6.3.2 do modular

Carlos depois de procurar muito, e eu não sei se o que fiz está certo, mas mesmo assim postei aqui minha dúvida, pq do jeito q era antes, funcionava como uma árvore e era possível acessar tudo que fosse na linha acima. Mas coloquei esse código no modulo de login e ele "importou?!", mas achei bem esquisito.

@override List<Module> get imports => [ AppModule(), ];

julioffigueiredo avatar Feb 18 '24 23:02 julioffigueiredo

Estou com o mesmo problema. Parece que os modulos não estão sendo importados. No meu caso usei o exportedBinds e também não funcionou. Estou utilizando a versão 6.3.2 do modular

Carlos depois de procurar muito, e eu não sei se o que fiz está certo, mas mesmo assim postei aqui minha dúvida, pq do jeito q era antes, funcionava como uma árvore e era possível acessar tudo que fosse na linha acima. Mas coloquei esse código no modulo de login e ele "importou?!", mas achei bem esquisito.

@override List<Module> get imports => [ AppModule(), ];

Julio está correto como você usou class XptoModule extends Module { @override void exportedBinds(i) { // Dependencies } } e onde quiseres usar as dependências class AbcModule extends Module { @override List<Module> get imports => [XptoModule()]; }

FelCarv01 avatar Feb 19 '24 23:02 FelCarv01

Continuando a fazer testes aqui, eu acho que a função i.addSingleton()/Lazy está com algum tipo de bug, está sendo recriada. Seguindo a criação com os passos acima e disponibilizando um instancia de AppInfoStore, na AppModule via i.addSingleton(), e depois a importando na LoginModule via import, a cada criação eu printo um UUID que gero no construtor.

Não sei pq ele a cria 2 vezes e printa o seguinte: [log] ID criando o AppInfoStore: ac7a783f-fe40-490b-975d-84008f4b7c97 [log] ID criando o AppInfoStore: b2c465f3-bd50-49b5-8a2a-c1984ed8b9ea

Caso eu faça o Module.get() em units separadas ele me retorna [log] Id da instância do AppInfoStore na LoginController : b2c465f3-bd50-49b5-8a2a-c1984ed8b9ea [log] Id da instância do AppInfoStore na LoginPage ac7a783f-fe40-490b-975d-84008f4b7c97 Não sei como e pq ele pega uma instância diferente em cada unit

julioffigueiredo avatar Feb 20 '24 00:02 julioffigueiredo

No meu caso o problema estava no uso do SharedPreference com o modular. O flutter_modular não aceita bind assíncrono. Segue o código que funcionou para mim.

void main() async { WidgetsFlutterBinding.ensureInitialized(); SharedPreferences sharedPreferences = await SharedPreferences.getInstance();

runApp(ModularApp( module: AppModule(sharedPreferences: sharedPreferences), child: const AppWidget(), )); }

class AppModule extends Module { final SharedPreferences sharedPreferences;

AppModule({ required this.sharedPreferences, });

@override List<Module> get imports => [ CoreModule(sharedPreferences: sharedPreferences), AuthModule(), ];

@override void routes(RouteManager r) { r.module('/auth', module: AuthModule()); } }


class CoreModule extends Module { final SharedPreferences sharedPreferences; CoreModule({ required this.sharedPreferences, });

@override void exportedBinds(Injector i) { i.addLazySingleton((i) => LoginController());

i.addInstance<LocalStorage>(
  SharedPreferencesStorageImpl(instanceSharedPreference: sharedPreferences),
);
i.addSingleton<AuthStore>(AuthStore.new);

} }

carlossulzer avatar Feb 20 '24 01:02 carlossulzer

I experienced this same issue after upgrading from 5.0.3 to 6.3.2 and migrating to the new auto_injector API. At first I thought the same thing, that the AppModule dependencies weren't visible to the LoginModule, but after further testing, I discovered if I change the syntax from using the constructor function reference:

i.addLazySingleton(LoginController.new);

to calling the constructor explicitly in a lambda:

i.addLazySingleton(() => LoginController(i()));

then it works.

This seems to only be a problem when using a constructor function reference that requires a dependency from a different module. Using a constructor function reference seems to work as long as all its parameters are dependencies in the same module.

jeffdgr8 avatar Mar 09 '24 01:03 jeffdgr8

Modular 6.3.3 same here. when using .new , BindNotFoundException happens. if changed on child module to "lambda" it works

I experienced this same issue after upgrading from 5.0.3 to 6.3.2 and migrating to the new auto_injector API. At first I thought the same thing, that the AppModule dependencies weren't visible to the LoginModule, but after further testing, I discovered if I change the syntax from using the constructor function reference:

i.addLazySingleton(LoginController.new);

to calling the constructor explicitly in a lambda:

i.addLazySingleton(() => LoginController(i()));

then it works.

This seems to only be a problem when using a constructor function reference that requires a dependency from a different module. Using a constructor function reference seems to work as long as all its parameters are dependencies in the same module.

ktnishide avatar Apr 16 '24 06:04 ktnishide

if I import all parent modules in the child module, it also works but doesn't seem to be aligned with what we see on Modular 5... However, other frameworks use this approach(importing all dependencies and not inheriting) such as Angular, Vue, etc... are you doing the same?

what are the guidelines? could you please document it since it is a breaking of paradigm from Modular 5 to 6.

importing parent modules:

class FeedModule extends Module {
  @override
  List<Module> get imports => [GlobalModule(), AppModule(), MenuModule()];

  @override
  void binds(i) {
    i.addSingleton<FeedStore>(FeedStore.new);
  }
...

using lambda syntax:

class FeedModule extends Module {
  @override
  void binds(i) {
    i.addSingleton<FeedStore>(() => FeedStore(i(), i(), i()));
  }
...

ktnishide avatar Apr 16 '24 06:04 ktnishide

I had a similar problem. was reporting to me that my injections were not being found. After many tests it worked for me to change from:

i.add<CrashLog>((i) => environment);

to:

i.add<CrashLog>(() => environment);

I thought it was strange, but it worked. flutter_modular version: 6.3.4

bielCostta avatar May 25 '24 05:05 bielCostta

Version 6.3.4 seems to have now made this bug worse. Now even the

i.addLazySingleton(() => LoginController(i()));

syntax fails to find dependencies declared in a separate module.

The bug is actually in the modular_core version 3.3.3 dependency.

jeffdgr8 avatar Jun 01 '24 23:06 jeffdgr8

Yep... same bug here. Anyone has find a workaround/fix for this? @jacobaraujo7 we need some help on this

intellitour avatar Jul 05 '24 13:07 intellitour

Please, we need a minimum code to be placed here so that we can check the error (main + module + widgets). I can say that I work with version 6.3.4 and everything works normally

eduardoflorence avatar Jul 05 '24 18:07 eduardoflorence

I am available to book a call and demo the problem. Can't handle the code, though.

intellitour avatar Jul 13 '24 17:07 intellitour

Same problem here

SamuelGadiel avatar Jul 30 '24 14:07 SamuelGadiel

Segue um projeto demonstrando o problema.

Crio uma instância de cliente e endereço no app_module, o cliente recebe de injeção o endereço.

Normalmente eles são lidos dentro da tela Home.

Na Store, caso eu queira a classe Cliente via injeção ele me retorna o erro abaixo: [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: UnregisteredInstance: Cliente not registered. HomeStore => Cliente

Se eu puxar dentro da Store a classe via Modular.get(), a dependência é encontrada!

Então acho que há algum problema ao encontrar a dependência qdo ela vem por DI.

https://github.com/julioffigueiredo/modular_import.git

julioffigueiredo avatar Aug 01 '24 13:08 julioffigueiredo

Olá @julioffigueiredo,

Olhei seu exemplo e esse não é o modo correto de trabalhar com injeção de dependências compartilhadas no Modular 6.x.x. Se você precisa compartilhar dependências, elas precisam ser declaradas num módulo à parte, por exemplo CoreModule, em exportedBinds:

class CoreModule extends Module {
  @override
  void exportedBinds(Injector i) {
    i.addSingleton<Endereco>(Endereco.new);
    i.addSingleton<Cliente>(Cliente.new);
  }
}

Depois você pode importar em qualquer módulo que precise dessas dependências, como o seu AppModule e HomeModule (em ambos terá que fazer a importação). Exemplo em HomeModule:

class HomeModule extends Module {
  @override
  List<Module> get imports => [CoreModule()];

  // Aqui é só um exemplo para o caso de você precisar do bind que tem em CoreModule
  // para ser usado em outro bind da HomeModule. Neste exemplo, suponha que 
  // OutraClasse peça em seu construtor a instância de Cliente, então bastará fazer o código 
  // abaixo que ele conseguirá achar a instância de Cliente, pois foi importada de CoreModule
  @override
  void binds(i) {
    i.addSingleton(OutraClasse.new);
  }
}

Nas versões anteriores (<= 5.x.x) você precisava somente importar em AppModule e ele passava para os módulos abaixo, mas isso causava problema colaterais, então foi decidido por mudar a abordagem na versão 6.x.x

edugemini avatar Aug 01 '24 14:08 edugemini

@edugemini,

Eu conheço como usar o "core module", estou usando assim. Mas pq dentro do mesmo nível, por exemplo, no HomeStore, eu consigo importar via Modular.get() mas não consigo importar via DI? Se não pode/deve importar, não deveria importar por nenhum dos 2 modos. Pra mim isso é um bug um tanto quanto estranho! Já que eu mantenho o acesso sem ser via DI.

julioffigueiredo avatar Aug 01 '24 18:08 julioffigueiredo