You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- A "composition root" is initialized part of the entry point of the application
16
+
- Create a script which needs to be injected
17
+
- Add `MonoInjector` to the `GameObject` hosting the script
18
+
-`MonoInjector` runs at `Awake`, and it's execution order (`int.MinValue` - first) is run before your own component's `Awake`. Every injected script will have it's own `IServiceScope` derived from the root scope. This scope can be retrieved through the `IScopeStore`, and the owner of the scope is the script being injected
19
+
- When the `GameObject` is destroyed, `MonoDisposer` will run during the `OnDestroy` method, with an execution order of `int.MaxValue` - last
33
20
34
-
// Resolve scripts already in the scene with FindObjectOfType()
// Get a prefab that contains a script which needs injection.
77
-
GameObjectprefab= ;
78
-
// IGameObjectInjector and ISceneInjector are services added by default to Services
79
-
IGameObjectFactorygameObjectFactory= ;
80
-
ISceneInjectorsceneInjector= ;
97
+
If you decorate your script with `[RequireComponent(typeof(MonoInjector))]` then, when adding the script to a `GameObject` the editor will add the `MonoInjector` and the `MonoDisposer` script to your `GameObject`. If for some reason this does not happen (for example, when changing an already living script into one needing injection), either add the `MonoInjector` component manually, or use the editor tools included to add the missing components to scenes or prefabs (will search all instances) through the editor menu `Tools / Injecter / ...`
81
98
82
-
// Either:
99
+
## Manual injection
83
100
84
-
// Instantiate the usual way
85
-
varinstance=GameObject.Instantiate(prefab);
86
-
// Inject into freshly created GameObject
87
-
sceneInjector.InjectIntoGameObject(instance);
101
+
When dynamically adding an injectable script to a `GameObject` you need to handle the injection and disposal manually.
88
102
89
-
// Or:
103
+
```csharp
90
104
91
-
// Use IGameObjectFactory which wraps GameObject.Instantiate(...) methods
92
-
varinstance=gameObjectFactory.Instantiate(prefab); // Prefab is created and injected
> When doing this manually, the later injected script's `Awake` method might run before the injection happens
118
+
119
+
## Testing
120
+
121
+
You can load tests and prefabs with controlled dependencies when running tests inside Unity. To do this create the following class in your test assembly:
You don't have to call InjectIntoGameObject on prefab children. When InjectIntoGameObject is called all the scripts on the game object and it's children which have the InjectAttribute gets injected.
95
137
96
-
## Scopes, Disposables
138
+
This will stop your `AppInstaller` from running when you execute tests. This will happen if either you have the test runner window open, or you are running Unity headless with the `-runTests` parameter (typically during CI).
97
139
98
-
- An IServiceScope is created for every script found in a GameObject.
99
-
- Thus each MonoBehavior injected has it's own scope (Scoped lifetime services start from here).
100
-
- A DestroyDetector script is added to every GameObject that receives injection. When the game object is destroyed, the DestroyDetector disposes of all the scopes that got created for that specific game object.
101
-
- Thus if you create a prefab, destroy one of it's children then only the scopes associated with that child are disposed.
102
-
- DestroyDetector is internal, and is hidden in the Inspector.
103
-
- Destroying the game object holding the SceneInjector disposes of the IServiceProvider if it is disposable
104
-
- When using the CompositionRoot behavior option the InjectedMonoBehavior handles disposing of the scope when destroyed and no DestroyDetector is created.
140
+
> [!WARNING]
141
+
> If you do this, then you must close the test runner window when entering play mode, otherwise the `AppInstaller` will not run
105
142
106
-
## Options
143
+
In your tests set up the composition root manually
107
144
108
-
You can customize some behavior of the SceneInjector by providing an action to configure the options when calling AddSceneInjector
> You can also do the same in the test's `Setup` or `Teardown` stage
111
162
112
-
| Name | Description | Default value|
113
-
|---|---|---|
114
-
| Behavior | CompositionRoot: Use the static service provider with inherited MonoBehaviors. Factory: use the SceneInjector and IGameObjectFactory | Factory |
115
-
| DontDestroyOnLoad | Calls GameObject.DontDestroyOnLoad(SceneInjector) during initialization. This prevents the game object from being destroyed | True |
163
+
## Migrating from `8.0.1` to `9.0.0`
116
164
117
-
## Notes
118
-
- To see sample usage check out tests and test scenes
165
+
1. Set up a composition root as described above.
166
+
2. Remove inheriting from the old `MonoBehaviourInjected` and similar classes
167
+
3. Optional - Decorate your injected scripts with `[RequireComponent(typeof(MonoInjector))]`
168
+
4. In the editor press the `Tools / Injecter / Ensure injection scripts on everyting` button
169
+
5. If a `GameObject` is missing the `MonoInjector` or `MonoDisposer` scripts, add them
0 commit comments